最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
当前位置: 首页 - 正文

STM32学习笔记:读写内部Flash(介绍+附代码)

来源:动视网 责编:小OO 时间:2025-09-24 10:09:09
文档

STM32学习笔记:读写内部Flash(介绍+附代码)

STM32学习笔记:读写内部Flash(介绍+附代码)⼀、介绍⾸先我们需要了解⼀个内存映射:stm32的flash地址起始于0x08000000,结束地址是0x08000000加上芯⽚实际的flash⼤⼩,不同的芯⽚flash⼤⼩不同。RAM起始地址是0x20000000,结束地址是0x20000000加上芯⽚的RAM⼤⼩。不同的芯⽚RAM也不同。Flash中的内容⼀般⽤来存储代码和⼀些定义为const的数据,断电不丢失,RAM可以理解为内存,⽤来存储代码运⾏时的数据,变量等等。掉电数据丢失。
推荐度:
导读STM32学习笔记:读写内部Flash(介绍+附代码)⼀、介绍⾸先我们需要了解⼀个内存映射:stm32的flash地址起始于0x08000000,结束地址是0x08000000加上芯⽚实际的flash⼤⼩,不同的芯⽚flash⼤⼩不同。RAM起始地址是0x20000000,结束地址是0x20000000加上芯⽚的RAM⼤⼩。不同的芯⽚RAM也不同。Flash中的内容⼀般⽤来存储代码和⼀些定义为const的数据,断电不丢失,RAM可以理解为内存,⽤来存储代码运⾏时的数据,变量等等。掉电数据丢失。
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也就是K的RAM。这与STM32的内存地址映射关系是对应的。

M3复位后,从0x08000004取出复位中断的地址,并且跳转到复位中断程序,中断执⾏完之后会跳到我们的main函数,main函数⾥边⼀般是⼀个死循环,进去后就不会再退出,当有中断发⽣的时候,M3将PC指针强制跳转回中断向量表,然后根据中断源进⼊对应的中断函数,执⾏完中断函数之后,再次返回main函数中。⼤致的流程就是这样。

1.1、内部Flash的构成:STM32F429 的内部 FLASH 包含主存储器、系统存储器、 OTP 区域以及选项字节区域,它们的地址分布及⼤⼩如下:

STM32F103的中容量内部 FLASH 包含主存储器、系统存储器、 OTP 区域以及选项字节区域,它们的地址分布及⼤⼩如下:

注意STM32F105VC的是有K或128页x2K=256k字节的内置闪存存储器,⽤于存放程序和数据。

1. 主存储器:⼀般我们说 STM32 内部 FLASH 的时候,都是指这个主存储器区域它是存储⽤户应⽤程序的空间,芯⽚型号说明中的 1M

FLASH、 2M FLASH 都是指这个区域的⼤⼩。与其它 FLASH ⼀样,在写⼊数据前,要先按扇区擦除,

2. 系统存储区:系统存储区是⽤户不能访问的区域,它在芯⽚出⼚时已经固化了启动代码,它负责实现串⼝、 USB 以及 CAN 等 ISP 烧

录功能。

3. OTP 区域:OTP(One Time Program),指的是只能写⼊⼀次的存储区域,容量为 512 字节,写⼊后数据就⽆法再更改, OTP 常⽤于

存储应⽤程序的加密密钥。

4. 选项字节:选项字节⽤于配置 FLASH 的读写保护、电源管理中的 BOR 级别、软件/硬件看门狗等功能,这部分共 32 字节。可以通过

修改 FLASH 的选项控制寄存器修改。

1.2、对内部Flash的写⼊过程:

1. 解锁(固定的KEY值)

(1) 往 Flash 密钥寄存器 FLASH_KEYR 中写⼊ KEY1 = 0x45670123

(2) 再往 Flash 密钥寄存器 FLASH_KEYR 中写⼊ KEY2 = 0xCDEFAB

2. 数据操作位数

最⼤操作位数会影响擦除和写⼊的速度,其中 位宽度的操作除了配置寄存器位外,还需要在 Vpp 引脚外加⼀个 8-9V 的电压源,且其供电间不得超过⼀⼩时,否则 FLASH可能损坏,所以 位宽度的操作⼀般是在量产时对 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 equivalent

6 * to FLASH_UnlockBank1 function..

7 * @param None

8 * @retval None

9*/

10void 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_XL

17/* 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_XL

15if(Page_Address < FLASH_BANK1_END_ADDRESS)

16 {

17/* Wait for last operation to be completed */

18 status = FLASH_WaitForLastBank1Operation(EraseTimeout);

19if(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 }

33else

34 {

35/* Wait for last operation to be completed */

36 status = FLASH_WaitForLastBank2Operation(EraseTimeout);

37if(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

55if(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);

65/* Disable the PER Bit */

66 FLASH->CR &= CR_PER_Reset;

67 }

68#endif /* STM32F10X_XL */

69

70/* Return the Erase Status */

71return status;

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位的,位单⽚机

系统⼀个字就是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_XL

16/* Wait for last operation to be completed */

17 status = FLASH_WaitForLastOperation(ProgramTimeout);

18

19if(Address < FLASH_BANK1_END_ADDRESS)

20 {

21if(status == FLASH_COMPLETE)

22 {

23/* if the previous operation is completed, proceed to program the new data */

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 }

34else

35 {

36if(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

53if(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;

}

65#endif /* STM32F10X_XL */

66

67/* Return the Program Status */

68return status;

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 {

5return *(__IO uint16_t*)address;

6 }

如果要连续都区多个地址数据,可以进⾏如下代码操作

1//从指定地址开始读取多个数据

2void FLASH_ReadMoreData(uint32_t startAddress,uint16_t *readData,uint16_t countToRead)

3 {

4 uint16_t dataIndex;

5for(dataIndex=0;dataIndex6 {

7 readData[dataIndex]=FLASH_ReadHalfWord(startAddress+dataIndex*2);

8 }

9 }

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 equivalent

6 * to FLASH_LockBank1 function.

7 * @param None

8 * @retval None

9*/

10void 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_XL

16/* 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//从指定地址开始写⼊多个数据

6void 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

13if(startAddress=(FLASH_BASE + SECTOR_SIZE * FLASH_SIZE)))

14 {

15return;//⾮法地址

16 }

17 FLASH_Unlock(); //解锁写保护

18

19 FLASH_ErasePage(sectorStartAddress);//擦除这个扇区

20

21for(dataIndex=0;dataIndex22 {

23 FLASH_ProgramHalfWord(startAddress+dataIndex*2,writeData[dataIndex]);

24 }

25

26 FLASH_Lock();//上锁写保护

27 }

28

29//读取指定地址的半字(16位数据)

30 uint16_t FLASH_ReadHalfWord(uint32_t address)

31 {

32return *(__IO uint16_t*)address;

33 }

34

35//从指定地址开始读取多个数据

36void FLASH_ReadMoreData(uint32_t startAddress,uint16_t *readData,uint16_t countToRead)

37 {

38 uint16_t dataIndex;

39for(dataIndex=0;dataIndex40 {

41 readData[dataIndex]=FLASH_ReadHalfWord(startAddress+dataIndex*2);

42 }

43 }

44

45void write_to_flash(void)

46 {

47 u16 buff[1200];

48 u16 count_len = 2272 / 2;

50 FLASH_WriteMoreData(StartServerManageFlashAddress,buff,count_len);

55 }

56

57void read_from_flash(void)

58 {

59 u16 buff[1200];

60 u16 count_len = 2272 / 2;

61 FLASH_WriteMoreData(StartServerManageFlashAddress,buff,count_len);

66

67 }

1void mian(void)

2 {

3 .........//初始化其他外设

4while(1)

5 {

6 ...........//其他外设执⾏函数

7if(满⾜条件真)//写数据操作

8{

9 write_to_flash();

10}

11else //读数据操作

12 {

13 read_from_flash();

14 }

15

16 }

17 }

四、附⾔

值得的注意的是,我们读写的地址是0x08036000,读写⽅式是半字,这⾥地址空间对于stm32f105芯⽚来说是第108扇区,每个扇区

2KB,stm32F105VC总共是256KB空间,128页。所以地址能取到0x08036000,像⼩中容量stm32f103单⽚机,KB和128KB的主存储区地址都是到不了0x08036000,除⾮是stm32f103VE的256KB芯⽚的主存储快,0x08036000才是有效的存储地址,中⼩型这个地址都不是有效的主存储开地址(超出了)

文档

STM32学习笔记:读写内部Flash(介绍+附代码)

STM32学习笔记:读写内部Flash(介绍+附代码)⼀、介绍⾸先我们需要了解⼀个内存映射:stm32的flash地址起始于0x08000000,结束地址是0x08000000加上芯⽚实际的flash⼤⼩,不同的芯⽚flash⼤⼩不同。RAM起始地址是0x20000000,结束地址是0x20000000加上芯⽚的RAM⼤⼩。不同的芯⽚RAM也不同。Flash中的内容⼀般⽤来存储代码和⼀些定义为const的数据,断电不丢失,RAM可以理解为内存,⽤来存储代码运⾏时的数据,变量等等。掉电数据丢失。
推荐度:
  • 热门焦点

最新推荐

猜你喜欢

热门推荐

专题
Top