HAL驱动程序擦除/读取/写入STM32F4核上的闪存

时间:2017-08-08 17:08:37

标签: c stm stm32f4

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

我想将变量计数器写入闪存,然后将其读作counter2。 第一个闪存扇区从0x08000000开始。

counter234通过OLED屏幕显示。 显示counter2有效并向我显示counter-1的值,但它只能运行一次。如果我再次写入闪光灯,似乎没有任何事情发生。

counter3counter4根本不起作用。

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

counter2: 536873624
counter3: -652214262
counter4: 31006720

写作和重新设定后:

counter2: 8
counter3: -654311424
counter4: 30998528

这里发生了什么?有人能告诉我为什么所有变量都会改变吗 我是否必须配置链接器?

3 个答案:

答案 0 :(得分:5)

我现在会把你当作乞讨者,但如果不是,我会说对不起。

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

概念也适用于您的核心,只需确保为闪存擦除设置正确的地址。

答案 1 :(得分:0)

感谢@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);

}

答案 2 :(得分:-1)

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

  2. 如果不知道链接描述文件创建一个段大小的表,并使用编译器指令将其放在flash的末尾。

  3. 如果您不知道两者,我建议使用Cube中的现成STM eeprom仿真示例