我正在使用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);
谢谢你
闪存要求你要写入的扇区必须在擦除状态下才能写入。
为此,你需要一些额外的步骤才能使你的写入持久化。
下面是一个如何做到这一点的例子,但要确保地址与你的目的相符,这里只是一个通用的代码。
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;
}
我用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);
}