你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32F0x HAL库学习笔记(6)片内闪存(Flash)的读写操作

[复制链接]
STMCU小助手 发布时间:2021-11-24 14:59
本文开发环境:

MCU型号:STM32F051R8T6
IDE环境: MDK 5.25
代码生成工具:STM32CubeMx 5.0.1
HAL库版本:v1.9.0(STM32Cube MCU Package for STM32F0 Series)

本文内容:

MCU片内Flash(闪存)的擦除与读写
一个Flash读写例子

Example
首先给出一个Flash程序一个完整的片段:
  1. ... ...
  2. #include "stm32f0xx_hal.h"
  3. ... ...
  4. static FLASH_EraseInitTypeDef EraseInitStruct = {
  5.         .TypeErase = FLASH_TYPEERASE_PAGES,       //页擦除
  6.         .PageAddress = 0x08008000,                //擦除地址
  7.         .NbPages = 1                              //擦除页数
  8. };
  9. ... ...
  10.   while (1)
  11.   {
  12.                 HAL_FLASH_Unlock();
  13.                 uint32_t PageError = 0;
  14.                 __disable_irq();                             //擦除前关闭中断
  15.                 if (HAL_FLASHEx_Erase(&EraseInitStruct,&PageError) == HAL_OK)
  16.                 {
  17.                         printf("擦除 成功\r\n");
  18.                 }
  19.                 __enable_irq();                             //擦除后打开中断
  20.                 uint32_t writeFlashData = 0x55555555;        //待写入的值
  21.                 uint32_t addr = 0x08008000;                  //写入的地址
  22.                 HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,addr, writeFlashData);
  23.                 printf("at address:0x%x, read value:0x%x\r\n", addr, *(__IO uint32_t*)addr);
  24.             HAL_FLASH_Lock();
  25.                 while(1);
  26.                
  27.     /* USER CODE END WHILE */
  28.     /* USER CODE BEGIN 3 */
  29.   }
复制代码

本地代码段写在main.c中,STMCubeMx生成工程时已经在main.c文件中包含了各种头文件,所以这段代码可以直接使用的,如果我们想在其它文件中使用它,请记得包含HAL库头文件:
  1. #include "stm32f0xx_hal.h"
复制代码

特别的,擦除flash的时候不能执行其他程序,所以擦除前要关闭中断,擦除后记得恢复中断状态。这段代码一旦运行,就会在特定地址写入特定的值,并可以通过串口助手查看数据:

20190420203712573.png


FLASH 简介
Reference manual (RM0091)手册给出了该系列的用户Flash的起始地址,Page,Sector的划分,这个是一个重要的参考信息,因为在Flash操作中,我们要写入数据需要先擦除数据,而擦除的最小单位是PAGE。单片机有几种启动模式,但大多数是从0x0800 0000这段代码开始运行的,我们的代码也是从这个地址开始烧录。这类似于我们计算机,常见开机就是从C盘(如果C是系统盘)启动,但是也可以设置从U盘启动。由于Flash的介绍,手册和网上已经有非常多的资料。

20190420144436525.png


Flash 的上锁与解锁
在操作Flash之前,我们都需要对Flash进行解锁,对应的,操作完Flash之后,则需要对Flash进行上锁。这里的操作包括擦除,读和写等。HAL库提供了2个API,用户可以直接调用:

  1. HAL_StatusTypeDef HAL_FLASH_Unlock(void);
  2. HAL_StatusTypeDef HAL_FLASH_Lock(void);
复制代码

Flash 的擦除
在擦除Flash之前,我们需要确定一些参数,擦除的地址,擦除的页数等,HAL库提供了一个与之相关的结构体:

  1. typedef struct
  2. {
  3.   uint32_t TypeErase;   /*!< TypeErase: Mass erase or page erase.
  4.                              This parameter can be a value of @ref FLASHEx_Type_Erase */

  5.   uint32_t PageAddress; /*!< PageAdress: Initial FLASH page address to erase when mass erase is disabled
  6.                              This parameter must be a number between Min_Data = FLASH_BASE and Max_Data = FLASH_BANK1_END */

  7.   uint32_t NbPages;     /*!< NbPages: Number of pagess to be erased.
  8.                              This parameter must be a value between Min_Data = 1 and Max_Data = (max number of pages - value of initial page)*/

  9. } FLASH_EraseInitTypeDef;
复制代码

所以在使用擦除函数之前,我们先定义一个结构体,并初始化它:
  1. static FLASH_EraseInitTypeDef EraseInitStruct = {
  2.         .TypeErase = FLASH_TYPEERASE_PAGES,        //擦除类型:page擦除,即擦除整页。也可以选择擦除整片
  3.         .PageAddress = 0x08008000,                 //擦除起始地址
  4.         .NbPages = 1                               //擦除页数
  5. };
复制代码

初始化好结构体之后,就可以使用HAL官方提供的API进行擦除:

  1. HAL_StatusTypeDef HAL_FLASHEx_Erase(FLASH_EraseInitTypeDef *pEraseInit, uint32_t *PageError)
复制代码

其中第一个参数为指针,我们传入我们上文初始化好的结构体,第二个参数用来存放错误信息,我们新建一个值来存储,以下是示例代码:
  1. ... ...
  2. uint32_t PageError = 0;
  3. HAL_FLASH_Unlock();
  4. if (HAL_FLASHEx_Erase(&EraseInitStruct,&PageError) == HAL_OK)
  5. {
  6.         printf("Erase Succeed\r\n");
  7. }
  8.         HAL_FLASH_Lock();
  9. ... ...
复制代码

如果你有ST-LINK或者J-LINK此类的调试器,可以使用硬件调试,然后查看0x08000000对应扇区的值,你会发现擦除后的数据全是0xFF。

Flash 的读写操作
Flash的写操作
当我们擦除了一个扇区,该扇区就属于可以写状态,我们可以通过读Flash来确认我们写入的值,HAL库提供的写操作函数如下:
  1. HAL_StatusTypeDef HAL_FLASH_Program(uint32_t TypeProgram, uint32_t Address, uint64_t Data)
复制代码

其中:
  1. - TypeProgram :写类型,只可以是半字(2个字节)或字(4个字节)
  2. - Address     :地址
  3. - Data        :写入的数据的值
复制代码

Flash的读操作
Flash 只需要所在地址,就可以读取对应的值:
  1. uint32_t pValue= *(__IO uint32_t*)(addr);
复制代码

以下程序写入一个值,并将整个值读取出来:
  1. ... ...
  2. uint32_t writeFlashData = 0x55555555;
  3. uint32_t addr = 0x08008000;
  4. HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,addr, writeFlashData);
  5. printf("at address:0x%x, read value:0x%x\r\n", addr, *(__IO uint32_t*)addr);
  6. HAL_FLASH_Lock();
  7. ... ...
复制代码

注意
由于我们经常使用Flash来存放用户程序,所以要特别注意我们读写的时候不破坏到原程序,本文因为程序很小,不可能写到0x08008000,所以直接用这个地址作为例子,在实际运行中,我们需要设计要那些区域是可以用来读写的,避免出现程序错误。



收藏 评论0 发布时间:2021-11-24 14:59

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版