STM32—FLASH闪存

1.FLASH简介

  • STM32F1系列的FLASH包含程序存储器、系统存储器和选项字节三个部分,通过闪存存储器接口(外设)可以对程序存储器和选项字节进行擦除和编程
    • 我们怎么操作这些存储器呢?这就需要用到这个闪存存储器接口了,闪存存储器接口是一个外设,是这个闪存的管理员,毕竟闪存的操作很麻烦,涉及到擦除、编程、等待忙、解锁等等操作,所以这里,我们需要把我们的指令和数据,写入到这个外设的相应寄存器,然后这个外设就会自动去操作对应的存储空间,后面写这个外设可以对程序存储器和选项字节,这两部分,进行擦除和编程,对比上面的三个部分少了系统存储器这个区域,因为系统存储器是原厂写入的Bootloader程序,不允许我们修改
  • 读写FLASH的用途:
    • 利用程序存储器的剩余空间来保存掉电不丢失的用户数据
      • 对于我们这个C8T6芯片来说,它的程序存储器容量是64K,一般我们写个简单的程序,可能就只占前面的很小一部分空间,剩下的大片空余空间可以加以利用,比如存储一些我们自定义的数据,这样就非常方便,而且可以充分利用盗源,不过这里要注意,我们在选取存储区域时,一定不要覆盖了原有的程序,要不然程序自己把自己给破坏了,之后程序就运行不了了,一般存储少量的数据,我们就选最后几页存储就行了
    • 通过在程序中编程(IAP),实现程序的自我更新
      • 我们在存储用户数据时要避开程序本身,以免破坏程序,但如果,我们就非要修改程序本身会发生什么呢?那这就是第二点提到的功能,在程序中编程,利用程序,来修改程序本身,实现程序的自我更新,这个在程序中编程,就是IAP
  • 在线编程(In-Circuit Programming-lCP)也可以叫在电路中编程,用于更新程序存储器的全部内容,它通过JTAG、SWD协议或系统加载程序(Bootloader)下载程序
    • 这个JTAG、SWD,就是仿真器下载程序,就是我们目前用的STLINK使用SWD下载程序,每次下载,都是把整个程序壳全更新掉,那系统加载程序,就是系统存储器的Bootloader,也就是串口下载,串口下载,也是更新整个程序,这就是我们一直在用的ICP下载方式,
  • 在程序中编程(In-Application Programming-IAP)可以使用微控制器支持的任一种通信接口下载程序
    • 怎么实现?那比如,这是整个程序存储器,我们首先需要自己写一个Bootloader程序,并且存放在程序更新时,不会覆盖的地方,比如我们放在这后面,然后,需要更新程序时,我们控制程序跳转到这个自己写的Bootloader里来,在这里面,我们就可以接收任意一种通信接口传过来的数据,比如串口、USB、蓝牙转串口、WIFI转串口等等,这个传过来的数据,就是待更新的程序,然后我们控制FLASH读写,把收到的程序,写入到前面,程序正常运行的地方,写完之后,再控制程序跳转回正常运行的地方或者直接复位,这样程序就完成了自我升级,这个过程其实就是和系统存储器这个的Bootloader-样,因为程序要实现自我升级,在升级过程中肯定需要布置一个辅助的小机器人来临时干活,只不过是系统存储器的Bootloader写死了,只能用串口下载到指定位置 ,启动方式也不方便,只能配置BOOT引脚触发启动,而我们自己写Bootloader的话,就可以想怎么收怎么收,想写到哪就写到哪,想怎么启动就怎么启动,并且这整个升级过程,程序都可以自主完成,实现在程序中编程,更进一步,就可以直接实现远程升级了,对吧,非常方便      

2.闪存模块组织

我们C8T6芯片的闪存容量是64K,属于中容量产,对于小容量产品和大容量产品,闪存的分配方式有些区别,可以参考手册

