stm32内部Flash的读写操作

发布者:SerendipityLove最新更新时间:2025-08-22 来源: cnblogs关键字:stm32  内部Flash  读写操作 手机看文章 扫描二维码
随时随地手机看文章

stm32的产品都有内置Flash,而且不同系列的产品其内置Flash的大小不尽相同,结构上也有差异,本文将对stm32f07x,stm32f10x,stm32f40x的内置Flash结构,以及如何进行读写操作做一个介绍。

一、特性与构成

1.stm32f07x系列

 

 

 2、stm32f10x系列

 

   

 

  

 

   

 

   

 

  3、stm32f40x系列 

   

 

 

 

 二、对内部Flash的读写操作

 2.1 stm32不同系列的产品,内部Flash的特性与构成确实存在一定的差异,但是对于读写操作,步骤一致,比如要往内部flash写入数据,需要几个步骤:

  ①、解锁flash

  ②、擦除

  ③、写入数据

  ④、锁住flash

  读取Flash的内容,只需要直接读取内存地址的数据即可。

注意:①如果要写入的地址内保存了一些重要的数据,不想丢失的话,应该在擦除之前先把数据读取到缓冲区里,再进行擦除和写入新的数据。在擦除页之后,如果写入的数据不够一页,可以连续写入。

②写入数据之前,应该计算好MCU程序占用的内存,因为MCU的程序也是保存在Flash里,如果写入的数据占用了MCU程序的内存,就会导致程序死掉。而计算MCU占用内存大小的方法可以将它生成为bin文件,从它的属性里可以知道它的大小。具体可以参考:https://www.cnblogs.com/xingboy/p/10818813.html;这里提供简单的操作介绍:

1、首先打开keil工程,点击,出现以下界面,选择User

 

 

 2、最下方的Run #1打上勾,后面文本框里输入:fromelf --bin --output .'SL@L.bin' '#L',然后点击OK

   

 

 3、编译

4、到工程文件夹里找到这个bin文件,右击该文件,点击属性就可以查到这个文件的大小

 

 

 

 

 比如我这个bin文件是16KB+,那么我们从0x0800 0000开始算起,17KB的内存不要动,从17KB的位置开始写入数据就不会影响MCU的程序。需要注意的是,不同的MCU,其每一页的大小都不一样,如开篇提供的三种MCU的Flash构成表格,stm32f07x每一页是2KB,stm32f10x的每一页是1KB,stm32f40x没有页的概念,只有扇区的概念,且扇区的大小也不一定相同,有的是16KB,有的是64KB,有的是128KB。所以虽然读操作的步骤一样,但是编程的时候有些区别。这里以HAL为例:


stm32f07x系列:


/************************************************************************

*函数名称:void Flash_Write(uint32_t address,uint32_t *data,uint8_t size)

*函数功能:往内部Flash里写入数据

*函数形参:address:写入数据的起始地址,data:要写入的数据的源地址,size:大小

*函数返回值:无

*************************************************************************/    

void Flash_Write(uint32_t address,uint32_t data)

{

    uint32_t PageError = 0;

    if(HAL_FLASH_Unlock() != HAL_OK)    /*解锁Flash*/

    {

        printf('Unlock Flash Fail!rn');

    }

    else

    {

        

        printf('Unlock Flash succeed!rn');

    }

    

    FLASH_EraseInitTypeDef FLASH_EraseInit;

    FLASH_EraseInit.TypeErase = FLASH_TYPEERASE_PAGES;

    FLASH_EraseInit.PageAddress = address;

    FLASH_EraseInit.NbPages = 1;


    if(HAL_FLASHEx_Erase(&FLASH_EraseInit,&PageError) != HAL_OK)

    {

        printf('Erase Flash Fail!rn');

    }

    else

    {

        printf('Erase Flash Succeed!rn');

    }

    


    HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD,address,data);


    

    HAL_FLASH_Lock();

}


其中:


//擦除结构体:

typedef struct

