cmaglie / FlashStorage

A convenient way to store data into Flash memory on the ATSAMD21 and ATSAMD51 processor family
203 stars 69 forks source link

erase() fails if FlashClass::flash_size > ROW_SIZE #54

Open joepasquariello opened 1 year ago

joepasquariello commented 1 year ago

Hi Cristian. Very useful library. I was doing some testing with an instance of FlashClass larger than 8192 bytes (ROW_SIZE), and I found an issue. My store was 65536 bytes, and I found that if I called store.erase(), only the first row (8192 bytes) was erased. The issue is the use of INTFLAG.bit.DONE, which does become true when a command completes, but needs to be cleared before doing another command. What you have in erase(ptr) now is:

NVMCTRL->ADDR.reg = ((uint32_t)flash_ptr); NVMCTRL->CTRLB.reg = NVMCTRL_CTRLB_CMDEX_KEY | NVMCTRL_CTRLB_CMD_EB; while (NVMCTRL->INTFLAG.bit.DONE == 0) { }

The DONE flag is never cleared, so when erase() is called for a store larger than one row, and the code above gets called more than once with no delay, the DONE flag is already set and the erase does not occur. My fix was to use the READY flag rather than the DONE flag, the same as you do for SAMD21. The READY flag is cleared automatically when you start a command, so it never has to be "manually" cleared, as is required for DONE. The code below fixes the problem, and it's nice that it is the same logic as SAMD21.

NVMCTRL->ADDR.reg = ((uint32_t)flash_ptr); NVMCTRL->CTRLB.reg = NVMCTRL_CTRLB_CMDEX_KEY | NVMCTRL_CTRLB_CMD_EB; while (NVMCTRL->STATUS.bit.READY == 0) { }

write() must also be modified to use READY instead of DONE in the logic for both PBC (page buffer clear) and WP (write page).