3

我正在使用 HAL_FLASH_Program() 将 uuid 编程到特定地址。我可以通过从同一地址读取来验证它是否成功写入。但是,如果我重新启动 MCU,该地址处的内存将恢复为原始值。如果我直接通过 ST-Link 写入它,那么它会永久保留。

有谁知道这是为什么?在使用 HAL_FLASH_Program() 写入之前,我是否需要擦除内存位置?我正在使用STM32F745。

我的代码很简单:

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

谢谢

4

2 回答 2

1

闪存要求您要写入的扇区必须处于擦除状态才能写入。

为此,您需要一些额外的步骤才能使您的写入持久化。

下面是一个示例,但请确保地址符合您的目的,这只是一个通用代码:

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;
}

于 2020-05-02T22:12:53.997 回答
-1

我用 Stm32F417 做了一个测试。我查看了 STM32F6xx 的参考手册。看起来很相似。

擦除闪存

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
}

将数据写入闪存

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;
}

Flash 可以与 INTERRUPT 一起使用。必须在擦除或写入数据之前设置中断。

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

然后,必须像这样设置 FLASH_CR_EOPIE

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

在中断例程中,必须重置某些标志

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);
}
于 2020-05-05T16:38:34.923 回答