I'm trying to reprogram the NVM (flash bank 2) while running code from flash bank 1 in the STM32L071CB microcontroller.
As AN4808 and AN4767 states, "the memory interface is capable of reading both banks in parallel, or reading one bank while writing to the other...", but I'm experiencing some problems:
- Debugging shows that FWWERR bit goes high in the flash status register during flash bank 2 half-page write operation. It means that writing flash bank 2 has been stopped because of code fetching.
- Erasing bank 2 by code in bank 1 works properly.
- Writing by words bank 2 by code in bank 1 seems to work properly (but I'm having doubts if it's only a coincidence).
- Half-page writing ends with FWWERR bit set in FLASH_SR and zeros in the memory I'm trying to write.
I know I'm missing something, but I can't find out what it is. Maybe someone had similar problem? I'm starting to think that there's something wrong with the microcontroller (errata sheet points out some problems with dual-bank switching mechanism, but it shouldn't be a problem in my case, because I'm not switching banks right now).
My function works properly when executed from RAM memory, but I'd rather want it to run from flash bank 1.
The function (1) below is responsible of writing half-pages. Code (2) shows the way that I'm calling (2).
(1)
void nvm_prog_write_halfpages(uint32_t* addr, uint32_t* data, uint32_t length){
// There can't be any previous alignment errors in the flash SR
if ((FLASH->SR & FLASH_SR_PGAERR_Msk) == FLASH_SR_PGAERR){
FLASH->SR = FLASH_SR_PGAERR; // clear any previous alignment errors
}
// Check if any operation was stopped previously due to code fetching
if ((FLASH->SR & FLASH_SR_FWWERR_Msk) == FLASH_SR_FWWERR){
FLASH->SR = FLASH_SR_FWWERR; // clear any previous fetch related errors
}
nvm_prog_unlock();
FLASH->PECR |= FLASH_PECR_PROG | FLASH_PECR_FPRG;
uint32_t cnt = 0;
while (length > 0){
*addr = *data; // Destination address will be increased by the hardware automatically
data++;
cnt++;
// When a half-page has been written
if (cnt == 16){
while ((FLASH->SR & FLASH_SR_BSY_Msk) == FLASH_SR_BSY)
;
cnt = 0;
addr += 16; // Write the next half-page
length--;
}
}
FLASH->PECR &= ~(FLASH_PECR_PROG | FLASH_PECR_FPRG);
nvm_prog_lock();
}
(2)
nvm_prog_erase_page((uint32_t *) 0x08010000); // Erase flash bank 2; it starts at 0x08010000
uint32_t dummydata[32], i;
for (i=0; i<32; i++){
dummydata[i] = i;
}
nvm_prog_write_halfpages((uint32_t *) 0x08010000, &dummydata[0], 2); // Write 2 half-pages at the beginning of flash bank 2