STM32(二十五)读写内部flash
一、内部flash简介
- 在 STM32 芯片内部有一个 FLASH 存储器,它主要用于存储代码 。
- 我们在电脑上编写好应用程序后,使用下载器把编译后的代码文件烧录到该内部 FLASH 中 。
- FLASH 存储器的内容在掉电后不会丢失,芯片重新上电复位后,内核可从内部 FLASH 中加载代码并运行。
- 访问内部flash的速度比外部的SPI-Flash要快。
- flash擦除时是按扇区擦除,使用电擦除,设备电压1.8V ~2.1V按字节(8bit)擦除,2.1V ~2.7V擦除半字(16bit),2.7V ~ 3.6V擦除一个字(32bit)
2.7V to 3.6V +外部电压擦除两个字(64bit),
二、内部flash的构成
STM32 的内部 FLASH 包含主存储器、系统存储器以及选项字节区域,它们的地址分布及大小见下表。
1、主存储器
- 一般我们说STM32内部FLASH的时候,都是指这个主存储器区域,它是存储用户应用程序的空间,芯片型号说明中的256K FLASH、512K FLASH都是指这个区域的大小。
- 主存储器分为256页,每须大小为2KB,共512KB。这个分页的概念,实质就是FLASH存储器的扇区,与其它FLASH - -样,在写入数据前,要先按页(扇区)擦除。
2、系统存储区
系统存储区是用户不能访问的区域,它在芯片出厂时已经固化了启动代码,它负责实现串口、 USB 以及 CAN 等 ISP 烧录功能。
3、选项字节
选项字节用于配置 FLASH 的读写保护、待机/停机复位、软件/硬件看门狗等功能,这部分共 16 字节。可以通过修改 FLASH 的选项控制寄存器修改。
三、对内部flash的写入过程
1.解锁
由于内部FLASH空间主要存储的是应用程序,是非常关键的数据,为了防止误操作修改了这些内容,芯片复位后默认会给控制寄存器FLASH _CR上锁,这个时候不允许设置FLASH的控制寄存器,从而不能修改FLASH中的内容。所以对FLASH写入数据前,需要先给它解锁。解锁的操作步骤如下:
(1) 往FPEC键寄存器FLASH_ KEYR中写入KEY1 = 0x45670123
(2)再往FPEC键寄存器FLASH_ KEYR中写入KEY2 = 0xCDEF89AB
2.页擦除.
在写入新的数据前,需要先擦除存储区域,STM32提供了页(扇区)擦除指令和整个FLASH擦除(批量擦除)的指令,批量擦除指令仅针对主存储区。页擦除的过程如下:
(1) 检查FLASH_ SR寄存器中的“忙碌寄存器位BSY”,以确认当前未执行任何Flash操作;
(2)在FLASH_ CR寄存器中,将“激活页擦除寄存器位PER”置1。
(3)用FLASHAR寄存器选择要擦除的页;
(4) 将FLASH _CR寄存器中的“开始擦除寄存器位STRT"置1,开始擦除;
(5)等待BSY位被清零时,表示擦除完成。
3.写入数据
擦除完毕后即可写入数据,写入数据的过程并不是仅仅使用指针向地址赋值,赋值前还还需要配置一-系列的寄存器,步骤如下:
(1) 检查FLASH_ SR中的BSY位,以确认当前未执行任何其它的内部Flash操作;
(2) 将FLASH_ CR寄存器中的“激活编程寄存器位PG”置1;
(3)向指定的FLASH存储器地址执行数据写入操作,每次只能以16位的方式写入;
(4)等待 BSY位被清零时,表示写入完成。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | /** * @brief InternalFlash_Test,对内部FLASH进行读写测试 * @param None * @retval None */ int InternalFlash_Test( void ) { uint32_t EraseCounter = 0x00; //记录要擦除多少页 uint32_t Address = 0x00; //记录写入的地址 uint32_t Data = 0x3210ABCD; //记录写入的数据 uint32_t NbrOfPage = 0x00; //记录写入多少页 FLASH_Status FLASHStatus = FLASH_COMPLETE; //记录每次擦除的结果 TestStatus MemoryProgramStatus = PASSED; //记录整个测试结果 /* 解锁 */ FLASH_Unlock(); /* 计算要擦除多少页 */ NbrOfPage = (WRITE_END_ADDR - WRITE_START_ADDR) / FLASH_PAGE_SIZE; /* 清空所有标志位 */ FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR); /* 按页擦除*/ for (EraseCounter = 0; (EraseCounter < NbrOfPage) && (FLASHStatus == FLASH_COMPLETE); EraseCounter++) { FLASHStatus = FLASH_ErasePage(WRITE_START_ADDR + (FLASH_PAGE_SIZE * EraseCounter)); } /* 向内部FLASH写入数据 */ Address = WRITE_START_ADDR; while ((Address < WRITE_END_ADDR) && (FLASHStatus == FLASH_COMPLETE)) { FLASHStatus = FLASH_ProgramWord(Address, Data); Address = Address + 4; } FLASH_Lock(); /* 检查写入的数据是否正确 */ Address = WRITE_START_ADDR; while ((Address < WRITE_END_ADDR) && (MemoryProgramStatus != FAILED)) { if ((*(__IO uint32_t*) Address) != Data) { MemoryProgramStatus = FAILED; } Address += 4; } return MemoryProgramStatus; } |
思考题1:flash擦除完之后,扇区里面所有的数据是什么?
思考题2:假如说现在已经擦除完扇区,先写入了1个字,然后在下一个偏移地址再次写入新的字是否在需要擦除扇区?
思考题3:假如说现在已经擦除完扇区,先写了1个字,然后在同一个地址再次写入新的字是否需要擦除扇区?
总结:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)