首先看一下第一列的几个块,这里分为了三个块,第一个是主存储器也就是我们刚才说的程序存储器,用来存放程序代码的,这是最主要,也是容量最大的一块,下面第二个,是信息块,里面又可以分为启动程序代码和用户选择字节,其中启动程序代码就是刚才说的系统存储器,存放的是原厂写入的Bootloader,用于串口下载,然后下面这个用户选择字节也就是刚才说的选项字节,存放一些独立的参数,这个选项字节,在手册里一直都称作选择字节,英文是Option Bytes,然后最后一块是闪存存储器接口寄存器,这一块的存储器,实际上并不属于闪存,你看它的地址就知道,地址都是40开头的,说明这个存储器接口寄存器就是一个普通的外设,和之前讲的GPIO、定时器、串口等等都是一个性质的东西,这些存储器,它们的存储介质,也都是SRAM,这个闪存存储器接口就是上面这些闪存的管理员,这些寄存器,就是用来控制擦除和编程这个过程的,只有程序存储器、系统存储器和选项字节才是真正的闪存

对于主存储器这里对它进行了分页,分页是为了更好地管理闪存,擦除和写保护,都是以而为单位的,这一点和之前W25Q64那一节的闪存一样,同为闪存,它们的特性基本一样,写入前必须擦除,擦除必须以最小单位进行,擦除后数据位全变为1,数据只能1写0,不能0写1,擦除和写入之后都需要等待忙,这些都是一样的,那W25064的分配方式是先分为块Block,再分为康区Sector比较复杂,这里,就比较简单了,它只有一个基本单位,就是页,每页的大小都是1K,0~127,总共128页,总容量就是128K,对于C8T6来说,它只有64K,所以C8T6的页只有一半,0~63,总共64页,共64K,然后看一下页的地址范围:第一个页的起始地址,就是程序存储器的起始地址,0x0800 0000,之后就是一个字节一个地址,依次线分配了,看一下每页起始地址的规律首先是0000然后0400、0300、0C00...到FC00,所以,地址只要以000、400、800、C00结尾的,都一定是页的起始地址,对吧

系统存储器,它的起始地址是0x1FFF F000,它的容量是2K,再下面,选项字节,起始地址是0X1FFF F800,容量是16个字节,里面只有几个字节的配置参数,我们平时说的,芯片闪存容量是64K、128K,它指的只是主存储器的容量,下面信息块的两个东西,虽然也是闪存,但是并不统计在这个容量里,这就是闪存的分配方式

那最后,就是这个闪存接口寄存器了,里面包括KEYR键寄存器、SR状态寄存器、CR控制寄存器等等,外设的起始地址是0x4002 2000,每个寄存器都是4个字节,也就是32位,这就是这个外设的寄存器

3.FLASH基本结构

整个闪存分为程序存储器、系统存储器和选项字节三部分,这里程序存储器我以C8T6为例,它是64K的共64页,最后一页的起始地址是0800 FC00,左边这里,是闪存存储器接口,手册里还有个名称闪存编程和擦除控制器(FPEC),然后,这个控制器,就是闪存的管理员,它可以对程序存储器进行擦除和编程,也可以对选项字节进行擦除和编程,当然系统存储器是不能擦除和编程的,之后选项字节,里面有很大一部分配置位,其实是配置主程序存储器的读写保护的,所以右边画的,写入选项字节,可以配置程序存储器的读写保护,当然选项字节还有几个别的配置参数

4.操作控制器FPEC

细节问题,如何操作这个控制器FPEC,来对程序存储器和选项字节进行擦除和编程,首先,第一步,是FLASH解锁,这个和之前W25Q64-样,W25064操作之前需要写使能,这个FLASH,操作之前需要解锁,目的,都是为了防止误操作,那这里,解锁的方式,和之前独立看门狗一样,都是通过在键寄存器写入指定的键值来实现,使用键寄存器的好处就是,更能防止误操作,每一个指令,必须输密码才能完成,,,,,,,,,,,,,,,,,,,,,

4.1FLASH解锁

5.使用指针访问存储器

因为STM32内部的存储器是直接挂在总线上的,所以这时,再读写某个存储器就非常简单了,直接使用C语言的指针,来访问即可,__IO对应C语言的关键字,volatile,volatile,直译就是,易变的数据,在这个数据类型前面加上volatile,是一个安全保障措施,用一句话来说,就是防止编译器优化,首先说一下,Keil编译器默认情况下是最低优化等级,这时,加不加这个volatile,都没有影响,如果,你要提高编译器优化等级,这时候就会有问题了,用途就是,可以去除无用的繁架代码,降低代码空间,提升运行效率,但优化之后,编译器在某些地方可能会弄巧成拙,比如,你想用变量计数空循环的方式实现延时函数,那编译器优化的时候,可能会说你这段延时函数好像没用啊还自白浪赛时间,我直接给你优化掉,这就弄巧成拙了,因为我们本意就是靠浪装时间来延时,这时,我们就可以在延时的变量定义前面加上volatile,告诉编译器我无论对这个变量干什么,你都原封不动地去执行,别给我优化掉了

