The T4 and 4.1's EEPROM emulation using Flash ROM has to sometimes erase a sector. This takes 0.045 to 0.400 seconds to do and the code is completely blocking- interrupts are disabled during this time. (eeprom.c in \hardware\teensy\avr\cores\teensy4, code below.)
I don't see what would influence the Winbond serial flash chip towards the 0.4 second end of that spec, but I have to assume the worst unless I hear otherwise. (P.90 on the datasheet referenced in this thread: https://forum.pjrc.com/index.php?threads/teensy-4-1-eeprom-endurance.72280/).
Moreover, some scenarios where you write more than one byte of data will result in multiples of these, though unlikely, it appears possible for the CPU to disappear for most of 3-25 seconds (all 63 sectors touched). (Possibly triggering a watchdog timer restart BTW, as I am using it?)
In my application, blocking for more than one ms is fatal to the purpose of the product, so writing to this flash is usually not permissible. Yet I need NV storage (not on the SD card - that's being used and might not always be there). And I don't want to add more parts.
So my question is, for an application where there is only one user of the flash, and that can be written to wait while everything else continues, is there a reason I shouldn't write a modified version of eeprom.c to not block so long, or not at all? Such here: eepromemu_flash_erase_sector()
Thanks if you have a chance to comment on this,
-Phil
// erase a 4K sector - From eeprom.c
void eepromemu_flash_erase_sector(void *addr)
{
__disable_irq();
FLEXSPI_LUTKEY = FLEXSPI_LUTKEY_VALUE;
FLEXSPI_LUTCR = FLEXSPI_LUTCR_UNLOCK;
FLEXSPI_LUT60 = LUT0(CMD_SDR, PINS1, 0x06); // 06 = write enable
FLEXSPI_LUT61 = 0;
FLEXSPI_LUT62 = 0;
FLEXSPI_LUT63 = 0;
FLEXSPI_IPCR0 = 0;
FLEXSPI_IPCR1 = FLEXSPI_IPCR1_ISEQID(15);
FLEXSPI_IPCMD = FLEXSPI_IPCMD_TRG;
arm_dcache_delete((void *)((uint32_t)addr & 0xFFFFF000), 4096); // purge data from cache
while (!(FLEXSPI_INTR & FLEXSPI_INTR_IPCMDDONE)) ; // wait
FLEXSPI_INTR = FLEXSPI_INTR_IPCMDDONE;
FLEXSPI_LUT60 = LUT0(CMD_SDR, PINS1, 0x20) | LUT1(ADDR_SDR, PINS1, 24); // 20 = sector erase
FLEXSPI_IPCR0 = (uint32_t)addr & 0x00FFF000;
FLEXSPI_IPCR1 = FLEXSPI_IPCR1_ISEQID(15);
FLEXSPI_IPCMD = FLEXSPI_IPCMD_TRG;
while (!(FLEXSPI_INTR & FLEXSPI_INTR_IPCMDDONE)) ; // wait
FLEXSPI_INTR = FLEXSPI_INTR_IPCMDDONE;
flash_wait();
}
static void flash_wait()
{
FLEXSPI_LUT60 = LUT0(CMD_SDR, PINS1, 0x05) | LUT1(READ_SDR, PINS1, 1); // 05 = read status
FLEXSPI_LUT61 = 0;
uint8_t status;
do {
FLEXSPI_IPRXFCR = FLEXSPI_IPRXFCR_CLRIPRXF; // clear rx fifo
FLEXSPI_IPCR0 = 0;
FLEXSPI_IPCR1 = FLEXSPI_IPCR1_ISEQID(15) | FLEXSPI_IPCR1_IDATSZ(1);
FLEXSPI_IPCMD = FLEXSPI_IPCMD_TRG;
while (!(FLEXSPI_INTR & FLEXSPI_INTR_IPCMDDONE)) {;}
FLEXSPI_INTR = FLEXSPI_INTR_IPCMDDONE;
asm("":::"memory");
status = *(uint8_t *)&FLEXSPI_RFDR0;
} while (status & 1);
FLEXSPI_MCR0 |= FLEXSPI_MCR0_SWRESET; // purge stale data from FlexSPI's AHB FIFO
while (FLEXSPI_MCR0 & FLEXSPI_MCR0_SWRESET) ; // wait
__enable_irq();
}
I don't see what would influence the Winbond serial flash chip towards the 0.4 second end of that spec, but I have to assume the worst unless I hear otherwise. (P.90 on the datasheet referenced in this thread: https://forum.pjrc.com/index.php?threads/teensy-4-1-eeprom-endurance.72280/).
Moreover, some scenarios where you write more than one byte of data will result in multiples of these, though unlikely, it appears possible for the CPU to disappear for most of 3-25 seconds (all 63 sectors touched). (Possibly triggering a watchdog timer restart BTW, as I am using it?)
In my application, blocking for more than one ms is fatal to the purpose of the product, so writing to this flash is usually not permissible. Yet I need NV storage (not on the SD card - that's being used and might not always be there). And I don't want to add more parts.
So my question is, for an application where there is only one user of the flash, and that can be written to wait while everything else continues, is there a reason I shouldn't write a modified version of eeprom.c to not block so long, or not at all? Such here: eepromemu_flash_erase_sector()
Thanks if you have a chance to comment on this,
-Phil
// erase a 4K sector - From eeprom.c
void eepromemu_flash_erase_sector(void *addr)
{
__disable_irq();
FLEXSPI_LUTKEY = FLEXSPI_LUTKEY_VALUE;
FLEXSPI_LUTCR = FLEXSPI_LUTCR_UNLOCK;
FLEXSPI_LUT60 = LUT0(CMD_SDR, PINS1, 0x06); // 06 = write enable
FLEXSPI_LUT61 = 0;
FLEXSPI_LUT62 = 0;
FLEXSPI_LUT63 = 0;
FLEXSPI_IPCR0 = 0;
FLEXSPI_IPCR1 = FLEXSPI_IPCR1_ISEQID(15);
FLEXSPI_IPCMD = FLEXSPI_IPCMD_TRG;
arm_dcache_delete((void *)((uint32_t)addr & 0xFFFFF000), 4096); // purge data from cache
while (!(FLEXSPI_INTR & FLEXSPI_INTR_IPCMDDONE)) ; // wait
FLEXSPI_INTR = FLEXSPI_INTR_IPCMDDONE;
FLEXSPI_LUT60 = LUT0(CMD_SDR, PINS1, 0x20) | LUT1(ADDR_SDR, PINS1, 24); // 20 = sector erase
FLEXSPI_IPCR0 = (uint32_t)addr & 0x00FFF000;
FLEXSPI_IPCR1 = FLEXSPI_IPCR1_ISEQID(15);
FLEXSPI_IPCMD = FLEXSPI_IPCMD_TRG;
while (!(FLEXSPI_INTR & FLEXSPI_INTR_IPCMDDONE)) ; // wait
FLEXSPI_INTR = FLEXSPI_INTR_IPCMDDONE;
flash_wait();
}
static void flash_wait()
{
FLEXSPI_LUT60 = LUT0(CMD_SDR, PINS1, 0x05) | LUT1(READ_SDR, PINS1, 1); // 05 = read status
FLEXSPI_LUT61 = 0;
uint8_t status;
do {
FLEXSPI_IPRXFCR = FLEXSPI_IPRXFCR_CLRIPRXF; // clear rx fifo
FLEXSPI_IPCR0 = 0;
FLEXSPI_IPCR1 = FLEXSPI_IPCR1_ISEQID(15) | FLEXSPI_IPCR1_IDATSZ(1);
FLEXSPI_IPCMD = FLEXSPI_IPCMD_TRG;
while (!(FLEXSPI_INTR & FLEXSPI_INTR_IPCMDDONE)) {;}
FLEXSPI_INTR = FLEXSPI_INTR_IPCMDDONE;
asm("":::"memory");
status = *(uint8_t *)&FLEXSPI_RFDR0;
} while (status & 1);
FLEXSPI_MCR0 |= FLEXSPI_MCR0_SWRESET; // purge stale data from FlexSPI's AHB FIFO
while (FLEXSPI_MCR0 & FLEXSPI_MCR0_SWRESET) ; // wait
__enable_irq();
}