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的电子签名

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

联系拯救者Y9000P2022笔记本电脑进入BIOS快捷键

联系拯救者Y9000P2022笔记本电脑进入BIOS快捷键 文章目录 联系拯救者Y9000P2022笔记本电脑进入BIOS快捷键1. 进入BIOS快捷键2. 快速进入BIOS设置界面3. 快速进入启动项选择界面 1. 进入BIOS快捷键 进入BIOS设置界面的快捷键为F2快速进入启动项选择界面的快捷键为F12 2. 快速进…

充电桩高压快充发展趋势

一、为什么要升级充电电压 1、新能源发展的困境 随着电动汽车加快发展,用户对电动汽车接受度不断提高,充电问题是影响电动车普及的重要因素,用户快速补能的需求强烈,例如节假日经常会遇到,高速充电1小时,…

jmeter中设置属性值的注意事项

jmeter中,可以在beanshell sampler, jsr223 sampler中对变量、属性等做一些操作,使得测试脚本变得更有关联性和一致性,以便完成更好的测试工作。 但是,在实际运用中,设置属性值经常会有些情况需要注意。不是我们以为的…

全能PDF工具集 | PDF Shaper Ultimate v14.6 便携版

软件简介 PDF Shaper是一款功能强大的PDF工具集,它提供了一系列用于处理PDF文档的工具。这款软件使用户能够轻松地转换、分割、合并、提取页面以及旋转和加密PDF文件。PDF Shaper的界面简洁直观,使得即使是新手用户也能快速上手。它支持广泛的功能&…

智能体网络时代即将来临,我们需要新的连接技术

备注:如果你也对这个话题感兴趣,欢迎联系我们: email: chgaoweigmail.com Discord: https://discord.gg/CDYdTPXXMB 官网: https://pi-unlimited.com 我们的方案代码已经开源,github:https://github.com/chgaowei/…

鸿蒙开发 四十四 ArkTs BuilderParam传递UI(二)

子组件多个BuilderParam,必须通过参数的方式传入,如果界面中有多个界面需要传递,可以定义多个尾随闭包,如图: 在自定义组件中调用: 在使用时候调用是作为参数传递给自定义的组件,参数是界面&…

KUKA外部自动配置(上)

通过外部PLC对机器人自动运行进程进行控制,其控制原理是:外部PLC通过外部自动运行接口向机器人控制系统发出机器人进程的相关信号(如:运行许可、故障确认、程序启动等),机器人控制系统向外部PLC系统发送有关…

探索YOLO v11:3D人工智能的RGB-D视觉革命

哈喽,各位OAK中国的朋友们! 大家好我是张伯生 今天,我想给大家演示一下最新发布的Yolo V11神经网络 下面我将演示的一个程序是:同时在我们的OAK相机上跑Yolo V11和RGB-D,也就是彩色相机和深度图的一个叠加的一个效果 RGB-D和Yo…

uniapp uni.uploadFile errMsg: “uploadFile:fail

uniapp 上传后一直显示加载中 1.检查前后端上传有无问题 2.检查失败信息 await uni.uploadFile({url,filePath,name,formData,header,timeout: 30000000, // 自定义上传超时时间fail: async function(err) {$util.hideAll()// 失败// err 返回 {errMsg: "uploadFile:fai…

【中国象棋】unity中国象棋自我对弈

中国象棋 一级目录二级目录三级目录 棋类游戏的难度等级自我对弈代码游戏管理器棋子和格子棋子移动类棋子规则类检测将军类悔棋UI类 一级目录 二级目录 三级目录 棋类游戏的难度等级 1、跳棋、五子棋:一星 2、中国象棋、国际象棋:三星 3、围棋&#…

分享一套SpringBoot+Vue民宿(预约)系统

大家好,我是java1234_小锋老师,看到一个不错的SpringBootVue民宿(预约)系统,分享下嘿嘿。 项目介绍 传统办法管理信息首先需要花费的时间比较多,其次数据出错率比较高,而且对错误的数据进行更改也比较困难&#xff0c…

如何使用Jconsole查看进程里面的多线程的情况

1.代码分析 下面的这个就是使用的我们的start创建新的线程,然后让两个线程交叉运行(这个其实是通过我们的结果打印看出来的),我们可以看到这个hello main和这个hello thread是交叉显示打印输出的; 2.JDK软件包 因为上…

IP地理位置定位系统之应用场景划分

IP地理位置定位系统是一个街道级别的、实时的IP地理位置查询系统。该系统采用超高精度IP实时定位技术,通过网络测量和大数据挖掘,对IP的地理位置和相关属性进行测量,在无需硬件支持的条件下,即可对被探测目标终端IP完成定位。 应…

二叉树刷题(JAVA)

引入: 递归是一种在函数定义中使用函数自身的方法。它是一种常见的编程技巧,用于解决可以被分解为相同问题的子问题的问题。 递归函数通常包含两个部分:基本情况和递归情况。 基本情况是指递归函数停止调用自身的条件。当满足基本情况时&a…

流体力学笔记

目录 1、名词2、湍流与涡流3 涡激振动4 压力面与吸力面参考:[空气动力学的“他山之石”](https://zhuanlan.zhihu.com/p/412542513) 1、名词 转列:transition 涡脱落:vortex shedding 涡分离:vortex rupture 气动噪声&#xff1a…

代码训练营 day39|0-1背包问题,LeetCode 416

前言 这里记录一下陈菜菜的刷题记录,主要应对25秋招、春招 个人背景 211CS本CUHK计算机相关硕,一年车企软件开发经验 代码能力:有待提高 常用语言:C 系列文章目录 第九章 动态规划part03 文章目录 前言系列文章目录第九章 动态…

GDAL+C#实现矢量多边形转栅格

1. 开发环境测试 参考C#配置GDAL环境,确保GDAL能使用,步骤简述如下: 创建.NET Framework 4.7.2的控制台应用 注意: 项目路径中不要有中文,否则可能报错:can not find proj.db 在NuGet中安装GDAL 3.9.1和G…

达梦数据库性能优化

1、SQL执行计划 拿到一条SQL的时候,首先要下达梦手册中提出的有效SQL规范,及是否命中了特殊OR子句的不规范,是否用了复杂的正则表达式,避免重复很高的索引,UINON ALL 是否可以替换UNION操作等,某些场景INSTR函数导致的…

ParallelsDesktop20最新版本虚拟机 一键切换系统 游戏娱乐两不误

让工作生活更高效:Parallels Desktop 20最新版本虚拟机的神奇之处 大家好!👋 今天我要跟大家安利一款让我工作效率飞升的神器——Parallels Desktop 20最新版本虚拟机。作为一个日常需要在不同操作系统间来回穿梭的人,这款软件简直…

【升华】python基础包NumPy学习

NumPy是使用Python进行科学计算的基础软件包。除其他外,它包括: 功能强大的N维数组对象。精密广播功能函数。集成 C/C和Fortran 代码的工具。强大的线性代数、傅立叶变换和随机数功能。 # 1、安装包 $ pip install numpy# 2、进入python的交互式界面 $…