另外,编译器还会利用缓存来加速代码,比如如果你要频繁读写内存的某个变量,那最常见的优化方式就是先把变量转移到高速缓存里来,在STM32内核里,有一个类似缓存的工作组寄存器,这些寄存器的访问速度最快,我先把变量放在缓存里,需要读写的时候,直接访问缓存就行了,用完之后,再写回内存,这是一个优化方案,但是,如果你的程序里有多个线程,比如中断函数,在中断函数里,你改变了这个原始变量,那可能缓存并不知道你更改了,下次程序还看缓存的变量,就会造成数据更改不同步的问题,这时,我们的做法也是,读取变量定义的前面加上一个volatile,告诉编译器这个变量是易变的,每次读取你都得执行到位,要直接从内存里找,不要再用缓存优化了,所以总结-下就是,如果开启了编译器优化,在无意义加减变量,多线程更改变量,读写与硬件相关的存储器时都需要加上volatile,防止被编译器优化,如果你默认,不开编译器优化,那就无所谓了,加不加都一样

其中,读取,可以直接读,写入,需要解锁,并且执行后面的流程
 

5.1 程序存储器全擦除

第 步是读取LOCK位,看一下芯片锁没锁,下面,如果LOCK位=1,锁住了,就执行解锁过程,在KEYR寄存器,先写入KEY1,再写入KEY2,这里,如果它当前没锁住就不用解锁了,在库函数中,并没有这个判断,库函数是直接执行解锁过程,解锁之后,首先,置控制寄存器里的MER(Mass Erase)位为1,然后再置STRT(Start)位为1,其中置STRT为1是触发条件,STRT为1之后,芯片开始干活,然后芯片看到,MER位是1,它就知道,接下来要干的活就是全擦除,这样内部电路就会自动执行全擦除的过程,然后继续擦除也是需要花一段时间的,所以擦除过程开始后程序要执行等待,判断状态寄存器的BSY(BuSy)位是否为1,BSY位表示芯片是否处于忙状态,BSY为1,表示芯片忙,所以这里,如果判断BSY=1,就跳转回来,继续循环判断,直到BSY=0,跳出循环,这样全擦除过程就结束了,最后一步,这里写的是读出并验证所有页的数据,读出并验证所有页的数据,这个是测试程序才要做的,正常情况下,全擦除完成了,我们默认就是成功了

5.2 程序存储器页擦除

第一步,上面这块一样的,是解锁的流程,第二步,这个方框里的置控制寄存器的PER(Page Erase) 位为1,然后,在AR(Address Register)地址寄存器中选择要擦除的页,最后,置控制寄存器的STRT位为1,置STRT为1,也是触发条件,STRT为1,芯片开始干活,然后芯片看到,PER=1,它就知道,接下来要执行页擦除,然后闪存不止一页,页擦除,芯片就要知道要具体要擦哪一页,所以,它会继续看AR寄存器的数据,AR寄存器我们要提前写入一个页起始地址,这样芯片就会把我们指定的一页,给擦除掉,然后擦除开始之后,我们也需要等待BSY位,最后,读出并验证数据,这个就不用看了,这就是页擦除的过程

5.3 程序存储器编程

擦除之后,我们就可以执行写入的流程了,另外说明一下,STM32的闪存在写入之前会检查指定地址有没有擦除,如果没有擦除就写入,STM32则不执行写入操作,除非写入的全是0,这一个数据是例外,因为不擦除就写入,可能会写入错误,但全写入0的话,写入肯定是没问题的,写入的第一步,也是解锁,然后第二步,我们需要置控制寄存器的PG(Programming)位为1,表示我们即将写入数据,之后第三步,就是在指定的地址写入半字,这步,我们需要用到刚才说的这句代码使用指针,在指定地址写入数据,想写入什么数据在这里指定即可,另外这里注意写入操作,只能以半字的新式写入,其中字,Word,就是32位数据,半字,HalfWord,就是16位数据,字节,Byte,就是8位数据,如果你要写入32位,就分两次完成,这个就比较麻烦了,如果你想单独写入一个字节,还要保留另一个字节的原始数据的话,那就只能把整页数据都读到SRAM,再随意修改SRAM数据,修改全部完成之后再把墪页都擦除,最后再把整页都写回去,所以,如果你想像SRAM一样随心所欲的读写,那最好的加法就是先把闪存的一页读到SRAM中,读写完成后,再擦除一页,整体写回去,那回到流程图这里,写入数据这个代码,就是触发开始的条件,不需要像擦除一样,置STRT位了,写入半字之后,芯片会处于忙状态,等待BSY位清0,这样写入数据的过程就完成了,那每执行这样一个流程,只能写入一个半字,如果要写入很多数据,那就不断循环调用这个流程,就可以了

