2

I am using HAL_FLASH_Program() to program an uuid into a specific address. I can verify that it writes successfully by reading from the same address. However, if I power cycle the MCU, the memory at that address returns to the original value. If I write to it directly through ST-Link then it stays permanently.

Does anyone know why is that? Do I need to erase the memory location before write to it using HAL_FLASH_Program()? I am using STM32F745.

My code is really simple:

#define UUID_ADDR      (0x080FFFFB)
uint16_t uuid 0x1234
HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, UUID_ADDR, uuid);

Thank you

HelpingHand
  • 1,123
  • 9
  • 23
cuckoo
  • 79
  • 9

2 Answers2

1

Flash memory requires that the sector you want to write to must be in the erase state before you can write to it.

For that, you need some extra steps before you can make your write persistent.

Below is an example in how to do it, but make sure that the addresses match your purpose, here is just a generic code:

HAL_StatusTypeDef write_halfword_to_flash(uint32_t sector, uint32_t addr, void *data) {
    HAL_StatusTypeDef status = HAL_FLASH_Unlock();
    uint32_t error = 0;

    // make sure that this structure matches the datasheet of your chip
    FLASH_EraseInitTypedef FLASH_EraseInitStruct = {
        .TypeErase = FLASH_TYPEERASE_SECTORS,
        .Sector = sector,
        .NbSectors = 1,
        .VoltageRange = FLASH_VOLTAGE_RANGE_3
    };

    // clear all flags before you write it to flash
    __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR |
                FLASH_FLAG_WRPERR | FLASH_FLAGH_PGAERR | FLAG_PGSERR);

    if (status != HAL_OK)
        return status;

    // perform the erase first
    HAL_FLASHEx_Erase(&FLASH_EraseInitStruct, &error);

    if (error)
        return -1;

    // now that the sector is erased, we can write to it
    status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, addr, data);
    if (status != HAL_OK)
        return status;

    HAL_FLASH_Unlock();

    return status;
}

campescassiano
  • 726
  • 3
  • 16
-1

I made a test with Stm32F417. I looked to the Reference Manual for STM32F6xx. It seems similar.

Erase Flash Memory

void eraseFlash()
{
    //  Disable prefetch memory
    __HAL_FLASH_PREFETCH_BUFFER_DISABLE();

    //  Flash 5 wait state.
    //  Check the Number of wait states according to CPU clock
    //  In my case, HCLK = 168MHz, Need FLASH_LATENCY_5
    if (FLASH_LATENCY_5 == __HAL_FLASH_GET_LATENCY())
        __HAL_FLASH_SET_LATENCY( FLASH_LATENCY_5 );

    //  Lock the memory to make sure to write the FLASH_OPT_KEYn in OPTKEYR
    HAL_FLASH_Lock();

    //  Clean all flags except FLASH_FLAG_BSY
    __HAL_FLASH_CLEAR_FLAG( FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGSERR );

    //  Write the FLASH_OPT_KEYn in OPTKEYR to access the memory
  HAL_FLASH_Unlock();

  //    Timeout of 500ms for the operation. Check if the FLASH_FLAG_BSY.
  FLASH_WaitForLastOperation( 500 );

  //    Write the Sector.
  //    STM32F40/41 have 11 sectors. 5 sectors of 16K, 1 x 64K, 7 x 128K
  //    Each STM32 has a different memory organisation
  //    The voltage range will selection the type to erase the memory
  //    FLASH_VOLTAGE_RANGE_3 erases by WORD
  FLASH_Erase_Sector(  FLASH_SECTOR_1,  FLASH_VOLTAGE_RANGE_3);

  FLASH_WaitForLastOperation( 500 );

    HAL_FLASH_Lock();
    //  The memory is erased from that point
}

Write Data to flash

uint32_t writeFlashData()
{
    __HAL_FLASH_PREFETCH_BUFFER_ENABLE();

    // Flash 5 wait state
    if (FLASH_LATENCY_5 == __HAL_FLASH_GET_LATENCY())
        __HAL_FLASH_SET_LATENCY( FLASH_LATENCY_5 );

    HAL_FLASH_Lock();
  HAL_FLASH_Unlock();

    //  Clean all flags except FLASH_FLAG_BSY
    __HAL_FLASH_CLEAR_FLAG( FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGSERR );

  /* Wait for last operation to be completed */
  FLASH_WaitForLastOperation((uint32_t)500);
  //    To check the state of this operation, we must declare
  //    extern FLASH_ProcessTypeDef pFlash;
  if (pFlash.ErrorCode != 0)
    return pFlash.ErrorCode;
  // Make sure the address match the FLASH_SECTOR_1.
  // The Memroy Organisation gives the address of each sector of memory
  HAL_FLASH_Program( FLASH_TYPEPROGRAM_WORD, 0x8004000, 0xAC1234AC );
  HAL_FLASH_Program( FLASH_TYPEPROGRAM_WORD, 0x8004004, 0xCA1234CA );
  // The return code must be 0, otherwise, there is an error
  return pFlash.ErrorCode;
}

The Flash can be use with INTERRUPT. The interrupt must be set before erasing or writing data.

HAL_NVIC_SetPriority(FLASH_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(FLASH_IRQn);

Then, the FLASH_CR_EOPIE must be set like that

  FLASH->CR |=  FLASH_CR_EOPIE;
  HAL_FLASH_Program( FLASH_TYPEPROGRAM_WORD, 0x8004000, 0xAC1234AC );

Inside the Interrupt routine, some flag must be reset

void FLASH_IRQHandler(void)
{
  FLASH->CR &= ~FLASH_CR_PG;
  FLASH->CR &= ~FLASH_CR_EOPIE;
  FLASH->CR |= FLASH_CR_LOCK;
  FLASH->SR = (FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGSERR);
}
YvonBlais
  • 105
  • 1
  • 5
  • The question refers to STM32F7 so a test with STM32F4 and checking the reference manual of STM32F6 may be irrelevant for the actual situation on STM32F7. To which of the other microcontroller families is the STM32F6 similar? F4 or F7? – HelpingHand May 17 '20 at 09:36