STM32 Flash闪存

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

如果有一些配置参数,需要掉电不丢失的保存,再外挂一个存储器芯片的话,显然会增加硬件成本,那STM32本身就是有掉电不丢失的程序存储器,直接把参数存里面,又方便,又节省成本,

每个芯片的唯一ID号都不一样,

闪存的操作很麻烦,涉及到擦除,编程,等待忙,解锁等等操作,,所以这里我们要把我们的指令和数据写入到这个外设的相应寄存器,然后这个外设会自动去操作对应的存储空间。这个外设可以对程序存储器和选型字节,这两部分进行擦除和编程,对比上面三个部分,少了系统存储器这个区域,因为系统存储器是原厂写入的Boot Loader程序,不允许我们修改,一般我们写个简单的程序,只占前面很小一部分空间,剩下的大片空余空间,可以加以利用,比如存储一些我们自定义的数据,我们在选取区域时,一定不要覆盖原有的程序,要不然程序自己把自己给破坏了,之后程序就运行不了了,一般存储少量的参数,我们就选最后几页就行了。关于如何查看程序所占空间的大小,下一节介绍。

IAP利用程序来修改程序本身,在数码圈,有个熟悉的技术叫OTA,都时实现程序升级的。
SWD每次下载,都是把整个程序完全更新掉,系统加载程序就是串口下载,串口下载,也是更新整个程序,也就是我们在用的ICP下载方式,

更高级的IAP,怎么实现呢,我们首先自己写一个bootloader程序,并且存放在程序更新时,不会覆盖的地方,然后我们控制程序跳转到这个自己写的Bootloader里来,在这里面,我们就可以接收任意一种通信接口传过来的数据,比如串口,USB,蓝牙转串口,Wifi转串口等等,这个传过来的数据,就是待更新的程序,然后我们控制Flash读写,把收到的程序,写入到前面程序正常运行的地方,写完之后,再控制程序跳转回到正常运行的地方,这样程序就完成了自我升级,

其实就是和系统存储器这这个Boot Loader一样,因为要实现程序的自我升级,所以需要布置一个辅助的小机器人来临时干活,只不过系统存储器的Boot loader写死了,只能用串口下载到指定位置,启动方式也不方便,只能配置BOOT引脚触发启动,而我们自己写Boot Loader的话,就可以想怎么收就怎么收,想写到哪就写到哪,想怎么启动就怎么启动,并且整个升级过程,程序自主完成,实现在程序中编程,更进一步就可以直接实现远程升级。
这个具体的内容,可以研究一下,很有意义的。 OTA在线升级。

此节只涉及对Flash进行读写,是实现IAP的基础,
参考手册是闪存编程参考手册,

闪存模块组织分为3个块,第一个是主存储器,也就是刚刚说的程序存储器,这时最主要,也是容量最大的一块,第二个是信息块,其中启动程序代码就是系统存储器,存放的是原厂写入的Boot Loader,用于串口下载,这个手册的名称经常会有不同的表述方式,但要知道,某些名称描述的是一个东西,用户选择字节就是刚才说的选项字节,存放一些独立的参数,在手册里一直都称作选择字节, 可能是翻译的问题,Option Bytes。闪存存储器接口寄存器实际并不属于闪存,就是一个普通的外设,和之前讲的GPIO,定时器,串口等等是一个性质,
这些存储器,他们的存储介质,也都是SRAM,这个闪存存储器接口,是上面这些闪存的管理员,这些寄存器就是用来控制擦除和编程这个过程的,。

并没有读取是因为读取指定存储器,直接使用指针读即可,用不到这个外设,

分页是为了更好地管理闪存,擦除和写保护,都是以页为单位的,这一点和之前W25Q64那一节的闪存一样,擦除必须以最小单位进行,擦除后数据位全变为1,数据只能1写0,不能0写1,擦除和写入之后都需要等待忙,。
建议掌握W25Q64,其实一样,

闪存接口寄存器包括KEY键寄存器,SR状态寄存器,CR控制寄存器等等

解锁时有两层写入,都通过才行,

使用指针读指定地址下的存储器代码意思
第一步,我们需要给定要读取寄存器的地址:比如这里以0800 0000为例,像读取这个地址下的数据,括号时目前里里面只有一个数,如果要对这个地址进行加减,那就必须加上括号,并且在括号里加减,
地址前面加上强制类型转换,转换为uint16_t的指针类型,如果你想以16位的方式读出指定地址的数据,那就转换成uint16_t* ,8位就是uint8_t*,浮点类型就是 float或者double,这个根据读取形式来,然后这个指针类型前面,还加个_IO,在STM32中,这是一个宏定义,对应C语言的关键字,volatile 易变的数据,是一个安全保障措施,在程序逻辑上没有作用,但是加上这个关键字的目的用一句话来说时为了防止编译器优化,
首先keil编译器默认情况下时最低优化等级,这时加不加volatile都没有影响,如果提高优化等级就会有影响,用途就是去除无用的繁杂代码,降低代码空间,提升运行效率,但优化之后,编译器在某些地方可能弄巧成拙,
比如想用计数空循环的方式实现延时函数,那编译器优化,可能会说这段延时函数好像没用用,直接给你优化掉,不浪费时间,因为我们本意就是浪费时间来延时,加上volatile,告诉编译器,无论对这个变量干什么,都原封不动地去执行,别给我优化掉了,另外编译器还会利用缓存来加速代码,比如如果你要频繁读写内存的某个变量,最常见优化方式就是先把变量转移到高速缓存里来。
在STM32内核里,有一个类似缓存的工作组寄存器,先把变量放缓存里,需要读写的时候,直接访问缓存就行了,弄完之后,再写回内存,这是一个优化方案,但是,如果你的程序里有多个线程,在中断函数里,你改变了这个原始变量,那可能缓存并不知道你更改了,这时我们的做法也是,读取变量定义的前面,加上一个volatile,告诉编译器这个变量是易变的,每次读取你都得执行到位,要直接从内存里找,不要再用缓存优化了,如果开启了编译器优化,在无意义加减变量,多线程更改变量,读写与硬件相关的存储器时,都需要加上volatile,防止被编译器优化,如果默认不开编译器优化,那加不加无所谓。

这里面的部分,就是一个指针变量,并且指针已经指向了0x0800 0000这个位置,最后一步就是使用*号,把这个指针指向的存储器取出来了,这个值就是指定存储器的值,取出来之后,我们可以把它赋值给自定义的变量Data,这样就完成指定地址读的任务了,是不需要解锁的,因为读取只是看看存储器,不对存储器进行更改,

下面的写的语句意思很明显,先给定地址,再强转为指针,最后指针取内容,这样就是之指定地址的值

如果写入的地址是SRAM的地址,可以直接写入,因为SRAM在程序运行时是可读可写的,

如果是其他的,写入需要解锁,并且执行三个流程,第一个是编程,也就是写入,STM32的闪存也是写入前必须擦除,擦除之后,所有的数据位变为1,擦除的最小单位就是一页,1K,1024字节,把所有的页都擦除掉,库函数已经帮我们写好了,直接调一个整体的参数就行了,

擦除之后,编程,

如果你想写入一段程序,只能在指定设备运行,那就可以在程序的多处,加入ID号判断,如果不是指定的设备ID号,就不执行程序功能,这样即使程序被盗,在别的设备上也难以运行,

Flash.h中的函数被分为了3个部分,各容量不同对应的函数能用的就不同

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值