6.选项字节

首先这里是选项字节的组织和用途,图里的起始地址就是我们刚才说的选项字节的起始地址1FFFF800,这一块的这些数据就是前面的用户选项字节,里面总共只有16个字节,其中有一半的名称,前面都带了个n,比如RDP和nRDP,这个意思就是你在写入RDP数据时,要同时在nRDP写入数据的反码,这样写入操作才是有效的,如果芯片检测到这两个存储器不是反码的关系,那就代表数据无效,有错误,对应的功能就不执行,这是一个安全保障措施,当然这个写入反码的过程,硬件会自动计算,并写入

1位保护4x8=32页,总共保护32*4=128页,正好对应中容量的最大128页       

7.器件电子签名

也就是每个芯片的身份证号,这个数据存放的基地址是1FFFF7E8,每一个芯片的这96位数据都是不一样的,使用这个唯一ID号可以做一些加密的操作,比如你想写入一段程序只能在指定设备运行,那就可以在程序的多处加入ID号判断,如果不是指定设备的ID号,就不执行程序功能,,这样即使你的程序被盗,在别的设备上也难以运行,这就是STM32的电子签名

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/56806.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Go语言Gin框架的常规配置和查询数据返回json示例

文章目录 路由文件分组查询数据库并返回jsonservice层controller路由运行效果 启动多个服务 在 上一篇文章《使用Go语言的gorm框架查询数据库并分页导出到Excel实例》 中主要给大家分享了较多数据的时候如何使用go分页导出多个Excel文件并合并的实现方案,这一篇文章…

2-127基于matlab的非圆齿轮啮合动画设计

基于matlab的非圆齿轮啮合动画设计,可根据需求设置齿数,齿高、平滑系数等,最后输出啮合动画。程序已调通,可直接运行。 下载源程序请点链接:2-127基于matlab的非圆齿轮啮合动画设计

day-13面向对象进阶

面向对象进阶部分学习方法: 特点: ​ 逻辑性没有那么强,但是概念会比较多。 ​ 记忆部分重要的概念,理解课堂上讲解的需要大家掌握的概念,多多练习代码。 day13 第一章 复习回顾 1.1 如何定义类 类的定义格式如…

探索Python配置新维度:Hydra库揭秘

文章目录 探索Python配置新维度:Hydra库揭秘背景:为何选择Hydra?初识Hydra安装Hydra简单的库函数使用方法基础配置覆盖配置组合配置多运行 场景应用数据库配置本地和远程运行多作业运行 常见Bug及解决方案配置加载失败命令行参数解析错误远程…

014_django基于大数据运城市二手房价数据可视化系统的设计与实现2024_3ahrxq75

目录 系统展示 开发背景 代码实现 项目案例 获取源码 博主介绍:CodeMentor毕业设计领航者、全网关注者30W群落,InfoQ特邀专栏作家、技术博客领航者、InfoQ新星培育计划导师、Web开发领域杰出贡献者,博客领航之星、开发者头条/腾讯云/AW…

测试右移实践的一些总结思考—稳定监控“及时雨”

随着项目开发的逐渐敏捷化,QA的职能早已不单单是曾经简单对功能的测试,在领域内测试左移和测试右移这两个概念被一再提及。 本文将分别从稳定发布、监控、风险控制三个方面,主要介绍一下目前测试右移概念在组内的落地应用、一些还没有落地的…

Wordpress GutenKit 插件 远程文件写入致RCE漏洞复现(CVE-2024-9234)

0x01 产品简介 GutenKit 是一个WordPress的页面构建器,在 Gutenberg 设计您的下一个 WordPress 网站。借助 Gutenberg 的原生拖放界面、50+ WordPress 块、14+ 多功能模块和 500+ 模板,您可以在几分钟内创建专业、响应迅速的 Web 内容。 0x02 漏洞概述 Wordpress GutenKit…

