LV16-27-内部Flash-02-Flash操作过程
本文主要是STM32开发——内部FLASH基本操作的一些相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。
点击查看使用工具及版本
Windows | windows11 |
Ubuntu | Ubuntu16.04的64位版本 |
VMware® Workstation 16 Pro | 16.2.3 build-19376536 |
SecureCRT | Version 8.7.2 (x64 build 2214) - 正式版-2020年5月14日 |
开发板 | 正点原子 i.MX6ULL Linux阿尔法开发板 |
uboot | NXP官方提供的uboot,NXP提供的版本为uboot-imx-rel_imx_4.1.15_2.1.0_ga(使用的uboot版本为U-Boot 2016.03) |
linux内核 | linux-4.15(NXP官方提供) |
STM32开发板 | 正点原子战舰V3(STM32F103ZET6) |
点击查看本文参考资料
- 通用
分类 | 网址 | 说明 |
官方网站 | https://www.arm.com/ | ARM官方网站,在这里我们可以找到Cotex-Mx以及ARMVx的一些文档 |
https://www.st.com/content/st_com/zh.html | ST官方网站,在这里我们可以找到STM32的相关文档 | |
https://www.stmcu.com.cn/ | 意法半导体ST中文官方网站,在这里我们可以找到STM32的相关中文参考文档 | |
http://elm-chan.org/fsw/ff/00index_e.html | FatFs文件系统官网 | |
教程书籍 | 《ARM Cortex-M3权威指南》 | ARM公司专家Joseph Yiu(姚文祥)的力作,中文翻译是NXP的宋岩 |
《ARM Cortex-M0权威指南》 | ||
《ARM Cortex-M3与Cortex-M4权威指南》 | ||
开发论坛 | http://47.111.11.73/forum.php | 开源电子网,正点原子的资料下载及问题讨论论坛 |
https://www.firebbs.cn/forum.php | 国内Kinetis开发板-野火/秉火(刘火良)主持的论坛,现也做STM32和i.MX RT | |
https://www.amobbs.com/index.php | 阿莫(莫进明)主持的论坛,号称国内最早最火的电子论坛,以交流Atmel AVR系列单片机起家,现已拓展到嵌入式全平台,其STM32系列帖子有70W+。 | |
http://download.100ask.net/index.html | 韦东山嵌入式资料中心,有些STM32和linux的相关资料也可以来这里找。 | |
博客参考 | http://www.openedv.com/ | 开源网-原子哥个人博客 |
http://blog.chinaaet.com/jihceng0622 | 博主是原Freescale现NXP的现场应用工程师 | |
cortex-m-resources | 这其实并不算是一个博客,这是ARM公司专家Joseph Yiu收集整理的所有对开发者有用的官方Cortex-M资料链接(也包含极少数外部资源链接) |
- STM32
STM32 | STM32 HAL库开发实战指南——基于F103系列开发板 | 野火STM32开发教程在线文档 |
STM32库开发实战指南——基于野火霸道开发板 | 野火STM32开发教程在线文档 |
- SD卡
SD Association | 提供了SD存储卡和SDIO卡系统规范 |
点击查看相关文件下载
STM32F103xx英文数据手册 | STM32F103xC/D/E系列的英文数据手册 |
STM32F103xx中文数据手册 | STM32F103xC/D/E系列的中文数据手册 |
STM32F10xxx英文参考手册(RM0008) | STM32F10xxx系列的英文参考手册 |
STM32F10xxx中文参考手册(RM0008) | STM32F10xxx系列的中文参考手册 |
Arm Cortex-M3 处理器技术参考手册-英文版 | Cortex-M3技术参考手册-英文版 |
STM32F10xxx Cortex-M3编程手册-英文版(PM0056) | STM32F10xxx/20xxx/21xxx/L1xxxx系列Cortex-M3编程手册-英文版 |
SD卡相关资料——最新版本 | 有关SD卡的一些资料可以从这里下载 |
SD卡相关资料——历史版本 | 有关SD卡的一些历史版本资料可以从这里下载,比如后边看的SD卡2.0协议 |
SD 2.0 协议标准完整版 | 这是一篇关于SD卡2.0协议的中文文档,还是比较有参考价值的,可以一看 |
我这里使用的是STM32CubeMX来配置生成工程,使用的就是HAL库,由于内部Flash不需要我们来做初始化,所以软件不用配置,我们直接调用相应的驱动函数即可。这些可以操作内部Flash的函数声明都存在于 以下几个文件中:
1 | stm32f1xx_hal_flash_ex.h |
关于Flash的相关资料,ST官方有另外的文档,叫做STM32F10xxx闪存编程手册,英文版在这里:STM32F10xxx Flash memory microcontrollers,这个手册也有中文版,但是只有本地可看:STM32F10xxx闪存编程参考手册
一、对内部Flash的读写过程
1. 解锁
1.1 解锁步骤
由于内部 FLASH 空间主要存储的是应用程序,是非常关键的数据,为了防止误操作修改了这些内容,芯片复位后默认会给控制寄存器 FLASH_CR 上锁,这个时候不允许设置 FLASH 的控制寄存器,从而不能修改 FLASH 中的内容。 我们可以参考STM32F10xxx闪存编程参考手册的2.3.2 解除闪存锁。所以对 FLASH 写入数据前,需要先给它解锁,也就是通过写入特定的序列到 FLASH_KEYR 寄存器可以打开 FPEC 模块(即写入 KEY1 和 KEY2)。解锁的操作步骤如下 :
(1) 往 FPEC 键寄存器 FLASH_KEYR 中写入 KEY1 = 0x45670123
(2) 再往 FPEC 键寄存器 FLASH_KEYR 中写入 KEY2 = 0xCDEF89AB
只有在写保护被解除后,我们才能操作相关寄存器,这 叫Unlock。需要注意的是键值不正确会产生总线错误。
1.2 解锁函数
1 | /** |
2. 上锁
2.1 上锁步骤
当我们操作完成后,我们还可以将内部FLASH上锁,我们向FLASH的CR寄存器的LOCK位写1即可完成上锁。
2.2 上锁函数
1 | /** |
3. 页擦除
3.1 页擦除步骤
在写入新的数据前,需要先擦除存储区域, STM32 提供了页(扇区)擦除指令和整个 FLASH 擦除 (批量擦除) 的指令,批量擦除指令仅针对主存储区。我们可以看一下STM32F10xxx闪存编程参考手册的2.3.4 闪存擦除一节,这里有一个流程图:
(1)检查FLASH_CR的LOCK是否解锁,如果没有则先解锁
(2)检查 FLASH_SR 寄存器中的“忙碌寄存器位 BSY”,也就是 bit[0],以确认当前未执行任何 Flash 操作;
(3)在 FLASH_CR 寄存器中,将“激活页擦除寄存器位PER ”置 1,也就是将bit[1]置 1 ;
(4)用FLASH_AR寄存器选择要擦除的页(该寄存器表示了要操作的地址,也叫闪存地址寄存器);
(5)将 FLASH_CR 寄存器中的“开始擦除寄存器位 STRT ”置 1,也就是将 bit[6] 置 1 ,然后就会开始擦除;
(6)等待 BSY 位被清零时,表示擦除完成。
(7)读出被擦除的页并做验证。
3.2 页擦除函数
1 | /** |
本函数包含两个输入参数,分别是擦除flash初始化结构体和返回擦除出错编码,FLASH_EraseInitTypeDef 擦除 flash 初始化结构体主要包含擦除的方式,是扇区擦除还是批量擦除,选择不同电压时实质是选择不同的数据操作位数,并且确定擦除首地址即擦除的扇区个数。函数根据输入参数配置 PSIZE 位,然后擦除扇区,擦除扇区的时候需要等待一段时间,它使用 FLASH_WaitForLastOperation 等待,擦除完成的时候才会退出 HAL_FLASHEx_Erase 函数。
4. 写入数据
4.1 写入步骤
擦除完毕后即可写入数据,写入数据的过程并不是仅仅使用指针向地址赋值,赋值前还还需要配置一系列的寄存器, 我们可以参考STM32F10xxx闪存编程参考手册的2.3.3 主闪存编程一节:
对主闪存编程每次可以写入16位。当FLASH_CR寄存器的PG位为’1’时,在一个闪存地址写入 一个半字将启动一次编程;写入任何非半字的数据,FPEC都会产生总线错误。在编程过程中 (BSY位为’1’),任何读写闪存的操作都会使CPU暂停,直到此次闪存编程结束。
(1)检查FLASH_CR的LOCK是否解锁,如果没有则先解锁。
(2)检查FLASH_SR寄存器的BSY位,以确认没有其他正在进行的编程操作。
(3)设置FLASH_CR寄存器的PG位为 1 在指定的地址写入要编程的半字,也就是每次只能以 16 位(32位处理器下,一个字是32位,半字就是16位,也就是2个字节)的方式写入。
(4)等待BSY位变为 0 。
(5)读出写入的地址并验证数据。
4.2 写入函数
1 | /** |
形参依次设置了数据操作宽度,写入数据地址,写入的数据。在赋值操作后,调用了 FLASH_WaitForLastOperation 函数等待写操作完毕。
5. 读取数据
5.1 读取步骤
读取数据就比较简单了,我们直接定义一个指针,指针指向想要读的地址,就可以直接读取了。
5.2 读取函数
在HAL库或者标准库中是没有提供读内部Flash数据的函数的,我们可以自己封装一个.
- 读取半字数据(16位)
1 | uint16_t internalFLASH_ReadHalfWord(uint32_t faddr) |
6. 读写实例
具体的可以看feat:读写内部Flash测试(MDK工程) · 944a6a2 · sumumm/STM32F103-Prj - Gitee.com
6.1 相关宏定义
1 | // 用户根据自己的需要设置 |
6.2 读取半字数据
1 | /** |
6.3 不检查擦除的写入
1 | /** |
6.4 写入指定半字数的数据
1 |
|
6.5 读取指定半字数的数据
1 | /** |
6.6 测试函数
1 | void internalFlash_Test(void) |
二、内部Flash的读写保护
1. 库函数说明
1.1 选项字节上锁、解锁
1 | /** |
解锁的时候,它对 FLASH_OPTCR 寄存器写入两个解锁参数,上锁的时候,对 FLASH_OPTCR 寄存器的 FLASH_OPTCR_OPTLOCK 位置 1。
1.2 设置选项字节函数
解锁后设置选项字节寄存器可以先初始化 FLASH_OBProgramInitTypeDef 结构体,然后调用 HAL_FLASHEx_OBProgram 完成。
1 | /** |
该函数根据输入选项字节结构体 FLASH_OBProgramInitTypeDef 参数设置寄存器响应的位,特别注意,其注释警告了若 RDPLevel 位配置成 OB_RDP_LEVEL_2 会无法恢复。
1.3 写入选项字节
1 | /** |
该函数设置 FLASH_OPTCR_OPTSTRT 位后调用了 FLASH_WaitForLastOperation 函数等待写入完成,并返回写入状态,若操作正常,它会返回 FLASH_COMPLETE。
2. 读写保护测试
这里就没实际操作了,后边有需要再补充吧。