//poll for busy status, return false if write is complete, true if timeout
static bool spi_eeprom_poll_busy(uint8_t block_select_bits){
uint8_t reg;
for(uint32_t i=0; i<0xfffff; i++) {
hwspi_write_read_cs((uint8_t[]){SPI_EEPROM_RDSR_CMD}, 1, ®, 1); // send the read status command
if((reg & 0x01) == 0) { // check if WIP bit is clear
return false; // write is complete
}
}
//printf("Error: EEPROM write timeout\r\n");
return true;
}
static bool spi_eeprom_read_16(uint8_t block_select_bits, uint8_t address_bytes, uint8_t *address, char *buf) {
//TODO: get the block select bits from the device
hwspi_write_read_cs((uint8_t[]){SPI_EEPROM_READ_CMD|block_select_bits, address[0], address[1], address[2]}, 1+address_bytes, buf, 16); // read 16 bytes from the EEPROM
return false;
}
static bool spi_eeprom_read_256(uint8_t block_select_bits, uint8_t address_bytes, uint8_t *address, char *buf){
//TODO: get block select bits from the device
hwspi_write_read_cs((uint8_t[]){SPI_EEPROM_READ_CMD|block_select_bits, address[0], address[1], address[2]}, 1+address_bytes, buf, 256); // read
return false;
}
static bool spi_eeprom_write_page(uint8_t block_select_bits, uint8_t address_bytes, uint8_t *address, uint32_t page_size, char *buf){
//TODO: get block select bits from the device
hwspi_write_read_cs((uint8_t[]){SPI_EEPROM_WREN_CMD}, 1, NULL, 0); // enable write
//TODO: this will need to be copied into a buffer with command, address, page...
hwspi_write_read_cs((uint8_t[]){SPI_EEPROM_WRITE_CMD|block_select_bits, address[0], address[1], address[2]}, 1 + address_bytes + page_size, NULL, 0); // write 0x00 to the status register
}
struct eeprom_hal_t {
bool (*read_16)(uint8_t block_select_bits, uint8_t address_bytes, uint8_t *address, char *buf);
bool (*read_256)(uint8_t block_select_bits, uint8_t address_bytes, uint8_t *address, char *buf);
bool (*write_page)(uint8_t block_select_bits, uint8_t address_bytes, uint8_t *address, uint32_t page_size, char *buf);
bool (*write_protection_blocks)(uint8_t block_select_bits, uint8_t address_bytes, uint8_t *address, uint8_t reg);
bool (*poll_busy)(uint8_t block_select_bits);
};
static struct eeprom_hal_t eeprom_hal[] = {
{.read_16 = spi_eeprom_read_16,
.read_256 = spi_eeprom_read_256,
.write_page = spi_eeprom_write_page,
.write_protection_blocks = NULL, // not implemented
.poll_busy = spi_eeprom_poll_busy},
{.read_16 = NULL, // not implemented
.read_256 = NULL, // not implemented
.write_page = NULL, // not implemented
.write_protection_blocks = NULL, // not implemented
.poll_busy = NULL} // not implemented
};
After messing with the SPI EEPROM stuff, and equipped with recent I2C EEPROM experience, this is the direction I’m headed.
- Several basic function to read 16 and 256 row/page aligned bytes. We need to read max 256 bytes because some EEPROMs have block select bits in the opcode (SPI) or I2C address, so they don’t naturally roll over to the next page without explicitly setting those block bits.
- A page write function, can’t write more than a page anyways.
- Poll for busy function
- Function to manipulate the lock bits (if present)
SPI and I2C functions are then referenced in a hardware abstraction layer struct, to be reused by the same base code for both types of devices.