{

  uint32_t TypeErase;   /*!< TypeErase: Mass erase or page erase.

                             This parameter can be a value of @ref FLASHEx_Type_Erase */


  uint32_t PageAddress; /*!< PageAdress: Initial FLASH page address to erase when mass erase is disabled

                             This parameter must be a number between Min_Data = FLASH_BASE and Max_Data = FLASH_BANK1_END */

  

  uint32_t NbPages;     /*!< NbPages: Number of pagess to be erased.

                             This parameter must be a value between Min_Data = 1 and Max_Data = (max number of pages - value of initial page)*/

                                                          

} FLASH_EraseInitTypeDef;

//擦除函数:

HAL_StatusTypeDef HAL_FLASHEx_Erase(FLASH_EraseInitTypeDef *pEraseInit, uint32_t *PageError)

//Flash编程函数


HAL_StatusTypeDef HAL_FLASH_Program(uint32_t TypeProgram, uint32_t Address, uint64_t Data);

//锁住Flash

HAL_StatusTypeDef HAL_FLASH_Lock(void);

复制代码

TypeErase是擦除的类型,可以是FLASH_TYPEERASE_PAGES(页擦出)也可以是FLASH_TYPEERASE_MASSERASE(块擦除,可以把Main Flash主存储块全部擦除);

PageAddress是页地址,就是数据要写入的地址,因为我的MCU程序占用16KB内存,那么我从17KB开始写入数据就是0x0800 0000 + (0x400 * 17) = 0x0800 4400;

NbPages擦除多少页;


擦除函数的最后一个形参是一个指针,指向一个变量,这个变量包含了擦除错误的情况下的配置信息(0xFFFFFFFF表示所有的页都被正确擦除)


Flash编程函数:第一个形参写入的方式:FLASH_TYPEPROGRAM_HALFWORD(半字,一次写入16bit),FLASH_TYPEPROGRAM_WORD(字,一次写入32bit),FLASH_TYPEPROGRAM_DOUBLEWORD(双字,一次写入64bit).

第二个形参,写入数据的起始地址,第三个形参是要写入的数据。


stm32f40x系列

uint32_t GetSector(uint32_t Address)

{

  uint32_t sector = 0;

  if((Address < ADDR_FLASH_SECTOR_1) && (Address >= ADDR_FLASH_SECTOR_0))

  {

    sector = FLASH_SECTOR_0;  

  }

  else if((Address < ADDR_FLASH_SECTOR_2) && (Address >= ADDR_FLASH_SECTOR_1))

  {

    sector = FLASH_SECTOR_1;  

  }

  else if((Address < ADDR_FLASH_SECTOR_3) && (Address >= ADDR_FLASH_SECTOR_2))

  {

    sector = FLASH_SECTOR_2;  

  }

  else if((Address < ADDR_FLASH_SECTOR_4) && (Address >= ADDR_FLASH_SECTOR_3))

  {

    sector = FLASH_SECTOR_3;  

  }

  else if((Address < ADDR_FLASH_SECTOR_5) && (Address >= ADDR_FLASH_SECTOR_4))

  {

    sector = FLASH_SECTOR_4;  

  }

  else if((Address < ADDR_FLASH_SECTOR_6) && (Address >= ADDR_FLASH_SECTOR_5))

  {

    sector = FLASH_SECTOR_5;  

  }

  else if((Address < ADDR_FLASH_SECTOR_7) && (Address >= ADDR_FLASH_SECTOR_6))

  {

    sector = FLASH_SECTOR_6;  

  }

  else if((Address < ADDR_FLASH_SECTOR_8) && (Address >= ADDR_FLASH_SECTOR_7))

  {

    sector = FLASH_SECTOR_7;  

  }

  else if((Address < ADDR_FLASH_SECTOR_9) && (Address >= ADDR_FLASH_SECTOR_8))

  {

    sector = FLASH_SECTOR_8;  

  }

  else if((Address < ADDR_FLASH_SECTOR_10) && (Address >= ADDR_FLASH_SECTOR_9))

  {

    sector = FLASH_SECTOR_9;  

  }

  else if((Address < ADDR_FLASH_SECTOR_11) && (Address >= ADDR_FLASH_SECTOR_10))

  {

    sector = FLASH_SECTOR_10;  

  }

  else

  {

    sector = FLASH_SECTOR_11;  

  }

  return sector;


}



