Search code examples
embeddedstm32

(STM32) Erasing flash and writing to flash gives HAL_FLASH_ERROR_PGP error (using HAL)


Trying to write to flash to store some configuration. I am using an STM32F446ze where I want to use the last 16kb sector as storage.

I specified VOLTAGE_RANGE_3 when I erased my sector. VOLTAGE_RANGE_3 is mapped to:

#define FLASH_VOLTAGE_RANGE_3        0x00000002U  /*!< Device operating range: 2.7V to 3.6V                */

I am getting an error when writing to flash when I use FLASH_TYPEPROGRAM_WORD. The error is HAL_FLASH_ERROR_PGP. Reading the reference manual I read that this has to do with using wrong parallelism/voltage levels.

From the reference manual I can read

enter image description here

Furthermore, in the reference manual I can read:

Programming errors

It is not allowed to program data to the Flash memory that would cross the 128-bit row boundary. In such a case, the write operation is not performed and a program alignment error flag (PGAERR) is set in the FLASH_SR register. The write access type (byte, half-word, word or double word) must correspond to the type of parallelism chosen (x8, x16, x32 or x64). If not, the write operation is not performed and a program parallelism error flag (PGPERR) is set in the FLASH_SR register

So I thought:

  • I erased the sector in voltage range 3
  • That gives me 2.7 to 3.6v specification
  • That gives me x32 parallelism size
  • I should be able to write WORDs to flash.

But, this line give me an error (after unlocking the flash)

    uint32_t sizeOfStorageType = ....; // Some uint I want to write to flash as test

    HAL_StatusTypeDef flashStatus = HAL_FLASH_Program(TYPEPROGRAM_WORD, address++, (uint64_t) sizeOfStorageType);
    auto err=  HAL_FLASH_GetError(); // err == 4 == HAL_FLASH_ERROR_PGP: FLASH Programming Parallelism error flag  

    while (flashStatus != HAL_OK)
    {
    }

But when I start to write bytes instead, it goes fine.

    uint8_t *arr = (uint8_t*) &sizeOfStorageType;
    HAL_StatusTypeDef flashStatus;
    for (uint8_t i=0; i<4; i++)
    {
        flashStatus = HAL_FLASH_Program(TYPEPROGRAM_BYTE, address++, (uint64_t) *(arr+i));
        while (flashStatus != HAL_OK)
        {
        }
    }

My questions:

  • Am I understanding it correctly that after erasing a sector, I can only write one TYPEPROGRAM? Thus, after erasing I can only write bytes, OR, half-words, OR, words, OR double words?
  • What am I missing / doing wrong in above context. Why can I only write bytes, while I erased with VOLTAGE_RANGE_3?

Solution

  • This looks like an data alignment error, but not the one related with 128-bit flash memory rows which is mentioned in the reference manual. That one is probably related with double word writes only, and is irrelevant in your case.

    If you want to program 4 bytes at a time, your address needs to be word aligned, meaning that it needs to be divisible by 4. Also, address is not a uint32_t* (pointer), it's a raw uint32_t so address++ increments it by 1, not 4. As far as I know, Cortex M4 core converts unaligned accesses on the bus into multiple smaller size aligned accesses automatically, but this violates the flash parallelism rule.

    BTW, it's perfectly valid to perform a mixture of byte, half-word and word writes as long as they are properly aligned. Also, unlike the flash hardware of F0, F1 and F3 series, you can try to overwrite a previously written location without causing an error. 0->1 bit changes are just ignored.