当前位置: 首页 > news >正文

【STM32 学习笔记】FLASH闪存

FLASH闪存

介绍

在这里插入图片描述
读写FLASH的用途:

  • 存储用户数据:
    在C8T6芯片中,可以利用程序存储器的剩余空间来保存掉电不丢失的用户数据。选择存储区域时,应避免覆盖原有程序代码

对于我们这个C8T6芯片来说,它的程序存储器容量是64K,一般我们写个简单的程序,可能就只占前面的很小一部分空间,剩下的大片空余空间我们就可以加以利用,比如存储一些我们自定义的数据,这样就非常方便,而且可以充分利用资源,不过这里要注意我们在选取存储区域时,一定不要覆盖了原有的程序,要不然程序自己把自己给破坏了,一般存储少量的参数,我们就选最后几页存储就行了

  • 程序自我更新(IAP):
    通过在应用程序中编程,可以实现程序的自我更新。这涉及到编写一个BOOTLOADER程序,并将其存放在程序更新时不会覆盖的地方。

闪存模块组织

对于小容量产品和大容量产品,闪存的分配方式有些区别,这个可以参考一下手册,那首先提醒一下闪存这一章的内容在手册里是单独列出来的,并不在之前的参考手册里,我们需要打开这个闪存编程参考手册,这里以中容量产品为例来讲解。
在这里插入图片描述
在这里插入图片描述在闪存编程参考手册中,我们可以看到C8T6的闪存分为三个主要部分:主存储器、信息块和闪存存储器接口寄存器。

  1. 主存储器:这是闪存中容量最大的部分,用于存放程序代码。主存储器被划分为多个页,每页大小为1K。C8T6共有64页。
  2. 信息块:这部分包含系统存储器和用户选择字节(也称为选项字节)。系统存储器的起始地址是0x1FFFF000,容量为2K,用于存放原厂写入的BOOTLOADER,以便通过串口下载。用户选择字节的起始地址是0x1FFFF800,容量为16字节,用于存储配置参数。需要注意的是,虽然系统存储器和用户选择字节属于闪存的一部分,但它们通常不计入我们常说的64K或128K闪存容量中
  3. 闪存存储器接口寄存器:这些寄存器不属于闪存本身,而是作为外设存在,其地址以0x4002开头,表明它们是普通的外设寄存器,类似于GPIO、定时器、串口等。这些寄存器包括KEYR、SR、CR等,用于控制闪存的擦除和编程过程。

对于主存储器,这里对它进行了分页,分页是为了更好的管理闪存,擦除和写保护都是以页为单位的,这点和之前W25Q64芯片的闪存一样,同为闪存它们的特性基本一样,写入前必须擦除,擦除必须以最小单位进行,擦除后数据位全变为1,数据只能1写0,不能0写1,擦除和写入之后都需要等待忙,这些都是一样的,学习这节之前,大家可以再复习一下W25Q64,再学这一节就会非常轻松了,那W25Q64的分配方式是先分为块block,再分为扇区sector比较复杂,这里就比较简单了,它只有一个基本单位就是页,每一页的大小都是1K,0到127总共128页,总量就是128K,对于C8T6来说,它只有64K,所以C8T6的页只有一半0~63总共64页共64K,

FLASH基本结构

在这里插入图片描述
接下来理一下这个基本结构图,整个闪存分为程序存储器系统存储器选项字节三部分,这里程序存储器为以C8T6为例,它是64K的,所以总共只有64页,最后一页的起始地址是0800FC00;左边这里是闪存存储器接口(闪存编程和擦除控制器LPEC),然后这个控制器就是闪存的管理员,他可以对程序存储器进行擦除和编程,也可以对选项字节进行擦除和编程,系统存储器是不能擦除和编程的,这个选项字节里面有很大一部分配置位,其实是配置主程序存储器的读写保护的,所以右边画的写入选项字节,可以配置程序存储器的读写保护,当然选项字节还有几个别的配置参数,这个待会再讲,那这就是整个闪存的基本结构。

