哪个网站查公司信息比较准,订货网站建设,google doc wordpress,网络实施方案怎么写FLASH闪存
程序现象#xff1a; 1、读写内部FLASH 这个代码的目的#xff0c;就是利用内部flash程序存储器的剩余空间#xff0c;来存储一些掉电不丢失的参数。所以这里的程序是按下K1变换一下测试数据#xff0c;然后存储到内部FLASH#xff0c;按下K2把所有参数清0 1、读写内部FLASH 这个代码的目的就是利用内部flash程序存储器的剩余空间来存储一些掉电不丢失的参数。所以这里的程序是按下K1变换一下测试数据然后存储到内部FLASH按下K2把所有参数清0最后OIED显示一下。 这里OLED显示Flag、Data 。Flag当做标志位内容定义为A5A5。Flag作用判断之前是不是存储过数据如果存储过直接读取如没有存储过就先初始化。 Data是要掉电存储的数据。 2读取芯片ID 在stm32里指定地址下存储有原厂写入的ID号使用指针的方式读取就可以得到ID号。 OLED可以看到有2个ID号第一个是F_SIZE表示芯片FLASH容量。0040表示FLASH容量单位是KB换成十进制是64KB。 第二个是U_ID是96位芯片唯一ID号每个芯片ID号都不一样。
STM32内部FLASH闪存简介 读写FLASH的用途 利用程序存储器的剩余空间来保存掉电不丢失的用户数据 通过在程序中编程IAP实现程序的自我更新 第一个用途对于我们这个C8T6芯片来说它的程序存储器容量是64K一般我们写个简单的程序可能就只占前面的很小一部分空间剩下的大片空余空间我们就可以加以利用比如存储一些我们自定义的数据而且可以充分利用资源。不过这里要注意我们在选取存储区域时一定不要覆盖了原有的程序要不然程序自己把自己给破坏了一般存储少量的参数我们就选最后几页存储就行了、 第二个用途通过在程序中编程IAP实现程序的自我更新。我们在存储用户数据时要避开程序本身以免破坏程序但如果我们就非要修改程序本身这会发生什么呢在程序中编程利用程序来修改程序本身实现程序的自我更新这个在程序中编程就是IAP是用来实现程序升级的。
在线编程 ICP这个JTAG SWD就是仿真器下载程序每次下载都是把整个程序完全更新掉那系统加载程序就是系统存储器的BOOTLOADER也就是串口下载串口下载也是更新整个程序这就是我们一直在用的ICP下载方式。 在程序中编程 IAP它可以使用微控制器支持的任意一种通信接口下载程序。实现过程 比如这是整个程序存储器我们首先需要自己写一个BOOTLOADER程序并且存放在程序更新时不会覆盖的地方然后需要更新程序时我们控制程序跳转到这BOOTLOADER这里来在这里面我们就可以接收任意一种通讯接口传过来的数据比如串口、USB、蓝牙转串口、WIFI转串口等等这个传过来的数据就是待更新的程序然后我们控制flash读写把收到的程序写入到前面程序正常运行的地方写完之后再控制程序跳转回正常运行的地方或者直接复位这样程序就完成了自我升级。
区别IAP就是和系统存储器这个的BOOTLOADER一样。系统存储器的BOOTLOADER只能配置boot引脚触发启动。而我们自己写BOOTLOADER的话就可以想怎么收怎么收并且在整个升级过程程序都可以自主完成。
回顾一下存储器影像 闪存模块组织 C8T6芯片的闪存容量是64K属于中容量产品。 这里分为了三个块第一个是主存储器也是程序存储器用来存放程序代码的这是最主要也是容量最大的一块。 第二个是信息块里面又可以分为启动程序代码和用户选择字节其中启动程序代码就是系统存储器存放的是原厂写入BOOTLOADER用于串口下载。 第三块是闪存存储器接口寄存器这一块的存储器实际上并不属于闪存地址都是40开头的说明这个存储器接口寄存器就是一个普通的外设和之前讲的GPIO定时器、串口等等都是一个性质的东西这些存储器它们的存储介质也都是SRAM。 这个闪存存储器接口寄存器就上面主存储器和信息块的管理员闪存存储器接口寄存器就是用来控制擦除和编程这个过程的。 对于主存储器这里对它进行了分页分页是为了更好的管理闪存擦除和写保护都是以页为单位的。这点和之前W25Q64芯片的闪存一样写入前必须擦除擦除必须以最小单位进行擦除后数据位全变为1数据只能1写0不能0写1擦除和写入之后都需要等待忙这些都是一样的。 这里就比较简单了它只有一个基本单位就是页每一页的大小都是1K0到127总共128页总量就是128K对于C8T6来说它只有64K所以C8T6的页只有一半0~63总共64页共64K然后看一下页的地址范围。 所以地址只要以000、400、800、400结尾的都一定是页的起始地址。
FLASH基本结构 整个闪存分为程序存储器、系统存储器和选项字节三部分这里程序存储器为以C8T6为例它是64K的所以总共只有64页最后一页的起始地址是0800FC00。 左边这里是闪存存储器接口手册里还有个名称闪存编程和擦除控制器LPEC。 然后闪存存储器接口可以对程序存储器进行擦除和编程也可以对选项字节进行擦除和编程系统存储器是不能擦除和编程的。 这个选项字节里面有很大一部分配置位其实是配置主程序存储器的读写保护的所以右边画的写入选项字节可以配置程序存储器的读写保护。
如何操作这个控制器FPEC来对程序存储器和选项字节进行擦除和编程。
FLASH解锁 首先第一步是flash解锁这个flash操作之前需要解锁目的都是为了防止误操作是通过在键寄存器写入指定的键值来实现使用键寄存容器的好处就是更能防止误操作每一个指令必须输密码才能完成叫密钥寄存器。 首先FPEC共有三个键值也就是三把开锁的钥匙RDPRT键是解除读保护的密钥值是0XA5这些值呢实际上是随便定义的只要你定义的不是很简单就行。 解锁第一个是复位后FPEC被保护不能写入FLASH_CR也就是复位后flash默认是锁着的。 在FLASH_KEYR键寄存器中先写入KEY1再写入KEY2解锁这个锁是KEYR寄存器所以这个有两道锁解锁的话要先用K1钥匙解再用K2钥匙解最终才能解锁成功所以非人为情况下基本不可能解锁。 然后就是错误的操作序列会在下次复位前锁死FPEC和FLASH_CR于是他发现有程序在尝试撬锁时一旦没有先写入KEY1再写入KEY2整个模块就会完全锁死除非复位这是整个解锁操作。 加锁我们操作完成之后要尽快把flash重新加锁以防止意外情况加锁的操作是设置FLASH_CR中的LOCK位锁住FPEC和FLASH_CR就是控制寄存器里面有个LOCK位我们在这一位写1就能重新锁住闪存。
使用指针访问存储器 uint16_t Data *((__IO uint16_t *)(0x08000000));第一步读取给定存储器器的地址比如0x08000000例读取这个地址下的数据。
第二步在地址前面加上强制类型转换转换成uint16_t * 。__IO 在stm32库函数中这是宏定义。 #define __IO volatile这个宏定义对应C语言关键字 volatile。在uint16_t *数据类型前加volatile起一个保障作用目的是防止编译器优化。
第三步使用*号指针取内容把这个指针指向的存储器取出来了这个值就是指定存储器的值取出来可以把它赋值给自定义变量Data这样就完成指定地址读的任务。
如果你这个地址写的是SRAM的地址比如0X20000000那可以直接写入了因为SRAM在程序运行时是可读可写的这是使用指针访问存储器的C语言代码。其中读取可以直接读写入需要解锁并且执行后面的流程。
程序存储器全擦除 第一步是读取lock位看一下芯片锁没锁如果lock位1锁住了就执行解锁过程解锁过程就是在KEYR寄存器先写入KEY1再写入KEY2如果lock位0当前没锁住就不用解锁了。这是流程图里给的解锁步骤如果锁住了就解锁如果没锁住就不用解锁。但是在库函数中并没有这个判断库函数是直接执行解锁过程管你锁没锁都执行解锁。
第二步然后继续解锁之后首先置控制寄存器里的MER(Mass Erase)位为1然后再置STRT(Start)位为1其中STRT为1是触发条件STRT为1之后芯片开始干活然后现在看到MER位是1它就知道接下来要干的活就是全擦除这样内部电路就会自动执行全擦除的过程。
第三步然后继续擦除擦除过程开始后程序要执行等待判断状态寄存器的BSY(Busy)位是否为1BSY位表示芯片是否处于忙状态BSY位为1表示芯片忙所以这里如果判断BSY位等于1就跳转回来继续循环判断直到BSY位0跳出循环。
第四步读出并验证所有页的数据这个是测试程序才要做的如要全读出来验证一下这个工作量太大了所以这里的最后一步就不管了正常情况下全删除完成了我们默认就成功了这是全擦除的流程。
程序存储器页擦除 第一步是解锁的流程。
第二步这个方框里的置控寄存器的PER(Page Erase)位为1在AR(Address Register)地址寄存器中选择要擦除的页最后置控制寄存器的STRT位为1置STRT位为1也是触发条件芯片开始干活然后芯片看到PER等于1它就知道接下来要执行页擦除。 然后闪存不止一页页擦除芯片就要知道要具体擦哪一页所以它会继续看AR寄存器的数据AR寄存器我们要提前写入一个页的起始地址这样芯片就会把我们指定的一页给擦除掉。
第三步然后擦除开始之后我们也要等待BSY位最后读出并验证数据。
程序存储器编程
闪存的写入
闪存的写入擦除之后我们就可以执行写入的流程了另外说明一下STM32的闪存在写入之前会检查指定地址有没有擦除如果没有擦除就写入STM32则不执行写入操作除非写入的全是0这个数据是例外因为不擦除就写入可能会写入错误。
第一步是解锁。
第二步置控制寄存器的PG(Programming)位为1表示我们即将写入数据。
第三步在指定的地址写入半字这一步我们需要*((__IO uint16_t *)(0x08000000)) 0x1234;使用指针在指定地址写入数据。 注意写入操作只能以半字的形式写入在STM32中有几个术语字、半字和字节其中字word就是32位数据半字half word就是16位数据字节byte就是8位数据。那这里只能以半字写入意思就是只能以16位的形式写入一次性写入两个字节如果你要写入32位就分两次完成。 如果你只要写入8位比较麻烦了如果你想单独写入一个字节还要保留另一个字节的原始数据的话那只能把整页数据都读到SRAM再随意修改SRAM数据修改全部完成之后再把整页都擦除最后再把整页都写回去。 所以如果你想像SRAM一样随心所欲的读写那最好的办法就先把闪存的一页读到SRAM中读写完成后再擦除一页整体写回去。
第四步写了半字之后芯片会处于忙状态我们等待一下BUSY清0这样写入数据的过程就完成。那每执行这样一个流程只能写入一个半字如果要写出很多数据要不断循环调用这个流程就可以。
选项字节 图里的起始地址就是选项字节的起始地址1FFF800这块的这些数据就前面这里这个表的这一行里面总共只有16个字节把这些存储器给展开就这个图。 这里是对应的16个字节其中有一半的名称前面都带了个N比如RDP和nRDP USER和nUSER等意思是你在写入RDP数据时要同时在NRDP写入数据的反码要在带N的对应的存储器写入反码这样写入操作才是有效的。 如果芯片检测到这两个存储器不是反码的关系那就代表数据无效有错误对应的功能就不执行这是一个安全保障措施。但这个写入反码的过程硬件会自动计算并写入。
那然后每个存储器的功能去掉所有带n的剩下八个字节存储器 第一个RDP(Read Protect)是读保护配置位解释在RDP存储器写入RDPRT键然后解除读保护如果RDP不是A5那闪存就是读保护状态无法通过调试器读取程序避免程序被别人窃取。 第二个字节USER可以配置硬件看门狗和进入停机待机模式是否产生复位。 第三个和第四个字节Data0/1这个在芯片中没有定义功能用户可自定义使用。 最后四个字节WRP(WriteProtect)0、1、2、3这四个字节配置的是写保护在中容量产品里是每一个位对应保护四个存储页四个字节总共32位一位对应保护四页总共保护32×4等于128页正好对应中容量量的最大128页。
小容量产品 手册2.5选项字节说明 对于小容量产品也是每一位对应保护四个存储页但小容量产品最大只有32K所以只需要一个字节WRP0就行4×832其他三个字节没用到。
大容量产品 然而对于大容量产品每一个位只能保护两个存储页这样的话四个字节就不够用了所以这里规定WRP3的最高位这一位直接把剩下的所有页一起都保护了这是写保护的定义。
选项字节擦除 选项字节擦除 第一步其实也是解锁闪存这里文字并没有写。
第二步这里文字版的流程多了一步检查SR的BSY位以确认没有其他正在进行的闪存操作这个实际上就是事前等待如果当前已经在忙了我先等一下。
第三步解锁CR的OPTWRE(Option Write Enable)位这一步是选项字节的解锁选项字节里面还有一个单独的锁在解锁闪存后还需要再解锁选项字节的锁之后才能操作选项字节。
解锁选项字节看(前面闪存模块组织图)整个闪存的锁是KEYR里面选项字节的小锁是下面的OPTKEYR(Option Key Register)解锁这个小锁也是类似的流程我们需要在OPTKEYR里先写入KEY1再写入KEY2这样就能解锁选项字节的小锁了。
第四步继续解除小锁之后设置CR的OPTER(Option Erase)位为1表示即将擦除选项字节。
第五步设置CR的STRT位为1触发芯片开始干活这样芯片就会启动擦除选项字节的工作。
第六步之后等待BUSY位变为0擦除选项字节就完成了。
选项字节编程 先检测BSY 然后解除小锁 之后设置CR的OPTPG(Option Programming)位为1表示即将写入选项字节 再之后写入要编程的半字到指定的地址这个是指针写入操作 最后等待忙这样写入选项字节就完成了。
器件电子签名 电子签名其实就是STM32的ID号它的存放区域是系统存储器它不仅有BOOTLOADER程序还有几个字节的ID号系统存储器起始地址是1FFFF000。 第一个是闪存容量存储器基地址是1FFF F7E0通过地址也可以确定它的位置就是系统存储器这个存储器的大小是16位它的值就是闪存的容量单位是KB。 第二个是产品唯一身份标识寄存器就是每个芯片的身份证号这个数据存放的基地址是1FFFF7E8大小是96位每一个芯片的这96位数据都是不一样的。 使用这个唯一ID号可以做一些加密的操作比如你想写入一段程序只能在指定设备运行那也可以在程序的多处加入ID号判断如果不是指定设备的ID号就不执行程序功能。这样即使你的程序被盗在别的设备上也难以运行这是STM32的电子签名。
闪存编程手册 在编程过程中任何读写闪存的操作都会使CPU暂停直到此闪存编程结束。
这是读写内部闪存存储数据的一个弊端忙的时候代码执行会暂停因为执行代码需要读闪存闪存在忙没法读所以CPU也就没法运行了程序就会暂停。这会导致假如你使用内部闪存存储数据同时你的中断代码又在频繁执行这样读写闪存的时候中断代码就无法执行了这可能会导致中断无法及时响应。
选项字节编程
闪存控制寄存器FLASH_CR