最近尝试了一下对32的内置flash进行读写,众所周知,芯片的flash是用来存放代码指令和变量的,其中的数据即使掉电也不会丢失。而stm32的flash之大,对于初学者的小打小闹完全不用担心不够用的情况。
因此,在需要保存一些芯片掉电之后依旧需要保存的数据(数据量不是特别大)时,运用内置flash的空闲部分可以为我们省去一颗eeprom或外置flash的花销。
知识总结:
1.flash的写入之前需要先擦除,且擦除是直接擦除一页(2KBytes),整个流程为
(1)解锁flash(2)擦除一页或多页(3)写数据(4)锁定flash
2.flash正常写入一次是16bit
3.flash的地址从0x08000000开始,存储代码指令与变量。所以在用户自己写flash时,要注意不要把代码指令与变量给覆盖了。查看编译过的代码使用了多少内存,可在Keil中双击工程名查看*.map文件
基地址加上Size就是代码指令与变量占用的空间。在写入用户数据时,要避开这些地方。
以下是基于正点原子库函数的flash读写代码。在STM32F103RCT6测试通过。可以直接复制使用,好用请为博客点个赞!
flash.h:
#ifndef _FLASH_H
#define _FLASH_H
#include "stm32f10x.h"
extern uint32_t Flash_EraseWriteOnePage(uint32_t WRITE_START_ADDR,u16 SizeOf_u32,uint32_t *DataAddress);
extern void Flash_ReadOnePage(uint32_t READ_START_ADDR,u16 SizeOf_u32,uint32_t *DataAddress);
#endif
flash.c
/
//Author: Read Air
//Version: 1.0
//Date:2019/4/18
/
#include "flash.h"
#include "stm32f10x.h"
///
//WRITE_START_ADDR -- 开始写的地址
//SizeOf_u32 -- 要写入的32位(双字)的数量
//DataAddress -- 等待被写入的数据数组(32位的)
//返回值 -- 出现擦除失败故障返回写入地址,正常返回0
///
uint32_t Flash_EraseWriteOnePage(uint32_t WRITE_START_ADDR,u16 SizeOf_u32,uint32_t *DataAddress)
{
char EraseCounter = 0;
static FLASH_Status FLASHStatus;
uint32_t Address;
u16 Remain_u32 = SizeOf_u32;
u8 err_time=0;
/* 解锁 */
FLASH_Unlock();
/* 清空所有标志位 */
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
/* 擦除一页*/
FLASHStatus = FLASH_ErasePage(WRITE_START_ADDR);
/* 尝试擦除*/
while((FLASHStatus != FLASH_COMPLETE)&&(err_time<5))
{
FLASHStatus = FLASH_ErasePage(WRITE_START_ADDR);
err_time++;
}
/* 擦除失败*/
if (err_time >= 5) return WRITE_START_ADDR;
/* 向内部 FLASH 写入数据 */
Address = WRITE_START_ADDR;
while ((Remain_u32 > 0) && (FLASHStatus == FLASH_COMPLETE))
{
FLASHStatus = FLASH_ProgramWord(Address, DataAddress[SizeOf_u32-Remain_u32]);
Address = Address + 4;
Remain_u32--;
}
/* 锁定*/
FLASH_Lock();
return 0;
}
///
//READ_START_ADDR -- 开始写的地址
//SizeOf_u32 -- 要读出的32位(双字)的数量
//DataAddress -- 等待被读出的数据数组(32位的)
///
void Flash_ReadOnePage(uint32_t READ_START_ADDR,u16 SizeOf_u32,uint32_t *DataAddress)
{
uint32_t Address;
u16 Remain_u32 = SizeOf_u32;
/* 检查写入的数据是否正确 */
Address = READ_START_ADDR;
while ((Remain_u32 > 0))
{
DataAddress[SizeOf_u32-Remain_u32] = (*(__IO uint32_t*) Address);
Address += 4;
Remain_u32--;
}
}
//注意事项:
//1、对flash进行写入操作,一定要遵循“先擦除,后写入”的原则
//2、注意到stm32内置flash的擦除操作都是以页为单位进行,而写入操作则必须以16位半字宽度数据为单位,允许跨页写,尝试写入非16位半字数据将导致stm32内部总线错误。
//3、进行stm32的内置flash编程操作时(写或擦除),必须打开内部的RC振荡器(HSI)
//4、注意stm32的内置flash最多只有10万次重复擦写的生命周期,谨记切勿在程序中放任死循环对flash进行持续地重复擦写。