uint32_t start_Add = 0x080E0000;

uint32_t end_Add = 0x080E0000;



//FLASH写入数据测试

uint32_t FlashWriteData(uint8_t *data,uint8_t len)

{

    uint32_t UserStartSector;

    uint32_t SectorError;

    uint32_t i = 0;

    FLASH_EraseInitTypeDef pEraseInit;

    /*解锁Flash*/

    HAL_FLASH_Unlock();

    /*清标志位*/

    __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | 

                          FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);

    UserStartSector = GetSector(start_Add);

    pEraseInit.TypeErase = TYPEERASE_SECTORS;

  pEraseInit.Sector = UserStartSector;

  pEraseInit.NbSectors = GetSector(end_Add)-UserStartSector+1 ;

  pEraseInit.VoltageRange = VOLTAGE_RANGE_3;

    

    if (HAL_FLASHEx_Erase(&pEraseInit, &SectorError) != HAL_OK)

    {

     /* Error occurred while page erase */

        printf('Flash Erase failed!rn');

        return (1);

    }

    printf('Flash Erase succeed!rn');

    

    for(i = 0; i < len; i+= 4 )

    {

        if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, (uint32_t)(start_Add+i), *(uint32_t*)(data+i)) == HAL_OK)

        {

            /* Check the written value */

            if(*(uint32_t *)(data + i) != *(uint32_t*)(start_Add+i))

            {

                    /* Flash content doesn't match SRAM content */

                    return 2;

            }

        }

        else

        {

            printf('src data != flash datarn');

            return 3;

        }    

    }

    HAL_FLASH_Lock(); //锁住Flash

    return HAL_OK;

}


2.2 读操作


/***********************************************

*函数名称:uint32_t Flash_Read(uint32_t address)

*函数功能:从内部Flash里读出数据

*函数形参:address:要读出的数据的起始地址

*函数返回值:读取到的数据

************************************************/

uint32_t Flash_Read(uint32_t address)

{

    uint32_t retval;

    retval = *(uint16_t *)(address);

    printf('retval = %xrn',retval);

    return retval;

}


总结:如果需要存储的数据并不是很多的时候,没必要外挂一个Flash去存储数据,完全可以充分利用内部Flash的。但是内部Flash对写操作的次数有限制,网上找到的数据是1万次,而读操作的次数就没有限制了。所以当数据量不大,不会频繁修改的时候,完全可以写到内部Flash。


关键字:stm32  内部Flash  读写操作 引用地址:stm32内部Flash的读写操作

上一篇:stm32相关笔记——ADC部分
下一篇:stm32与BQ4050通讯

推荐阅读最新更新时间:2026-03-25 11:54

