关于Flash,官方的解释为:Flash为32位宽的存储单元,可用于存储代码和数据常量。Flash模块位于微控制器内存映射中的特定基址……。而对于我们来说,只要知道Flash闪存区是一个掉电后也不会清除的数据存储地。(相信大家对于Flash闪存也有着一定 的了解了,我也不多说废话,直接开整)
STM32芯片大致可分为小容量、中容量和大容量三种类型,在小容量和中容量系列芯片中一个扇区为1KB,在大容量系列芯片中一个扇区为2KB,为什么要说这个呢?因为Flash的擦除只能以一个扇区为最小单位擦除。因为代码也是存储在Flash区,所以各位在做项目时,最先就应该将内存分配好,我的建议是将Flash最后一个扇区用来做用户数据存储,我们甚至可以在keil配置好代码地址,这样就每次下载程序时也不会改变最后一个扇区的数据。
例:以STM32F103C6Tx的一款芯片为例(代码部分同),这个芯片拥有32KFlash存储器容量,算是小容量芯片。
![](https://i-blog.csdnimg.cn/blog_migrate/8ec7cc18a8eb823b04a634e561b0c782.png)
如果不设置,IROM1的地址应该为:0x8000000—0x8000,0x8000转换为十进制为32768,除以1024(1KB为1024bit),刚好为32K,减去最后一个扇区1KB,31KB转换为十六进制为0x7C00,设置后就如图所示,IROM1的地址为0x8000000—0x7C00,表示keil写入代码时将不会擦除0x7C00以后的空间,数据也会得以保存。
Flash读操作
因为嵌入式Flash模块可以直接寻址,因此读取操作十分简单,只需要找到读取的地址即可。
uint16_t Flash_Data; //存储数据
__IO uint16_t * flashPtr; //该指针用来存储Flash读写地址
首先需要定义一个指针,该指针主要用来存储Flash读写的地址,__IO uint16_t数据类型表示flashPtr是一个易变的无符号的大小为16位的指针。
flashPtr = (__IO uint16_t *) 0x08007C00; //指向数据地址
Flash_Data = *flashPtr; //读取数据
两行代码就可以完成对Flash的读取,只是指针的简单运用,当然在实际项目中最好加上对提取数据的校验。
Flash写操作
写入Flash是一个相对复杂的过程,已经是在对STM芯片底层数据直接编程,废话不多说。Flash写入数据,大致可分为两个步骤,一是擦除数据、二是写入数据。在上代码前,我们先来了解几个会用到的Flash寄存器:
![](https://i-blog.csdnimg.cn/blog_migrate/6935c61a5e67c716229643e729dd6b80.png)
首先是Flash控制寄存器(FLASH_CR),主要了解第0位PG写入控制位、第1位PER擦除控制位、第6位STRT擦除触发控制位和第7位LOCK解锁控制位,再此我不过多介绍,在文章末尾我会提供STM32F103Flash编辑手册,各位自行去阅读(配合手册去理解代码事半功倍)。
![](https://i-blog.csdnimg.cn/blog_migrate/9a19c04ae12e7040506a5cc82865ba4e.png)
其次是Flash状态寄存器(FLASH_SR),主要了解第5位EOP擦除/写入完成标志位,第0位BSYFlash擦除/写入状态位。
FPEC密钥寄存器(FLASH_KEYR),这个寄存器用来写入钥匙,Flash地址寄存器(FLASH_AR)用来写入扇区擦除的首地址。
这个是官方提供写入Flash的具体流程,每次写入前需要先判断FLASH_CR_LOCK位,当为1时可直接进行写入配置,当为0时需要先解锁才能写入配置(为什么要解锁呢?因为每次复位后FPEC(闪存编程和擦除控制器)都是被锁定的,只有解锁后才有权限),写入配置很简单只需要置位FLASH_CR_PG写入位,再把数据(16位)写入指定的地址,再检测是否写好,最后重新上锁。当然写入前需要先擦除,擦除也是同样的操作,接下来请看代码:
/*Flash解锁函数*/
void Flash_unlock(void) {
if ((FLASH->CR & FLASH_CR_LOCK) != RESET) { //判断LOCK位
FLASH->KEYR = 0x45670123;
FLASH->KEYR = 0xCDEF89AB;
/*若LOCK位不为1,则执行解锁程序,向Flash_KEYR寄存器写入解锁密钥,密钥是唯一的,
一旦写错,就会锁死,只能复位后才能操作Flash*/
}
}
/*Flash写入函数*/
void putFlash(void)
Flash_unlock(); //解锁
SET_BIT(FLASH->CR, FLASH_CR_PER); //置位扇区擦除控制位
WRITE_REG(FLASH->AR, 0x08007C00); //对应扇区起始地址
SET_BIT(FLASH->CR, FLASH_CR_STRT); //开始扇区清除
while ((FLASH->SR & (FLASH_SR_BSY | FLASH_SR_EOP)) != 0x20) //等待擦除完毕
;
FLASH->SR |= FLASH_SR_EOP; //清除标志位
FLASH->CR = 0x80; //重新上锁,擦除完成
Flash_unlock(); //解锁
flashPtr = (__IO uint16_t *) 0x08007C00; //选择写入地址,只能是擦除的扇区内
SET_BIT(FLASH->CR, FLASH_CR_PG); //置位Flash写入控制位
*flashPtr = Flash_Data; //写入数据到flashPrt地址对应空间中
while ((FLASH->SR & (FLASH_SR_BSY | FLASH_SR_EOP)) != 0x20) //等待写入完成
;
FLASH->SR |= FLASH_SR_EOP; //清除标志位
FLASH->CR = 0x80; //重新上锁
}
通过上面两个函数便可以完成对Flash的写入,当然为了方便大家理解,我代码写的很简单,到了真实项目中,我的代码只能作为你们的思路。
注意事项:
Flash擦除/写入千万、千万、千万不要放到主程序while循环中,因为每一块芯片由于硬件的限制对于Flash的擦除/写入都是次数限制的,一旦用完这些擦除/写入次数,芯片就报废了,当然也不用太小心,一般这个限制次数都是10万次。
Flash擦除/写入是一个比较严谨的过程,一旦出错将会导致整个程序的崩溃,所以希望大家多看看手册。
手册资料:
STM32F103XXFlash编辑手册:链接:https://pan.baidu.com/s/1IdWxsnysqhs6iWfW5oIhaQ
提取码:udbs