FLASH解锁

在这里插入图片描述
解锁过程

  1. 复位后保护状态:在微控制器复位后,FPEC(Flash Programming and Erase Controller)默认是被保护的,此时不能写入FLASH_CR(Flash Control Register)。
  2. 写入解锁键值:要解锁FPEC,需要按照正确的顺序在FLASH_KEYR(Flash Key Register)中写入特定的键值。
    • KEY1:首先写入0x45670123。
    • KEY2:然后写入0xCDEF89AB。
  3. 安全性设计:这种两步解锁过程提高了安全性,因为需要连续写入两个正确的键值才能解锁。这减少了因程序异常而意外解锁的风险。
  4. 错误操作保护:如果解锁序列错误,比如没有按照先KEY1后KEY2的顺序写入,FPEC和FLASH_CR将会在下次复位前被锁死,防止了进一步的误操作。

加锁过程

  1. 操作完成后加锁:在完成所有必要的闪存操作后,为了防止意外写入,需要重新锁定FPEC。
  2. 设置LOCK位:通过在FLASH_CR寄存器中设置LOCK位来重新锁定FPEC。通常,向LOCK位写入1即可完成加锁操作。

注意事项
解锁和加锁操作都需要谨慎进行,以确保系统的稳定性和安全性。
在进行任何解锁操作之前,确保理解了相关寄存器的功能和操作步骤,以避免不必要的风险。

接着看下一个知识点,这个地方我们要学习的是,如何使用指针访问存储器,因为STM32内部的存储器是直接挂在总线上的,所以这时在读写某个存储器就非常简单了,直接使用C语言的指针来访问即可。

使用指针访问存储器

在这里插入图片描述
讲解为什么会用到volatile

如果你这个地址写的是SRAM的地址,比如0X20000000,那可以直接写入了,因为SRAM在程序运行时是可读可写的,这是使用指针访问存储器的C语言代码,0X08000000,其中读取可以直接读,写入需要解锁,并且执行后面的流程。

程序存储器全擦除

下面我们来详细审视以下三个流程图的内容。首先是编程流程,亦即数据写入过程。其次是页擦除流程,值得注意的是,在STM32的闪存操作中,写入数据前需进行擦除操作。完成擦除后,该页的所有数据位将统一变为1,页擦除的操作单元是1K,即1024字节。最后是全擦除流程,这一过程涉及对所有页面的擦除。关于这些流程的细节,库函数已经为我们封装好了相应的操作,我们只需调用一个总函数即可,操作便捷

在这里插入图片描述

  1. 检查锁状态:首先,读取芯片的LOCK位,以确定芯片是否处于锁定状态。若LOCK位为1,表明芯片已被锁定,此时需要执行解锁操作。
  2. 解锁操作(如果需要):
    如果芯片锁定(LOCK位等于1),则需在KEYR寄存器中依次写入KEY1和KEY2以执行解锁。这一步骤在流程图中有所体现,即锁定了才需要解锁。
    若芯片未锁定,则无需执行解锁操作。然而,库函数的设计是直接执行解锁过程,不考虑芯片是否实际锁定。这种方法虽然简单直接,但最终效果是相同的。
  3. 启动全擦除:
    将控制寄存器中的MER(Mass Erase)位置1,以指示全擦除操作。
    接着,将STRT(Start)位置1。STRT位为1时,将触发芯片开始执行操作。当芯片检测到MER位为1时,它会识别接下来的操作是全擦除,并自动执行全擦除流程。
  4. 等待擦除完成:
    全擦除操作需要一定时间,因此程序需等待擦除过程结束。这通过检查状态寄存器的BSY(Busy)位来实现。
    如果BSY位为1,表示芯片正忙于擦除操作,程序将继续循环检查,直到BSY位变为0,表明擦除操作完成。
  5. 验证擦除结果(可选):
    流程的最后一步是读取并验证所有页的数据。这一步骤通常用于测试程序,以确保擦除操作的成功。
    在正常操作中,全擦除完成后,我们可以默认操作成功。由于全读出并验证所有页的数据工作量巨大,因此在实际应用中,这一步骤通常可以省略。
