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

3
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根本不工作。

当我擦除了闪存但没有写入任何内容时,OLED上的输出为counter=0x00000008

counter2: 536873624
counter3: -652214262
counter4: 31006720

在编写和重置后:

counter2: 8
counter3: -654311424
counter4: 30998528

这里发生了什么?有人能告诉我为什么所有变量都改变了吗? 我需要配置链接器吗?


我确实了解HAL,因为它是我见过的最荒谬的库之一,但更改此闪存位置并不明智。 - 0___________
@0___________ 为什么HAL很荒谬? - Mohammad Kholghi
3个回答

11

如果您不是初学者,我将为您道歉,现在我会把您当作初学者来对待。

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软件包中找到的示例。

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

这个概念同样适用于您的nucleo板,只需确保设置正确的地址以进行闪存擦除。


我已经输入了 .NbSectors,但现在它根本无法运行。(是的,我是个初学者) - Alex M.
因为您擦除了实际程序用于代码执行的第一个扇区。@AlexM。我告诉过您,检查最后一条语句。 - ringbuffer_peek
哈哈,这就是我为什么是个初学者。现在它像魔法一样运行了,谢谢! - Alex M.
@AlexM。如果这对您有用,请将其标记为正确答案。 - ringbuffer_peek

0

感谢 @phoenix!

在Stm32CubF3中,参考擦除闪存的工作方式如下:

需要提到的是,内存页地址的格式如下:

/* 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. 最好的方法是在链接脚本中创建新的闪存段,并将数据放置在那里。这是最安全的。

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

  3. 如果两者都不知道,我建议使用来自Cube的现成STM EEPROM仿真示例。


我建议使用来自Cube的现成STM eeprom仿真示例。你有链接吗? - phoenix
谷歌搜索您的微控制器,您将在STM网站上找到Cube的链接。 - 0___________
2
对于未来的读者,针对STM32F3系列,请下载STM32CubeF3,并查看STM32303E_EVAL/Applications/EEPROM/EEPROM_Emulation - phoenix

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接