STM32F4 nucleo 上的 HAL 驱动程序 erase/read/write 闪存

HAL drivers erase/read/write flash on STM32F4 nucleo

uint32_t PAGEError = 0;
FLASH_EraseInitTypeDef EraseInitStruct;
EraseInitStruct.TypeErase   = FLASH_TYPEERASE_SECTORS ;
EraseInitStruct.Sector   = FLASH_SECTOR_0;
EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;

HAL_FLASH_Unlock();
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);
HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError);
HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, 0x08000000, counter)
HAL_FLASH_Lock();

counter2 = *(__IO uint32_t *)0x08000000;
counter3 = *(__IO uint32_t *)0x08000001;
counter4 = *(__IO uint32_t *)0x08000002;

sprintf(buf, "%d", counter2); //gets send to the OLED with I2C
sprintf(buf2, "%d", counter3);
sprintf(buf3, "%d", counter4);

我想将变量counter写入flash,然后读取为counter2。 第一个闪存扇区从 0x08000000.

开始

counter234 是通过 OLED 屏幕显示的。 显示 counter2 有效并向我显示 counter-1 的值,但它只有效一次。如果我再次写入闪存,似乎什么也没有发生。

counter3counter4 根本不起作用。

擦除闪存但未写入任何内容后counter=0x00000008时OLED上的输出:

counter2: 536873624
counter3: -652214262
counter4: 31006720

写入和重置后:

counter2: 8
counter3: -654311424
counter4: 30998528

这是怎么回事?有人能告诉我为什么所有变量都会改变吗? 我必须配置链接器吗?

现在我会把你当成初学者,如果你不是初学者,我会说对不起。

STM32 设备在 0x08000000 上有闪存,通过擦除此扇区,您在启动时失败了,因为您从 CPU 加载指令的地方擦除了实际部分。

当您尝试擦除扇区时,您没有指定要擦除多少 个扇区。

计数器读取错误。因为你有 uint32_t 变量,你必须在读数之间做 4 个字节,比如:

counter2 = *(__IO uint32_t *)0x08000000;
counter3 = *(__IO uint32_t *)0x08000004;
counter4 = *(__IO uint32_t *)0x08000008;

正确的擦除如下图

EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;
EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;
EraseInitStruct.Sector = FLASH_SECTOR_0; //Specify sector number
EraseInitStruct.NbSectors = 1; //This is also important!
if(HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) {
    //Erase error!
}

所以,找出你的程序有多长,然后在你的程序之后的扇区中进行操作。

您可以在 STM32CubeF4 包中找到 EraseProgram 的示例。

STM32Cube_FW_F4_V1.16.0\Projects\STM324x9I_EVAL\Examples\FLASH\FLASH_EraseProgram\Src\main.c

概念也适用于您的 nucleo,只要确保您设置正确的闪存擦除地址即可。

  1. 最好的方法是在 linkescriptr 中创建新的 flash 段并将数据放在那里。这是最安全的。

  2. 如果不知道链接器脚本创建一个 table 一个段大小,并使用您的编译器指令将其放在闪存的末尾。

  3. 如果您不知道两者,我建议您使用 Cube

  4. 中现成的 STM eeprom 仿真示例

感谢@phoenix!

在Stm32CubF3参考擦除flash的工作原理如下:

这里提到内存页面地址的样子:

/* Base address of the Flash sectors */
#define ADDR_FLASH_PAGE_0   ((uint32_t)0x08000000) /* Base @ of Page 0, 2 Kbytes */
#define ADDR_FLASH_PAGE_1   ((uint32_t)0x08000800) /* Base @ of Page 1, 2 Kbytes */
#define ADDR_FLASH_PAGE_2   ((uint32_t)0x08001000) /* Base @ of Page 2, 2 Kbytes */
#define ADDR_FLASH_PAGE_3   ((uint32_t)0x08001800) /* Base @ of Page 3, 2 Kbytes */
#define ADDR_FLASH_PAGE_4   ((uint32_t)0x08002000) /* Base @ of Page 4, 2 Kbytes */
#define ADDR_FLASH_PAGE_5   ((uint32_t)0x08002800) /* Base @ of Page 5, 2 Kbytes */
#define ADDR_FLASH_PAGE_6   ((uint32_t)0x08003000) /* Base @ of Page 6, 2 Kbytes */

因此您的最小代码如下所示:

我想删除我的应用程序 @ 0x08003000 --> FLASH_PAGE_6。擦除以 2kB 的大小完成:

/* EEPROM start address in Flash */
#define EEPROM_START_ADDRESS  ((uint32_t)ADDR_FLASH_PAGE_32) /* EEPROM emulation start address */

/* Pages 0 and 1 base and end addresses */
#define PAGE0_BASE_ADDRESS    ((uint32_t)(EEPROM_START_ADDRESS + 0x0000))
#define PAGE0_END_ADDRESS     ((uint32_t)(EEPROM_START_ADDRESS + (PAGE_SIZE - 1)))
//#define PAGE0_ID               ADDR_FLASH_PAGE_32


/* Clear flash flags */
HAL_FLASH_Unlock();
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP    |
                       FLASH_FLAG_WRPERR |
                       FLASH_FLAG_PGERR);


uint32_t *flash_ptr = 0x8003000;
uint32_t page_error = 0;

HAL_StatusTypeDef  flashstatus;
FLASH_EraseInitTypeDef s_eraseinit;
/* Fill EraseInit structure*/
s_eraseinit.TypeErase   = FLASH_TYPEERASE_PAGES;
s_eraseinit.NbPages     = 1;             // seems to be 1 !!!!

/* I want to delete 54kB in my flash --> 52kB / 2kB (per erase) = 26 iterations
   After erasing one page, increment page by 0x800 = 2048 byte = 2kB = pagesize */
for(int pageCount = 0;  pageCount < 26; pageCount++){
   s_eraseinit.PageAddress = ADDR_FLASH_PAGE_6 + pageCount * 0x800;
   flashstatus = HAL_FLASHEx_Erase(&s_eraseinit, &page_error);

}