程序存储器页擦除

在这里插入图片描述
接下来,我们来看看页擦除的过程,这一过程与全擦除类似,包含以下步骤:

  1. 解锁操作:首先执行与全擦除相同的解锁流程。如果芯片处于锁定状态,需要在KEYR寄存器中依次写入KEY1和KEY2来解锁。
  2. 设置页擦除模式:
    将控制寄存器中的PER(Page Erase)位置1,指示接下来要执行的是页擦除操作。
    在AR(Address Register)地址寄存器中写入要擦除的页的起始地址。这一步是必要的,因为闪存包含多个页,而页擦除操作需要明确指出具体要擦除哪一页。
  3. 启动擦除操作:
    将控制寄存器的STRT(Start)位置1,这是触发条件,告诉芯片开始执行擦除操作。
    当芯片检测到PER位为1时,它会识别接下来的操作是页擦除,并且会参考AR寄存器中的地址来确定要擦除的具体页。
  4. 等待擦除完成:
    擦除操作开始后,程序需要等待操作完成。这同样是通过检查状态寄存器的BSY(Busy)位来实现的。
    如果BSY位为1,表示芯片正在执行擦除操作,程序将持续检查,直到BSY位变为0,表明擦除操作已经完成。
  5. 验证擦除结果(可选):
    最后一步是读取并验证擦除页的数据。这一步骤在测试程序中可能需要执行,以确保擦除操作的成功。
    在实际应用中,由于验证所有数据的工作量较大,通常可以省略这一步骤,假设擦除操作已经成功完成。

总结来说,页擦除过程包括解锁、设置擦除模式、启动擦除、等待操作完成,以及可选的数据验证步骤。通过这些步骤,我们可以确保指定的页被正确擦除。

程序存储器编程

在这里插入图片描述

最后,我们来探讨闪存的写入流程。在擦除操作之后,我们就可以进行数据写入。以下是写入流程的详细步骤:

  1. 解锁操作:与擦除操作类似,写入流程的第一步是对闪存进行解锁,确保可以执行写入操作。
  2. 设置编程模式:
    将控制寄存器中的PG(Programming)位置1,这表示即将进行数据写入操作。
  3. 写入数据:
    在指定的地址写入半字(16位数据)。这一步骤通过指针操作实现,可以直接在指定的内存地址写入想要的数据。
    需要注意的是,STM32的闪存写入操作仅支持半字写入。在STM32中,数据单位有字(32位)、半字(16位)和字节(8位)。因此,写入时必须以半字为单位,即每次写入16位数据。如果需要写入32位数据,则需要分两次写入;而写入8位数据时,则需要额外的处理。

处理字节写入:
如果需要单独写入一个字节且保留另一个字节的原始数据,必须将整页数据读取到SRAM中,修改SRAM中的数据,然后擦除整页闪存,并将修改后的整页数据写回。这种方法虽然繁琐,但能实现类似SRAM的灵活读写。

  1. 触发写入操作:
    写入数据后,芯片将自动进入忙状态,开始执行写入操作。与擦除操作不同,写入操作不需要显式设置STRT位,写入半字即可触发。
    等待写入完成:
    写入过程中,程序需要等待状态寄存器的BSY(Busy)位清0,这表示写入操作已经完成。
  2. 重复写入流程:
    每次执行上述流程,只能写入一个半字。若需要写入大量数据,则需要循环调用写入流程,直到所有数据写入完成。

总结来说,闪存的写入流程包括解锁、设置编程模式、写入数据、等待写入完成,并根据需要重复写入流程以写入多个数据。STM32的闪存写入有一定的限制,需要按照半字单位进行,并且在特定情况下需要采取额外的步骤来保证数据的正确写入。

选项字节

现在,让我们进一步了解选项字节的相关内容。对此有一个基本的认识就足够了。首先,我们要关注的是选项字节的结构和它们的作用。
在这里插入图片描述
在图表中,可以看到选项字节的起始地址,即我们之前提到的0x1FFF8000。这一区域包含的数据,正如表格所示,总共只有16个字节。这些字节在图中被详细展示,它们中的每一个都有一个对应的名称。值得注意的是,其中一半的名称带有“N”前缀,例如RDP和nRDP,USER和nUSER。这表示在写入数据到RDP等存储器时,必须同时在对应的nRDP存储器中写入数据的反码。这样的操作确保了写入的有效性。如果芯片检测到这些存储器中的数据不是反码关系,那么数据将被视为无效,相关的功能也不会被执行。这是一种安全特性,旨在防止错误操作。幸运的是,硬件会自动处理反码的写入过程,因此在使用库函数时,我们只需直接调用相应的函数即可,无需手动干预。

接下来看看这些存储器的具体功能。排除带有“N”前缀的字节后,我们剩下八个字节存储器。首先是RDP(读保护配置位),通过向RDP存储器写入特定的RDPRT键(例如0xA5),可以解除读保护。如果RDP不包含0xA5,则闪存将处于读保护状态,防止调试器读取程序代码,从而保护代码不被未授权访问。第二个字节是USER,它包含了一些零碎的配置位,可以用来配置硬件看门狗以及停机待机模式是否产生复位等。

接着是Data0/1这两个字节,它们在芯片中没有预设功能,用户可以根据自己的需求进行自定义。最后四个字节,WRP0/1/2/3,用于配置写保护。在中容量产品中,每个位对应保护四个存储页,总共32位,可以保护128页,这与中容量产品的最大页数相匹配。

对于小容量和大容量产品,写保护配置有所不同。根据手册中的2.5节,小容量产品每个位同样对应保护四个存储页,但由于其最大容量只有32K,因此只需使用一个字节WRP0,即8位,足以保护32页。其他三个字节WRP1、WRP2、WRP3在此不被使用。而对于大容量产品,每个位仅能保护两个存储页,因此四个字节不足以覆盖所有页。为此,规定WRP3的最高位用于保护剩余的所有页,从而确保了写保护功能的完整性。

然后看一下如何去写入这些位呢,这里两页PPT展示的就是选项字节的擦除和编程,因为选项字节本身也是闪存,所以它也得擦除,这里参考手册并没有给流程图,我们看一下这个文字流程,这个文字流程和流程图细节上有些出入,我们知道关键部分就行。
在这里插入图片描述
首先,我们来探讨选项字节的擦除流程。虽然第一步在文字描述中未明确提及,但实际上,它同样是解锁闪存。接着,我们看到文字版流程中包含了额外的步骤,即检查状态寄存器(SR)的BSY位,以确保没有其他闪存操作正在进行。这一步骤实际上是一个预先等待的过程:如果检测到BSY位为忙状态,我们需要等待直到操作完成。这一步骤在先前的流程图中并未展示。

下一步是解锁控制寄存器(CR)的OPTWRE(Option Write Enable)位,这是专门针对选项字节的解锁操作。在解锁整个闪存之后,我们还需要单独解锁选项字节,才能对其进行操作。关于解锁选项字节,我们可以参考之前的寄存器组织图。整个闪存的解锁是通过KEYR寄存器完成的,而选项字节的小锁则是通过OPTKEYR(Option Key Register)寄存器来解锁。解锁这个小锁的流程如下:首先在OPTKEYR中写入KEY1,然后写入KEY2,这样就可以成功解锁选项字节。

解锁选项字节的小锁之后,接下来的步骤与之前的擦除操作类似。首先,我们需要将CR的OPTER(Option Erase)位置1,这表示我们准备擦除选项字节。然后,设置CR的STRT位为1,这一操作将触发芯片开始擦除选项字节的过程。在设置STRT位后,我们等待BUSY位变为0,这表明擦除选项字节的过程已经完成。一旦擦除操作完成,我们就可以进行后续的写入操作了。

