3
votes

The L4 series erases flash using pages (or banks, if you do a full erase). But I'm having some problem writing after doing page erases, and I'm not sure why.

Just to outline the objective I am storing 6 values starting at 0x08080000 (Page 256) then I am storing more values from 0x08080800) (page 257) to 0x08085800 (page 267)

There is a single function that I use to erase/write the values at page 256:

void write_bias_flash(int16_t biases[]) {
    uint16_t *flash_biases = (uint16_t*) (ADDR_FLASH_PAGE_256);
    static FLASH_EraseInitTypeDef EraseInitStruct;
    Address = ADDR_FLASH_PAGE_256;

    /* Fill EraseInit structure*/
    EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
    EraseInitStruct.Page = 0;
    EraseInitStruct.Banks = FLASH_BANK_2;
    EraseInitStruct.NbPages = 1;

    HAL_FLASH_Unlock();
    if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK) {
        serprintf("Error erasing biases at address: 0x%x", Address);
    }
    for (int8_t bias = 0; bias < 6; bias++) {
         if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD,
                Address + bias * sizeof(uint64_t), (uint64_t) biases[bias])
                != HAL_OK)
            serprintf("Error writing biases to flash.");
     }
    HAL_FLASH_Lock();
    serprintf("Biases stored in flash.");
}

This work great. No issues.

I have two functions I use to erase/write the data starting at 0x08080800) (page 257):

void Erase_TM_Flash() {
    uint8_t *flash = (uint8_t*) (FLASH_USER_START_ADDR);
    uint8_t *b = (uint16_t*) (ADDR_FLASH_PAGE_256);
    static FLASH_EraseInitTypeDef EraseInitStruct;
    Address = FLASH_USER_START_ADDR;

    /* Fill EraseInit structure*/
    EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
    EraseInitStruct.Page = 1;
    EraseInitStruct.NbPages = 255;
    EraseInitStruct.Banks = FLASH_BANK_2;

    HAL_FLASH_Unlock();
    if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK) {
        serprintf("Error erasing biases at address: 0x%x", Address);
    }

    HAL_FLASH_Lock();

    for (uint16_t i = 0; i< (FLASH_ROW_SIZE * sizeof(uint64_t))*255; i++)
    {
        if ((uint16_t) *(flash+i) != 255) {
            serprintf("0x%x is not erased (%i)", flash+i, (uint16_t) *(flash+i));
        }

    }

}
void Save_to_Flash(uint32_t *data) {

    uint32_t src_addr = (uint32_t) data;
    Erase_TM_Flash();
    serprintf("Saving to flash...");
    HAL_StatusTypeDef HAL_STATUS;

    HAL_FLASH_Unlock();
    Address = FLASH_USER_START_ADDR;
    while (Address < (FLASH_USER_END_ADDR - (FLASH_ROW_SIZE * sizeof(uint64_t)))) {
        HAL_STATUS = HAL_FLASH_Program(FLASH_TYPEPROGRAM_FAST, Address, (uint64_t) src_addr);
        if (HAL_STATUS == HAL_OK) {
          Address = Addres+ (FLASH_ROW_SIZE * sizeof(uint64_t));
            src_addr = src_addr + (FLASH_ROW_SIZE * sizeof(uint64_t));
            } else {
                serprintf("Error writing flash at address 0x%x. (%i)", Address, HAL_STATUS);
                Address = Address + (FLASH_ROW_SIZE * sizeof(uint64_t));
                src_addr = src_addr + (FLASH_ROW_SIZE * sizeof(uint64_t));
            }
    }
    HAL_FLASH_Lock();
    serprintf("Done");
    }

The erase works fine. I verify the values in the debugger (and in the code I check for non-erased pages). But when the saving occurs:

Error writing flash at address 0x8080800. (1)
Error writing flash at address 0x8080900. (1)
Error writing flash at address 0x8080a00. (1)
Error writing flash at address 0x8080b00. (1)

And so on through all the remaining pages.

However, if I erase the entire flash:

void Erase_Flash() {
    serprintf("Erasing flash...");
    HAL_FLASH_Unlock();
    /* Clear OPTVERR bit set on virgin samples */
    __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR);

    /* Fill EraseInit structure*/
    EraseInitStruct.TypeErase = FLASH_TYPEERASE_MASSERASE;
    EraseInitStruct.Banks = FLASH_BANK_2;

    if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK) {
        serprintf("Error erasing flash.");
    }
    HAL_FLASH_Lock();
    serprintf("Done.");
}

Then the writing works like a charm. HAL_STATUS = 1, which according to the code I found is HAL_ERROR = 0x01U, which isn't entirely helpful.

I am not sure what the difference in, but I am hoping another set of eye on my erasure might reveal the issue.

Thanks!

1

1 Answers

1
votes

This issue seems to be related to flash fast programming, which isn't available on all STM32 models.

According to the Reference Manual (RM0351), the flash must be mass erased before using fast programming. Otherwise a Programming Sequence Error occurs, and the PGSERR bit in the FLASH_SR register will be set. See 3.3.7 Flash main memory programming sequences in sections Fast Programming / Programming errors and 3.7.5 Flash status register (FLASH_SR) under Bit 7 PGSERR.

RM0351 Rev 9, 3.3.7 Flash main memory programming sequences, on page 106:

Fast programming
(...)
1. Perform a mass erase of the bank to program. If not, PGSERR is set.
2. (...)

RM0351 Rev 9, 3.3.7 Flash main memory programming sequences, on page 107:

Programming errors
(...)
PGSERR: Programming Sequence Error
PGSERR is set if one of the following conditions occurs:
– (...)
– In the fast programming sequence: the Mass erase is not performed before setting 
  FSTPG bit.
– (...)

The observed behavior is therefore as expected. - So you could replace your Erase_TM_Flash() function and use Erase_Flash() to mass erase the entire flash bank first. Or, avoid using flash fast programming altogether and use FLASH_Program_DoubleWord() or FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, ...) instead.

Related source files: stm32l4xx_hal_flash.h, stm32l4xx_hal_flash.c

Related post: STM32 - writing and reading flash