stm32中将结构体数据写到内部Flash时遇到的问题
在一次写代码的过程中,想把一个结构体的数据写到stm32单片机内部代码没有用到的空闲Flash,结构体开始时这样的: //#pragma pack(1) typedef struct { u8 DeviceAddr;//设备地址 LEDMODE LED_Mode; //LED 控制模式 BAUTRARE Baudrate; //串口波特率 u16 CRC16; //CRC校验 }SYSTEM_CONFIG; //#pragma pack() SYSTEM_CONFIG SystemConfig; LEDMODE和BAUTRARE是定义好的两个枚举类型,开始时发现同样的数据,在两次不同的CRC校验中得到的校验
[单片机]
stm32 内部flash
嵌入式闪存 闪存 存储器有主存储块和信息块组成 大容量产品主存储块最大为64K×64位,每个存储块划分为256个2K字节的页 编程和擦除闪存 闪存编程一次可以写入16位(半字) 闪存擦除操作可以按页面擦除或完全擦除(全擦除)。全擦除不影响信息块 编程过程 页擦除过程 操作步骤 1.解锁 2.读操作 3.擦除操作 4.写操作 5.获取FLASH状态 6.锁定 举例 #define STM32_FLASH_BASE 0x08000000 #define STM32_PAGE_NUM 256 #define STM32_PAGE_SIZE (2 * 1024) void FLASH_read(u16 *buf,
[单片机]
<font color='red'>stm32</font> <font color='red'>内部</font><font color='red'>flash</font>
stm32专题二十八:读写内部Flash
内部Flash STM32芯片内部有一个FLASH存储器,主要用于存储代码。我们在电脑上编写好应用程序后,使用下载器把编译后的代码文件烧录到该内部FLASH中,由于FLASH存储器的内容在掉电后不会丢失,芯片重新上电复位后,内核可从内部FLASH中加载代码并运行。 除了使用外部的工具(如下载器)读写内部FLASH外,STM32芯片在运行的时候,也能对自身的内部FLASH进行读写,因此,若内部FLASH存储了应用程序后还有剩余的空间,我们可以把它像外部SPI-FLASH那样利用起来,存储一些程序运行时产生的需要掉电保存的数据。 由于访问内部FLASH的速度要比外部的SPI-FLASH快得多,所以
[单片机]
<font color='red'>stm32</font>专题二十八:<font color='red'>读写</font><font color='red'>内部</font><font color='red'>Flash</font>
STM32开发笔记38: 单片机内部Flash读写
单片机型号:STM32F070F6P6 本文介绍应用C语言进行单片机内部Flash的读写技巧,将从查看文档开始,到最终完成完整的程序。 单片机型号:STM32F070F6P6 步骤如下: 1、查看文档《STM32F030x4/x6/x8/xC and STM32F070x6/xB advanced ARM®-based 32-bit MCUs》确认其Flash的内部结构。 2、查看文档确认STM32F070F6P6内部存储器地址分配。从下表中得到的主要信息是Main Flash memory的起始地址是0x08000000,长度是32KB,到0x08017FFF结束(结束值可不关心)。 3、继续
[单片机]
<font color='red'>STM32</font>开发笔记38: 单片机<font color='red'>内部</font><font color='red'>Flash</font>的<font color='red'>读写</font>
STM32程序移植之_内部flash开机次数管理lib库建立
1. 测试环境:STM32C8T6 2. 测试接口: 3. 串口使用串口一,波特率9600 单片机引脚------------CH340引脚 VCC--------------------VCC GND-------------------GND PA9--------------------RXD PA10-------------------TXD 1. 紧接011,下面进行lib可的移植 2. 需要移植好的程序和密码初始化 3. 将移植好的程序复制一份,改名为lib库建立,打开编译 4. 将所有的文件删除,留下两个文件 5. 编译成库,编译成功之后将STM32.lib库复制出
[单片机]
<font color='red'>STM32</font>程序移植之_<font color='red'>内部</font><font color='red'>flash</font>开机次数管理lib库建立
STM32内部FLASH
思想: FLASH分三个区: Bootloader区: 校验备份程序,若满足条件将用备份程序替换用户程序,否者运行用户程序. 运行区:运行用户程序,程序中要求能接受用户程序到备份区,接收完后,在备份区的程序头内打上标记,然后启动Bootloader,由Bootloader完成程序替换 备份区:用户程序在此接受 4.1 空间分区 STM32L151C8T6有64KB的FLASH空间,每4KB是一个区,每个区有16个页,程序编程是按页来编程的. 程序的Vector是按512的整数倍偏移的, 空间划分如下图, 后续所示的设置都是基于这个空间划分来配置的. 程序头的含义是这个新程序正文的标签,标记了当前程序的版本号,程序总校验,程
[单片机]
<font color='red'>STM32</font>写<font color='red'>内部</font><font color='red'>FLASH</font>
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地址的偏
[单片机]
<font color='red'>STM32</font>学习笔记:<font color='red'>读写</font><font color='red'>内部</font><font color='red'>Flash</font>
STM32 内部flash读写程序
/* Base address of the Flash sectors */ #define ADDR_FLASH_SECTOR_0 ((uint32_t)0x08000000) /* Base @ of Sector 0, 16 Kbytes */ #define ADDR_FLASH_SECTOR_1 ((uint32_t)0x08004000) /* Base @ of Sector 1, 16 Kbytes */ #define ADDR_FLASH_SECTOR_2 ((uint32_t)0x08008000) /* Base @ of Sector 2, 16 Kbytes */ #de
[单片机]
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved