stm32flash取数据_STM32学习笔记:读写内部Flash(介绍+附代码)
一、介绍
首先我们需要了解一个内存映射:
stm32的flash地址起始于0x0800 0000,结束地址是0x0800 0000加上芯片实际的flash大小,不同的芯片flash大小不同。
RAM起始地址是0x2000 0000,结束地址是0x2000 0000加上芯片的RAM大小。不同的芯片RAM也不同。
Flash中的内容一般用来存储代码和一些定义为const的数据,断电不丢失,
RAM可以理解为内存,用来存储代码运行时的数据,变量等等。掉电数据丢失。
STM32将外设等都映射为地址的形式,对地址的操作就是对外设的操作。
stm32的外设地址从0x4000 0000开始,可以看到在库文件中,是通过基于0x4000 0000地址的偏移量来操作寄存器以及外设的。
一般情况下,程序文件是从 0x0800 0000 地址写入,这个是STM32开始执行的地方,0x0800 0004是STM32的中断向量表的起始地址。
在使用keil进行编写程序时,其编程地址的设置一般是这样的:
程序的写入地址从0x08000000(数好零的个数)开始的,其大小为0x80000也就是512K的空间,换句话说就是告诉编译器flash的空间是从0x08000000-0x08080000,RAM的地址从0x20000000开始,大小为0x10000也就是64K的RAM。这与STM32的内存地址映射关系是对应的。
M3复位后,从0x08000004取出复位中断的地址,并且跳转到复位中断程序,中断执行完之后会跳到我们的main函数,main函数里边一般是一个死循环,进去后就不会再退出,当有中断发生的时候,M3将PC指针强制跳转回中断向量表,然后根据中断源进入对应的中断函数,执行完中断函数之后,再次返回main函数中。大致的流程就是这样。
1.1、内部Flash的构成:
STM32F429 的内部 FLASH 包含主存储器、系统存储器、 OTP 区域以及选项字节区域,它们的地址分布及大小如下:
STM32F103的中容量内部 FLASH 包含主存储器、系统存储器、 OTP 区域以及选项字节区域,它们的地址分布及大小如下:
注意STM32F105VC的是有64K或128页x2K=256k字节的内置闪存存储器,用于存放程序和数据。
主存储器:一般我们说 STM32 内部 FLASH 的时候,都是指这个主存储器区域它是存储用户应用程序的空间,芯片型号说明中的 1M FLASH、 2M FLASH 都是指这个区域的大小。与其它 FLASH 一样,在写入数据前,要先按扇区擦除,
系统存储区:系统存储区是用户不能访问的区域,它在芯片出厂时已经固化了启动代码,它负责实现串口、 USB 以及 CAN 等 ISP 烧录功能。
OTP 区域:OTP(One Time Program),指的是只能写入一次的存储区域,容量为 512 字节,写入后数据就无法再更改, OTP 常用于存储应用程序的加密密钥。
选项字节:选项字节用于配置 FLASH 的读写保护、电源管理中的 BOR 级别、软件/硬件看门狗等功能,这部分共 32 字节。可以通过修改 FLASH 的选项控制寄存器修改。
1.2、对内部Flash的写入过程:
1. 解锁 (固定的KEY值)
(1) 往 Flash 密钥寄存器 FLASH_KEYR 中写入 KEY1 = 0x45670123
(2) 再往 Flash 密钥寄存器 FLASH_KEYR 中写入 KEY2 = 0xCDEF89AB
2. 数据操作位数
最大操作位数会影响擦除和写入的速度,其中 64 位宽度的操作除了配置寄存器位外,还需要在 Vpp 引脚外加一个 8-9V 的电压源,且其供电间不得超过一小时,否则 FLASH可能损坏,所以 64 位宽度的操作一般是在量产时对 FLASH 写入应用程序时才使用,大部分应用场合都是用 32 位的宽度。
3. 擦除扇区
在写入新的数据前,需要先擦除存储区域, STM32 提供了扇区擦除指令和整个FLASH 擦除(批量擦除)的指令,批量擦除指令仅针对主存储区。
扇区擦除的过程如下:
(1) 检查 FLASH_SR 寄存器中的“忙碌寄存器位 BSY”,以确认当前未执行任何
Flash 操作;
(2) 在 FLASH_CR 寄存器中,将“激活扇区擦除寄存器位 SER ”置 1,并设置“扇
区编号寄存器位 SNB”,选择要擦除的扇区;
(3) 将 FLASH_CR 寄存器中的“开始擦除寄存器位 STRT ”置 1,开始擦除;
(4) 等待 BSY 位被清零时,表示擦除完成。
4. 写入数据
擦除完毕后即可写入数据,写入数据的过程并不是仅仅使用指针向地址赋值,赋值前还还需要配置一系列的寄存器,步骤如下:
(1) 检查 FLASH_SR 中的 BSY 位,以确认当前未执行任何其它的内部 Flash 操作;
(2) 将 FLASH_CR 寄存器中的 “激活编程寄存器位 PG” 置 1;
(3) 针对所需存储器地址(主存储器块或 OTP 区域内)执行数据写入操作;
(4) 等待 BSY 位被清零时,表示写入完成。
1.3、查看工程内存的分布:
由于内部 FLASH 本身存储有程序数据,若不是有意删除某段程序代码,一般不应修改程序空间的内容,所以在使用内部 FLASH 存储其它数据前需要了解哪一些空间已经写入了程序代码,存储了程序代码的扇区都不应作任何修改。通过查询应用程序编译时产生的“ *.map”后缀文件,
打开 map 文件后,查看文件最后部分的区域,可以看到一段以“ Memory Map of the
image”开头的记录(若找不到可用查找功能定位),
【注】ROM加载空间
这一段是某工程的 ROM 存储器分布映像,在 STM32 芯片中, ROM 区域的内容就是 指存储到内部 FLASH 的代码。
在上面 map 文件的描述中,我们了解到加载及执行空间的基地址(Base)都是0x08000000,它正好是 STM32 内部 FLASH 的首地址,即 STM32 的程序存储空间就直接是执行空间;它们的大小(Size)分别为 0x00000b50 及 0x00000b3c,执行空间的 ROM 比较小的原因就是因为部分 RW-data 类型的变量被拷贝到 RAM 空间了;它们的最大空间(Max)均为 0x00100000,即 1M 字节,它指的是内部 FLASH 的最大空间。
计算程序占用的空间时,需要使用加载区域的大小进行计算,本例子中应用程序使用
的内部 FLASH 是从 0x08000000 至(0x08000000+0x00000b50)地址的空间区域。
所以从扇区 1(地址 0x08004000)后的存储空间都可以作其它用途,使用这些存储空间时不会篡改应用程序空间的数据。
具体可参考原子的例程:实验四十一:FLASH 模拟 EEPROM 实验
文章引用地址:https://blog.csdn.net/qq_33559992/article/details/77676716
感谢原文作者
二、代码拆分介绍(以STM32F105系列为例,如上图表5所示)
2.1 读/写入数据流程
写数据流程
2.1.1、Flash 解锁,直接调用#include "stm32f10x_flash.h"中的void FLASH_Unlock(void)函数,这个函数是官方提供的,其内部代码如下:
1 /**2 * @brief Unlocks the FLASH Program Erase Controller.3 * @note This function can be used for all STM32F10x devices.4 * - For STM32F10X_XL devices this function unlocks Bank1 and Bank2.5 * - For all other devices it unlocks Bank1 and it is equivalent6 * to FLASH_UnlockBank1 function..7 * @param None8 * @retval None9 */
10 void FLASH_Unlock(void)11 {12 /*Authorize the FPEC of Bank1 Access*/
13 FLASH->KEYR =FLASH_KEY1;14 FLASH->KEYR =FLASH_KEY2;15
16 #ifdef STM32F10X_XL17 /*Authorize the FPEC of Bank2 Access*/
18 FLASH->KEYR2 =FLASH_KEY1;19 FLASH->KEYR2 =FLASH_KEY2;20 #endif /* STM32F10X_XL */
21 }
View Code
2.1.2、擦除扇区,也是直接调用固件库官方的函数FLASH_Status FLASH_ErasePage(uint32_t Page_Address),这个官方函数代码也贴出来看看,代码如下:
1 /**2 * @brief Erases a specified FLASH page.3 * @note This function can be used for all STM32F10x devices.4 * @param Page_Address: The page address to be erased.5 * @retval FLASH Status: The returned value can be: FLASH_BUSY, FLASH_ERROR_PG,6 * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.7 */
8 FLASH_Status FLASH_ErasePage(uint32_t Page_Address)9 {10 FLASH_Status status =FLASH_COMPLETE;11 /*Check the parameters*/
12 assert_param(IS_FLASH_ADDRESS(Page_Address));13
14 #ifdef STM32F10X_XL15 if(Page_Address
18 status =FLASH_WaitForLastBank1Operation(EraseTimeout);19 if(status ==FLASH_COMPLETE)20 {21 /*if the previous operation is completed, proceed to erase the page*/
22 FLASH->CR|=CR_PER_Set;23 FLASH->AR =Page_Address;24 FLASH->CR|=CR_STRT_Set;25
26 /*Wait for last operation to be completed*/
27 status =FLASH_WaitForLastBank1Operation(EraseTimeout);28
29 /*Disable the PER Bit*/
30 FLASH->CR &=CR_PER_Reset;31 }32 }33 else
34 {35 /*Wait for last operation to be completed*/
36 status =FLASH_WaitForLastBank2Operation(EraseTimeout);37 if(status ==FLASH_COMPLETE)38 {39 /*if the previous operation is completed, proceed to erase the page*/
40 FLASH->CR2|=CR_PER_Set;41 FLASH->AR2 =Page_Address;42 FLASH->CR2|=CR_STRT_Set;43
44 /*Wait for last operation to be completed*/
45 status =FLASH_WaitForLastBank2Operation(EraseTimeout);46
47 /*Disable the PER Bit*/
48 FLASH->CR2 &=CR_PER_Reset;49 }50 }51 #else
52 /*Wait for last operation to be completed*/
53 status =FLASH_WaitForLastOperation(EraseTimeout);54
55 if(status ==FLASH_COMPLETE)56 {57 /*if the previous operation is completed, proceed to erase the page*/
58 FLASH->CR|=CR_PER_Set;59 FLASH->AR =Page_Address;60 FLASH->CR|=CR_STRT_Set;61
62 /*Wait for last operation to be completed*/
63 status =FLASH_WaitForLastOperation(EraseTimeout);64
65 /*Disable the PER Bit*/
66 FLASH->CR &=CR_PER_Reset;67 }68 #endif /* STM32F10X_XL */
69
70 /*Return the Erase Status*/
71 returnstatus;72 }
View Code
注意这个擦除扇区函数是你提供一个STM32f105系列扇区的开始地址即可,擦除是按照页擦除(每页2KB=1024Byte)或者整个擦除(见STM32参考手册的第二章2.3.3嵌入式闪存部分介绍)
比如我们要擦除互联网型的127页,我们只需要FLASH_ErasePage(0x0803f800);执行后,第127页的0x0803f800-0x0803FFFF数据都将被擦除。
当然官方提供的也不知一个擦除函数,而是三个,具体如下,对于32位系统:一个是字节=4byte=32bite;一个是半字=2byte=16bite;一个是字节=1byte=8bite;进行擦除。
FLASH_Status FLASH_ErasePage(uint32_t Page_Address);
FLASH_Status FLASH_EraseAllPages(void);
FLASH_Status FLASH_EraseOptionBytes(void);
2.1.3、接下来是写/读数据函数,该函数也是官方给出的,我们只需要用就好了。但要注意,这个是个半字的写操作,威少是uint16_t 的数据算半字呢,因为单片机是32的,对于32位单片机系统来说,一个字是4个字节的,8位的比如51单片机系统一个字就是2位的,64位单片机系统一个字就是8个字节,脱离单片机系统说字是多少个字节是没意义的。所以这里写入/读出半字也就是一次写入2个字节,写完/读出一次地址会加2。
写数据操作:
1 /**2 * @brief Programs a half word at a specified address.3 * @note This function can be used for all STM32F10x devices.4 * @param Address: specifies the address to be programmed.5 * @param Data: specifies the data to be programmed.6 * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG,7 * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.8 */
9 FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data)10 {11 FLASH_Status status =FLASH_COMPLETE;12 /*Check the parameters*/
13 assert_param(IS_FLASH_ADDRESS(Address));14
15 #ifdef STM32F10X_XL16 /*Wait for last operation to be completed*/
17 status =FLASH_WaitForLastOperation(ProgramTimeout);18
19 if(Address
24 FLASH->CR |=CR_PG_Set;25
26 *(__IO uint16_t*)Address =Data;27 /*Wait for last operation to be completed*/
28 status =FLASH_WaitForLastBank1Operation(ProgramTimeout);29
30 /*Disable the PG Bit*/
31 FLASH->CR &=CR_PG_Reset;32 }33 }34 else
35 {36 if(status ==FLASH_COMPLETE)37 {38 /*if the previous operation is completed, proceed to program the new data*/
39 FLASH->CR2 |=CR_PG_Set;40
41 *(__IO uint16_t*)Address =Data;42 /*Wait for last operation to be completed*/
43 status =FLASH_WaitForLastBank2Operation(ProgramTimeout);44
45 /*Disable the PG Bit*/
46 FLASH->CR2 &=CR_PG_Reset;47 }48 }49 #else
50 /*Wait for last operation to be completed*/
51 status =FLASH_WaitForLastOperation(ProgramTimeout);52
53 if(status ==FLASH_COMPLETE)54 {55 /*if the previous operation is completed, proceed to program the new data*/
56 FLASH->CR |=CR_PG_Set;57
58 *(__IO uint16_t*)Address =Data;59 /*Wait for last operation to be completed*/
60 status =FLASH_WaitForLastOperation(ProgramTimeout);61
62 /*Disable the PG Bit*/
63 FLASH->CR &=CR_PG_Reset;64 }65 #endif /* STM32F10X_XL */
66
67 /*Return the Program Status*/
68 returnstatus;69 }
View Code
当然官方给的不止是这一个函数写数据,官方提供了3个
FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data);//一次写一个字,对于32系统,一次写的是4个字节,uint32_t 变量大小,32bit
FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data);//一次写一个半字,对于32系统,一次写的是2个字节,uint16_t 变量大小,16bit
FLASH_Status FLASH_ProgramOptionByteData(uint32_t Address, uint8_t Data);//一次写一个字节,对于32系统,一次写的是1个字节,uint8_t 变量大小,8bit
读数据操作:
读数据的函数,官方并没有给出:下面我们自己给出,具体的读法代码如下
1 //读取指定地址的半字(16位数据)2 //也是按照半字读出,即每次读2个字节数据返回
3 uint16_t FLASH_ReadHalfWord(uint32_t address)4 {5 return *(__IO uint16_t*)address;6 }
如果要连续都区多个地址数据,可以进行如下代码操作
1 //从指定地址开始读取多个数据
2 void FLASH_ReadMoreData(uint32_t startAddress,uint16_t *readData,uint16_t countToRead)3 {4 uint16_t dataIndex;5 for(dataIndex=0;dataIndex
2.1.4、这步骤应该就是再次上锁,保护存储区不被重写覆盖了,直接使用官方的函数即可:FLASH_Lock();//上锁写保护
具体官方代码贴出如下
1 /**2 * @brief Locks the FLASH Program Erase Controller.3 * @note This function can be used for all STM32F10x devices.4 * - For STM32F10X_XL devices this function Locks Bank1 and Bank2.5 * - For all other devices it Locks Bank1 and it is equivalent6 * to FLASH_LockBank1 function.7 * @param None8 * @retval None9 */
10 void FLASH_Lock(void)11 {12 /*Set the Lock Bit to lock the FPEC and the CR of Bank1*/
13 FLASH->CR |=CR_LOCK_Set;14
15 #ifdef STM32F10X_XL16 /*Set the Lock Bit to lock the FPEC and the CR of Bank2*/
17 FLASH->CR2 |=CR_LOCK_Set;18 #endif /* STM32F10X_XL */
19 }
View Code
三、简单的小例程代码实现
例子功能:
1、将数据存储在stm32F105单片机的主存储区0x08036000地址开始的扇区,(0x08036000应该是该单片机大约108个扇区的开始地址位置即页108起始地址)。
2、将该单片机的页108(page108=0x08036000)处的数据再读出来;
具体实现代码如下,作为例子,只进行了半字的读写操作,我们写的数据buff为空,内容默认值为0
1 #include "stm32f10x_flash.h"
2
3 #define StartServerManageFlashAddress ((u32)0x08036000)//读写起始地址(内部flash的主存储块地址从0x08036000开始)
4
5 //从指定地址开始写入多个数据
6 void FLASH_WriteMoreData(uint32_t startAddress,uint16_t *writeData,uint16_t countToWrite)7 {8 uint32_t offsetAddress=startAddress - FLASH_BASE; //计算去掉0X08000000后的实际偏移地址
9 uint32_t sectorPosition=offsetAddress/SECTOR_SIZE; //计算扇区地址,对于STM32F103VET6为0~255
10 uint32_t sectorStartAddress=sectorPosition*SECTOR_SIZE+FLASH_BASE; //对应扇区的首地址
11 uint16_t dataIndex;12
13 if(startAddress=(FLASH_BASE + SECTOR_SIZE *FLASH_SIZE)))14 {15 return;//非法地址
16 }17 FLASH_Unlock(); //解锁写保护
18
19 FLASH_ErasePage(sectorStartAddress);//擦除这个扇区
20
21 for(dataIndex=0;dataIndex
26 FLASH_Lock();//上锁写保护
27 }28
29 //读取指定地址的半字(16位数据)
30 uint16_t FLASH_ReadHalfWord(uint32_t address)31 {32 return *(__IO uint16_t*)address;33 }34
35 //从指定地址开始读取多个数据
36 void FLASH_ReadMoreData(uint32_t startAddress,uint16_t *readData,uint16_t countToRead)37 {38 uint16_t dataIndex;39 for(dataIndex=0;dataIndex
45 void write_to_flash(void)46 {47 u16 buff[1200];48 u16 count_len = 2272 / 2;50 FLASH_WriteMoreData(StartServerManageFlashAddress,buff,count_len);55 }56
57 void read_from_flash(void)58 {59 u16 buff[1200];60 u16 count_len = 2272 / 2;61 FLASH_WriteMoreData(StartServerManageFlashAddress,buff,count_len);66
67 }
1 void mian(void)2 {3 .........//初始化其他外设
4 while(1)5 {6 ...........//其他外设执行函数
7 if(满足条件真)//写数据操作8 {9 write_to_flash();
10 }11 else //读数据操作
12 {13 read_from_flash();
14 }15
16 }17 }
四、附言
值得的注意的是,我们读写的地址是0x08036000,读写方式是半字,这里地址空间对于stm32f105芯片来说是第108扇区,每个扇区2KB,stm32F105VC总共是256KB空间,128页。所以地址能取到0x08036000,像小中容量stm32f103单片机,64KB和128KB的主存储区地址都是到不了0x08036000,除非是stm32f103VE的256KB芯片的主存储快,0x08036000才是有效的存储地址,中小型这个地址都不是有效的主存储开地址(超出了)
stm32flash取数据_STM32学习笔记:读写内部Flash(介绍+附代码)相关推荐
- STM32学习笔记:读写内部FLASH
ST提供的库函数基本能搞定 简介 由于 FLASH 存储器的内容在掉电后不会丢失,芯片重新上电复位后,内核可从内部 FLASH 中加载代码并运行,亦可当做EEROM来使用保存所需要的数据,以便下次启用 ...
- 大数据业务学习笔记_学习业务成为一名出色的数据科学家
大数据业务学习笔记 意见 (Opinion) A lot of aspiring Data Scientists think what they need to become a Data Scien ...
- redis基础命令和数据操作命令学习笔记
redis基础命令和数据操作命令学习笔记 基础命令 安装成功后,redis的启动命令:先修改配置文件.将服务改成默认运行.然后以配置文件启动服务 redis-server config/redis-c ...
- 大数据HiveSQL学习笔记三-查询基础语法以及常用函数
大数据HiveSQL学习笔记三-查询基础语法以及常用函数 一.基础语法 1.SELECT -列名- FROM -表名- WHERE -筛选条件- 如:需要根据城市,性别找出匹配的10个用户 user_ ...
- React学习:路由定义及传参、数据复用-学习笔记
文章目录 React学习:路由定义及传参.数据复用-学习笔记 在React中使用react-router-dom路由 简单例子 路由定义及传参 React学习:路由定义及传参.数据复用-学习笔记 在R ...
- python气象数据可视化学习笔记6——利用python地图库cnmaps绘制地图填色图并白化
文章目录 1. 效果图 2. cnmaps简介及安装 2.1 写在前面 2.2 cnmaps简介和安装 3. 导入库 4. 定义绘图函数 4.1 使用get_adm_maps返回地图边界 4.2 ax ...
- ECharts数据可视化学习笔记和应用
ECharts数据可视化学习笔记和应用 一.概念 二.Echarts使用 使用步骤 三.Echarts-基础配置 四.柱状图图表1 五.柱状图图表2 六.折线图1 七.折线图2 八.饼状图1 九.饼形 ...
- 经典神经网络论文超详细解读(八)——ResNeXt学习笔记(翻译+精读+代码复现)
前言 今天我们一起来学习何恺明大神的又一经典之作: ResNeXt(<Aggregated Residual Transformations for Deep Neural Networks&g ...
- STM32 HAL库学习笔记2 HAL库介绍
STM32 HAL库学习笔记2 HAL库介绍 CMSIS标准 一.再次认识HAL库 HAL库设计思想 HAL库实现方式 以GPIO模块为例 GPIO外设数据类型 GPIO外设接口函数 二.使用HAL库 ...
- 影像组学视频学习笔记(27)-SimpleITK包介绍、Li‘s have a solution and plan.
本笔记来源于B站Up主: 有Li 的影像组学的系列教学视频 本节(27)主要讲解: 功能强大的图像处理工具SimpleITK包 视频中李博士演示了SimpleITK的两个基本功能:图像格式转换以及图像 ...
最新文章
- java 实现hashmap_Java集合(十)实现Map接口的HashMap
- GitHub 2017 年度报告,最受欢迎的编程语言是?
- python getopt参数参数自动补全_如何在Python中使用getopt / OPTARG?如果给出过多的参数(9),如何转移参数?...
- STM32----摸石头过河系列(四)
- hadoop--HDFS_DataNode工作机制
- 经验总结[系统方面]
- 查询:使用多表连接查询数据
- Java进阶之网络编程
- 显示器尺寸对照表_常见像素和显示屏大小对照表
- 人工智能与安全论坛:智能与安全的融合与对抗
- html5颜色选择按钮,H5的input color系统颜色选择器
- 【测试理论】如何做好探索性测试(二)—增加维度
- Android ViewPager放入多个XML如何监听其的控件
- C++ 60分钟入门教程 - 1、绪论
- null hypothesis
- 3G终端变局:安卓崛起 联通高调摆脱苹果
- 环境光照IBL(Image-Based Lighting)
- 线性代数让我想想:三阶行列式计算优化策略
- 一个分组查询引发的思考
- python列表的基本操作-python列表的用法
热门文章
- 华为手机怎么把计算机放到桌面,将华为手机投影到计算机屏幕
- 【解决方法】VMware Horizo​​n View创建虚拟桌面失败,报错:View Composer Agent初始化错误(16):无法激活软件许可证
- MAC 控制台常用命令
- 06_JavaEE回顾笔记Ⅱ
- Java实现多张图片转pdf
- matlab中pts什么意思,【网安学术】使用PTS和SLM联合技术降低FBMC-OQAM系统的PAPR
- 仪器采集信号后用matlab分析,基于MATLAB的语音信号采集和分析系统的可视化设计...
- 使用反相器的rc振荡电路
- 《计算机网络教程》(微课版 第五版)复习补充题
- PCB layout的基本原则