I am developing a custom bootloader with firmware update functionality, and as such I need to make direct writes to flash. During testing I have discovered that some small portions (~256 bytes or less) of flash are not being updated as expected and are instead retaining their old values. The failure is intermittent and the addresses that are missed changes on each attempt- I have frequently observed multiple failed portions on the first update attempt, but a second write corrects them and results in a valid firmware image.
The update process must make multiple writes to update a single flash sector. The sector contents before and after the target address are copied to RAM, the sector is erased, and the buffered copy is written back out alongside the new data. It is possible there is a bug with this copying process, but it is well tested elsewhere and the random nature of the failure suggests a problem with the low level flash write and erase itself.
Below are my flash write and erase functions. I have disabled the flash cache, line buffer, and interrupts as called out in the VIMS section of the manual. Is there any other stipulations or safeguards missing for safely manipulating flash memory?
static uint32_t _Flash_Updater_eraseSegment(uintptr_t segmentAddr)
{
uint32_t err;
unsigned int key = _disable_interrupts();
err = FlashSectorErase(segmentAddr);
_restore_interrupts(key);
return err;
}
static uint32_t _Flash_Updater_directWrite(uintptr_t dstAddr, const void *pSrc,
uint16_t size)
{
uint32_t err;
uint8_t *pByte = (uint8_t *) pSrc;
// Disable cache and line buffer (see VIMS section 8.3 of TRM).
unsigned int key = _disable_interrupts();
VIMSModeSafeSet(VIMS_BASE, VIMS_MODE_OFF, 1);
VIMSLineBufDisable(VIMS_BASE);
err = FlashProgram(pByte, dstAddr, size);
// Re-enable cache and line buffer.
VIMSModeSafeSet(VIMS_BASE, VIMS_MODE_ENABLED, 1);
VIMSLineBufEnable(VIMS_BASE);
_restore_interrupts(key);
return err;
}