完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
扫一扫,分享给好友
1024G 嵌入式资源大放送!包括但不限于C/C++、单片机、Linux等。关注微信公众号【嵌入式大杂烩】,回复1024,即可免费获取!本次分享关于STM32内部FLASH的笔记。 STM32 芯片内部的 FLASH 存储器,主要用于存储我们代码。如果内部FLASH存储完我们的代码还有剩余的空间,那么这些剩余的空间我们就可以利用起来,存储一些需要掉电保存的数据。 本文以STM32103ZET6为例。STM32103ZET6属于大容量产品,其闪存模块组织如下: 其主存储器大小为512KB,分为256页,每页大小都为2KB。我们的程序一般默认烧写到第0页的起始地址(0x08000000)处。当BOOT0引脚和BOOT1引脚都接GND时,就是从这个地址开始运行代码的。这个地址在keil中可以看到: 假如我们要下载的程序大小为4.05KB,则第0、1、2页用于保存我们的程序,我们需要掉电保存的数据只能保存在第3页至第255页这一部分空间内。我们最终要下载的程序大小可在工程对应的.map文件中看到。.map文件可以双击工程的Target的名字快速打开,如: 下面对STM32的内部FLASH进行简单的读写测试: STM32的内部FLASH读写测试 过程图如下(省略异常情况,只考虑成功的情况): 示例代码: 本例的关键代码如下: /******************************************************************************************************* *------------------------------------------STM32 Demo--------------------------------------------------- * * 工程说明:STM32内部FLASH实验 * 作 者:ZhengNian * 博 客:zhengnianli.github.io * 公 众 号:嵌入式大杂烩 * ********************************************************************************************************/ #define MAIN_CONFIG #include "config.h" /* STM32F103ZET6有256页,每一页的大小都为2KB */ #define ADDR_FLASH_PAGE_255 ((uint32_t)0x0807F800) /* Page255 2KB */ /* FLASH读写测试结果 */ #define TEST_ERROR -1 /* 错误(擦除、写入错误) */ #define TEST_SUCCESS 0 /* 成功 */ #define TEST_FAILED 1 /* 失败 */ /* Flash读写测试buf */ #define BufferSize 6 uint16_t usFlashWriteBuf[BufferSize] = {0x0101,0x0202,0x0303,0x0404,0x0505,0x0606}; uint16_t usFlashReadBuf[BufferSize] = {0}; /* 供本文件调用的函数声明 */ static int FlashReadWriteTest(void); /******************************************************************************************************* ** 函数: main **------------------------------------------------------------------------------------------------------ ** 参数: void ** 返回: 无 ** 说明: 主函数 ********************************************************************************************************/ int main(void) { /* 上电初始化 */ SysInit(); /* 内部Flash读写测试 */ if (TEST_SUCCESS == FlashReadWriteTest()) { printf("Flash test success!n"); } else { printf("Flash test failed!n"); } while (1) {} } /******************************************************************************************************* ** 函数: FlashReadWriteTest, 内部Flash读写测试函数 **------------------------------------------------------------------------------------------------------ ** 参数: void ** 返回: TEST_ERROR:错误(擦除、写入错误) TEST_SUCCESS:成功 TEST_FAILED:失败 ** 说明: 无 ********************************************************************************************************/ static int FlashReadWriteTest(void) { uint32_t ucStartAddr; /* 解锁 */ FLASH_Unlock(); /* 擦除操作 */ ucStartAddr = ADDR_FLASH_PAGE_255; if (FLASH_COMPLETE != FLASH_ErasePage(ucStartAddr)) { printf("Erase Error!n"); return TEST_ERROR; } else { ucStartAddr = ADDR_FLASH_PAGE_255; printf("擦除成功,此时FLASH中值为:n"); for (int i = 0; i < BufferSize; i++) { usFlashReadBuf = *(uint32_t*)ucStartAddr; printf("ucFlashReadBuf[%d] = 0x%.4xn", i, usFlashReadBuf); ucStartAddr += 2; } } /* 写入操作 */ ucStartAddr = ADDR_FLASH_PAGE_255; printf("n往FLASH中写入的数据为:n"); for (int i = 0; i < BufferSize; i++) { if (FLASH_COMPLETE != FLASH_ProgramHalfWord(ucStartAddr, usFlashWriteBuf)) { printf("Write Error!n"); return TEST_ERROR; } printf("ucFlashWriteBuf[%d] = 0x%.4xn", i, usFlashWriteBuf); ucStartAddr += 2; } /* 上锁 */ FLASH_Lock(); /* 读取操作 */ ucStartAddr = ADDR_FLASH_PAGE_255; printf("n从FLASH中读出的数据为:n"); for (int i = 0; i < BufferSize; i++) { usFlashReadBuf = *(__IO uint16_t*)ucStartAddr; printf("ucFlashReadBuf[%d] = 0x%.4xn", i, usFlashReadBuf); ucStartAddr += 2; } /* 读出的数据与写入的数据做比较 */ for (int i = 0; i < BufferSize; i++) { if (usFlashReadBuf != usFlashWriteBuf) { return TEST_FAILED; } } return TEST_SUCCESS; } /********************************************************************************************************* ** End Of File ********************************************************************************************************/ (1)进行解锁操作 STM32 的闪存编程是由内嵌的闪存编程/擦除控制器(FPEC)管理 ,这个模块包含的寄存器如下: STM32 复位后, FPEC 模块是被保护的, 不能写入 FLASH_CR 寄存器; 通过写入特定的序列到 FLASH_KEYR 寄存器可以打开 FPEC 模块(即写入 KEY1 和KEY2) , 只有在写保护被解除后, 我们才能操作相关寄存器。 固件库中的函数为: void FLASH_Unlock(void); (2)擦除将要写的页 STM32 的 FLASH 在编程的时候,也必须要求其写入地址的 FLASH 是被擦除了的(也就是其值必须是 0XFFFF),否则无法写入,在 FLASH_SR 寄存器的 PGERR 位将得到一个警告。 STM32 的闪存擦除分为两种:页擦除和整片擦除。 也就是其最小擦除单位为1页,尽管你只需往某页里写10个字节数据或者更少的数据,你也必须先擦除该页(2*1024个字节)。我们这里使用按页擦除,固件库中按页擦除的函数为: FLASH_Status FLASH_ErasePage(uint32_t Page_Address); 其返回值为枚举: typedef enum { FLASH_BUSY = 1, /* 忙 */ FLASH_ERROR_PG, /* 编程错误 */ FLASH_ERROR_WRP, /* 写保护错误 */ FLASH_COMPLETE, /* 操作完成 */ FLASH_TIMEOUT /* 操作超时 */ }FLASH_Status; (3)往上一步擦写成功的页写入数据 STM32 闪存的编程每次必须写入16 位。虽然固件库中有如下三个写操作的函数: FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data); FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data); FLASH_Status FLASH_ProgramOptionByteData(uint32_t Address, uint8_t Data); 分别为按字(32bit)写入、按半字(16bit)写入、按字节(8bit)写入函数。32 位字节写入实际上是写入的两次 16 位数据,写完第一次后地址+2,这与我们前面讲解的 STM32 闪存的编程每次必须写入 16 位并不矛盾。 写入 8 位实际也是占用的两个地址了,跟写入 16 位基本上没啥区别。 (4)写入操作完成后进行上锁操作 对FLASH进行写操作完成后要进行上锁操作,对应的固件库中函数为: void FLASH_Lock(void); 1 (5)读出数据 固件库中并没有与读操作的函数。读操作其实就是读取FLASH某个地址的数据。 (6)对比写入的数据与读出的数据是否相等 最后对比我们写入的数据与读出的数据是否完全一致,若一致则表明读写测试成功,否则失败。 程序执行结果: 可见,读出的数据与写入的数据一致,表明读写测试成功。 最后 STM32的内部FLASH读写步骤大致如上,有时候我们还需要封装一些读写函数,但步骤大都如上。写入数据之前需要先进行擦除操作。以上就是本次的笔记分享,如有错误,欢迎指出! |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1632 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1559 浏览 1 评论
985 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
688 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1605 浏览 2 评论
1869浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
655浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
525浏览 3评论
540浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
512浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-25 21:08 , Processed in 0.819386 second(s), Total 78, Slave 61 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号