1
\$\begingroup\$

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:

  1. 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.
  2. Erasing bank 2 by code in bank 1 works properly.
  3. 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).
  4. 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
\$\endgroup\$
1
  • \$\begingroup\$ Make sure the debugger does not read the flash contents while programming. Don't step the programming sequence, use breakpoints. \$\endgroup\$
    – Jeroen3
    Commented Aug 30, 2017 at 13:34

1 Answer 1

1
\$\begingroup\$

Reading-While-Write has some limitation in case of Multiple programming operation. See RM0377 § 3.3.4 Writing/erasing the NVM - Program half-page in Flash program memory page 82:

When a half-page operation starts, the memory interface waits for 16 addresses/data, aborting (with a hard fault) all read accesses that are not a fetch (refer to Fetch and prefetch). A fetch stops the half-page operation. The memory content remains unchanged, the FWWERR error is set in the FLASH_SR register.

This means that no fetch operation are allowed in the flash while feeding the memory interface with the 16 words (whatever the code is running in bank 1 and the half page programming is performed in bank 2) . Once the 16 words have been sent to the memory interface, you can resume execution from flash, i.e. during the physical writing of the data inside the flash bank (assuming your code is running in the other bank).

In a nutshell, you need to execute from SRAM the feeding of the memory interface with the 16 words and make sure the interrupts will not cause fetch in flash memory (either mask all interrupts or relocate interrupt handlers and interrupts vector in SRAM).

Note: there is no such limitation in case of Single programming operation.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.