在这里插入图片描述
和普通的闪存写入也差不多,先检测BSY,然后解除小锁,之后设置CR的OPTPG(Option Programming)位为1,表示即将写入选项字节,再之后写入要编程的半字到指定的地址,这个是指针写入操作,最后等待忙,这样写入选项字节就完成了。
在这里插入图片描述
最后我们花几分钟学一下器件电子签名,这个非常简单,既然讲到闪存了,就顺便学习一下吧
看一下电子签名存放在闪存存储器模块的系统存储区域,包含的芯片识别信息在出厂时编写不可更改,使用指针读指定地址下的存储器,可获取电子签名,电子签名其实就是STM32的id号,它的存放区域是系统存储器,它不仅有BOOTLOADER程序,还有几个字节的id号,系统存储器起始地址是1FFFF000,看下这里,这里有两段数据,第一个是闪存容量存储器,基地址是1FFF F7E0,通过地址也可以确定它的位置,就是系统存储器,这个存储器的大小是16位,它的值就是闪存的容量单位是KB,然后第二个是产品唯一身份标识寄存器,就是每个芯片的身份证号,这个数据存放的基地址是1FFFF7E8,大小是96位,每一个芯片的这96位数据都是不一样的,使用这个唯一id号可以做一些加密的操作,比如你想写入一段程序,只能在指定设备运行,那也可以在程序的多处加入id号判断,如果不是指定设备的id号,就不执行程序功能,这样即使你的程序被盗,在别的设备上也难以运行,这是STM32的电子签名。

代码实战:读写内部FLASH&读取芯片 ID

建议观看视频:15-2 读写内部FLASH&读取芯片 ID
在这里插入图片描述

  • 读写内部FLASH
    在这里插入图片描述

  • 读取芯片 ID
    在这里插入图片描述

http://www.dtcms.com/a/273008.html

相关文章:

  • pytorch学习-12循环神经网络(基础篇)
  • 机器视觉之激光码检测系统
  • 【世纪龙科技】学测-汽车信息化综合实训考核平台(机电方向)
  • 数字孪生系统如何助力汽车零部件企业实现虚拟智控
  • RedisJSON 内存占用剖析与调优
  • Lua嵌入式爬虫实现步骤
  • 【Linux系统】冯诺依曼体系结构 | 初识操作系统
  • 生产者、消费者问题(C语言、POSIX)
  • 测试覆盖标准-条件覆盖-短路求值
  • 全新开源AI知识库系统!PandaWiki一键构建智能文档,支持AI问答、创作与搜索!
  • [特殊字符] 05_Jenkins 部署前端项目实现自动化部署
  • rv1106使用笔记
  • 【RL-VLM-F】算法框架图绘图学习笔记
  • ubuntu server配置静态IP
  • ​​​​​​​微软PowerBI PL-300认证考试报名入口及费用
  • 【PTA数据结构 | C语言版】顺序队列的3个操作
  • 完美卸载 Ubuntu 双系统:从规划到实施的完整指南
  • 乐鑫代理商飞睿科技,ESP32模组重塑AIoT体验的四大技术支柱
  • C++类型萃取(Type Traits):深入解析std::enable_if与std::is_same
  • git fetch的使用
  • 【第五章-基础】Python 函数---以一个初学者来理解函数
  • 第十六天,7月10日,八股
  • 【网络安全】利用 Cookie Sandwich 窃取 HttpOnly Cookie
  • vue中token的使用与统计实践
  • android闪光灯源码分析
  • Android 插件化实现原理详解
  • 【读书笔记】如何画好架构图:架构思维的三大底层逻辑
  • 遥感影像图像分割-地物提取模型训练与大图直接推理流程
  • 突破传统局限:60G 3D毫米波雷达如何实现精准人体全状态检测?
  • Vue3基础知识