stm32 HAL库 Flash操作简介
目录
stm32的hal库确实提供有关flash的操作代码库,,但是我们在操作flash之前依旧需要对stm32的flash进行简单的介绍。
首先,stm32的flash读不限制次数,写大约100 0000次,也就是说一天对同一个地方写100次,你需要大约20年才能写坏,所以可以你可以放心大胆的写。
其次,对于flash的操作代码也储存在flash中,也就是说如果你的写块覆盖掉了你的原始代码,你的程序可能出现未知的错误。
最后,flash的读写操作在一定程度上的修正,可以有效的实现代码的边运行变更新,当然有人意识到这就是iap,但是我不这么认为,iap至少需要bootloaer启动不同的代码块,而采用这种操作可以在运行状态下修正部分常量。例如,如果你的某段控制代码或者运行代码的某些参数并非是最优的,需要在运行中调节,你就可以通过指定该常量的存储地址并且在之后的运行与自我修正中不停 的覆盖,就可以闪现代码的自我优化。
第一stm32,flash介绍
stm32的烧录后的程序起始地址是从 0x0800 0000开始的,但是起始地址是从0x0000 0000,根据芯片名字及明面规则计算可用flash的结束地址。
对照下图的内存映射表就可以看出内存的开始与结束位置
查看代码段,以判断代码长度
一个编译完成的程序在下方会提示你代码长度,其中
Code 表示代码占用的空间
RO-data表示(Read Only) 只读常亮的大小,如const 型、字符串常量;
RW-data表示(Read Wirte) 已初始化的读写数据,程序中定义并且初始化的全局变量和静态变量位于此处
ZI-data表示(Zero Initialize) 未初始化的读写数据,程序中定义了但没有初始化的全局变量和静态变量
烧写入Flash中所占用的空间为:Code + RO-data + RW-data
程序运行时,芯片所占用的RAM空间为:RW-data + ZI-data
然后通过实际可用地址开始位置为0x0800 0000+烧写入Flash中所占用的空间
当然这种方法还学要计算比较麻烦,还有一种更为简单的查找方式,打开工程所属的文件夹,在右上角搜索中找到 .map开头文件
找到内存映射,将这两个求和就行了。
flash的基本操作规则
flash的成型以块(block)和扇区(sector)存在
STM32的flash在写的时候不能读,读的时候不能写,也就是说stm32在操作flash的时候程序必然是中止的,所以既不能响应中断,也不能有运行程序
During a write operation to the Flash memory, any attempt to read the Flash memory willstall the bus. The read operation will proceed correctly once the write operation hascompleted. This means that code or data fetches cannot be made while a write/eraseoperation is ongoing.For write and erase operations on the Flash memory(write/erase), the internal RC oscillator (HSI) must be ON.
The Flash memory can be programmed and erased using in-circuit programming and in-application programming.
中文翻译第一段话:在Flash写入操作过程中,任何试图读取Flash的操作都会锁定住总线,在完成Flash写操作之后读取Flash操作会继续执行,这意味着写入Flash期间无法访问Flash中的代码和数据。
极端情况下,如果想写FLASH时响应中断,唯有cortex-m从RAM中取指令能行的通,即写FLASH前,将响应中断的代码从FLASH拷入RAM中运行并将中断向量表设置到RAM即可。
flash的读可以从读写可以从任何地方开始,但是一次必须以半字,字,或者双字的方式来,但是flash的写之前如果该扇区存在数据,必须擦除整个扇区,再重写。
对照下面的表格可以找出你所有的可操作的stm32的扇区,不是你的代码段,又恰好在可用的flash扇区。
stm32 HAL库 Flash操作指南
stm32 有一个与flash相关的寄存器FLASH Option Control Registers该寄存器提供了flash的读写保护以及中断响应flag等标识。
stm32f1xx_hal_flash.c
该文件用于基本的flash操作,提供了以下的方法对flash进行写操作与上锁解锁操作。
写操作
/** @addtogroup FLASH_Exported_Functions_Group1
* @{
*/
/* IO operation functions *****************************************************/
HAL_StatusTypeDef HAL_FLASH_Program(uint32_t TypeProgram, uint32_t Address, uint64_t Data);
HAL_StatusTypeDef HAL_FLASH_Program_IT(uint32_t TypeProgram, uint32_t Address, uint64_t Data);
/* FLASH IRQ handler function */
void HAL_FLASH_IRQHandler(void);
/* Callbacks in non blocking modes */
void HAL_FLASH_EndOfOperationCallback(uint32_t ReturnValue);
void HAL_FLASH_OperationErrorCallback(uint32_t ReturnValue);
上锁与解锁
/** @addtogroup FLASH_Exported_Functions_Group2
* @{
*/
/* Peripheral Control functions ***********************************************/
HAL_StatusTypeDef HAL_FLASH_Unlock(void);
HAL_StatusTypeDef HAL_FLASH_Lock(void);
HAL_StatusTypeDef HAL_FLASH_OB_Unlock(void);
HAL_StatusTypeDef HAL_FLASH_OB_Lock(void);
void HAL_FLASH_OB_Launch(void);
void FLASH_PageErase(uint32_t PageAddress);
注意上面的最后一行代码,FLASH_PageErase该函数在擦除时没有检测并且置0忙标识位,使得该段flash一直状态忙,无法使用,所以在擦除页面时一定要使用下面文件中的HAL_FLASHEx_Erase函数
stm32f1xx_hal_flash_ex.c
flash擦除
/** @addtogroup FLASHEx_Exported_Functions_Group1
* @{
*/
/* IO operation functions *****************************************************/
HAL_StatusTypeDef HAL_FLASHEx_Erase(FLASH_EraseInitTypeDef *pEraseInit, uint32_t *PageError);
HAL_StatusTypeDef HAL_FLASHEx_Erase_IT(FLASH_EraseInitTypeDef *pEraseInit);
flash 寄存器操作
/** @addtogroup FLASHEx_Exported_Functions_Group2
* @{
*/
/* Peripheral Control functions ***********************************************/
HAL_StatusTypeDef HAL_FLASHEx_OBErase(void);
HAL_StatusTypeDef HAL_FLASHEx_OBProgram(FLASH_OBProgramInitTypeDef *pOBInit);
void HAL_FLASHEx_OBGetConfig(FLASH_OBProgramInitTypeDef *pOBInit);
uint32_t HAL_FLASHEx_OBGetUserData(uint32_t DATAAdress);
代码实例
flash 读数据
uint16_t flash_read = *(__IO uint16_t*)( Flash_Add ); //读2字节
uint32_t flash_read = *(__IO uint32_t*)( Flash_Add );//读4字节
flash 擦除页
uint32_t Flash_Add = 0x0800d000;
FLASH_EraseInitTypeDef My_Flash; //声明FLASH_EraseInitTypeDef 结构体为 My_Flash
HAL_FLASH_Unlock(); //解锁Flash
My_Flash.TypeErase = FLASH_TYPEERASE_PAGES; //标明Flash执行页面只做擦除操作
My_Flash.PageAddress = Flash_Add; //声明要擦除的地址
My_Flash.NbPages = 1; //说明要擦除的页数,此参数必须是Min_Data = 1和Max_Data =(最大页数-初始页的值)之间的值
uint32_t PageError = 0; //设置PageError,如果出现错误这个变量会被设置为出错的FLASH地址
HAL_FLASHEx_Erase(&My_Flash, &PageError); //调用擦除函数擦除
HAL_FLASH_Lock();
flash 写操作
HAL_FLASH_Unlock(); //解锁Flash
uint16_t Write_Flash_Data = my_data;
HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, Flash_Add, Write_Flash_Data); //对Flash进行烧写,FLASH_TYPEPROGRAM_HALFWORD 声明操作的Flash地址的16位的,此外还有32位跟64位的操作,自行翻查HAL库的定义即可
HAL_FLASH_Lock(); //锁住Flash