vue-router钩子中调用ElMessage等样式出错

升级 vue3.5 时遇到奇怪的问题, 页面点击离开没反应 经过排查, 是以下几点相互作用导致此问题 vue 有应用上下文的概念, 例如 runWithContext API,vue-router 在调用钩子时会获取 vue 的应用上下文element-plus 在唤起弹窗时会从 parent 或 应用上下文上拿到 config 信息eleme…

OpenCV高级图形用户界面(20)更改窗口的标题函数setWindowTitle()的使用

操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在OpenCV中,cv::setWindowTitle函数用于更改窗口的标题。这使得您可以在程序运行时动态地更改窗口的标题文本。 函数原型 void cv::…

浏览器实时更新esp32-c3 Supermini http server 数据

一利用此程序的思路就可以用浏览器显示esp32 采集的各种传感器的数据,也可以去控制各种传感器。省去编写针对各系统的app. 图片 1.浏览器每隔1秒更新一次数据 2.现在更新的是开机数据,运用此程序,可以实时显示各种传感器的实时数据 3.es…

【计算机网络 - 基础问题】每日 3 题(四十七)

✍个人博客:https://blog.csdn.net/Newin2020?typeblog 📣专栏地址:http://t.csdnimg.cn/fYaBd 📚专栏简介:在这个专栏中,我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话,欢迎点赞…

Cesium 实战 - 自定义纹理材质 - 立体墙(旋转材质)

Cesium 实战 - 自定义纹理材质 - 立体墙(旋转材质) 核心代码完整代码在线示例Cesium 给实体对象(Entity)提供了很多实用的样式,基本满足普通项目需求; 但是作为 WebGL 引擎,肯定不够丰富,尤其是动态效果样式。 对于实体对象(Entity),可以通过自定义材质,实现各种…

YOLOv11来了 | 自定义目标检测

概述 YOLO11 在 2024 年 9 月 27 日的 YOLO Vision 2024 活动中宣布:https://www.youtube.com/watch?vrfI5vOo3-_A。 YOLO11 是 Ultralytics YOLO 系列的最新版本,结合了尖端的准确性、速度和效率,用于目标检测、分割、分类、定向边界框和…

esp32-c3 Supermini 驱动ds3121的问题

c3 驱动ds3121 ,始终有问题,但把程序用esp32上,一点问题都没有,难道c3 的i2c库是另外的库, 下图只读取秒显示的 错误数据,更换了scl频率,针脚,还是错,但换成esp32 输出是正确连续秒…

字节跳动实习生投毒自家大模型细节曝光 影响到底有多大?

10月19日,字节跳动大模型训练遭实习生攻击一事引发广泛关注。据多位知情人士透露,字节跳动某技术团队在今年6月遭遇了一起内部技术袭击事件,一名实习生因对团队资源分配不满,使用攻击代码破坏了团队的模型训练任务。 据悉&#xf…

鸿蒙开发 四十七 Promise async await

1、Promise是接口 鸿蒙sdk提供的ProPromise版本有点多,是泛型接口,用interface修饰,官网给出的解释是“Represents the completion of an asynchronous operation”,翻译大概意思是:异步操作的完成的处理,总…

全球知名度最高的华人改名大师颜廷利:世界公认的三大哲学家思想家

颜廷利教授,一位享誉全球的思想巨擘与现代国学泰斗,以其卓越的哲学地位和深远的影响力,成为当代思想界的璀璨明星。他的哲学思想深邃而广博,不仅涵盖了人的全面发展、自然社会的深度融合,更在教育理念上独树一帜&#…

2.2机器学习--逻辑回归(分类)

目录 1.算法介绍 2.算法原理 3. API 介绍 4.代码示例 本章节我们来学习线性分类问题,在有监督学习中,最主要的两种学习任务是 回归(regression) 和 分类(classification),而其中线性回归和线…

JR_T0213—2021 金融网络安全 Web应用服务安全测试通用规范.pdf

预览 内容太多,自己下载看吧 https://www.mhtsec.com/667/

精选20个爆火的Python实战项目(含源码),直接拿走不谢!

今天给大家介绍20个非常实用的Python项目,帮助大家更好的学习Python。 完整版Python项目源码,【点击这里】领取! ① 猜字游戏 import random def guess_word_game(): words ["apple", "banana", "cherry&quo…