打印
[其他ST产品]

STM32F407----内部Flash的读写

[复制链接]
446|15
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
一、STM32存储器介绍
STM32存储器分为以下两种:

1. 随机存储器—RAM
RAM是与CPU直接交换数据的内部存储器,也叫主存(内存)。
它可以随时读写,而且速度很快,通常作为操作系统或其他正在运行中的程序的临时数据存储媒介。
当电源关闭时RAM不能保留数据(掉电数据消失哦)如果需要保存数据,就必须把它们写入一个长期的存储设备中(例如硬盘)。
2. 只读存储器—ROM
ROM所存数据,一般是装入整机前事先写好的,整机工作过程中只能读出,而不像随机存储器那样能快速地、方便地加以改写。
ROM所存数据稳定,断电后所存数据也不会改变。

使用特权

评论回复
沙发
gaonaiweng|  楼主 | 2023-12-27 13:38 | 只看该作者
二、STM32F407系列存储器介绍
按照内存,具体分类如下:

使用特权

评论回复
板凳
gaonaiweng|  楼主 | 2023-12-27 13:38 | 只看该作者
本文使用的是STM32F407VET6芯片,keil5环境下默认的内存配置见下图:

使用特权

评论回复
地板
gaonaiweng|  楼主 | 2023-12-27 13:38 | 只看该作者
ROM区域 是0x8000000开始,大小是512K字节。
RAM区域 是0x20000000开始,大小是192K字节。

内部Flash基本知识
内部Flash就是STM32存储器的ROM区域,掉电数据不丢失,但是Flash在STM32中比较重要,程序也是保存在这个地方,所以轻易不让用户进行随意的读写,以避免不必要的问题。

使用特权

评论回复
5
gaonaiweng|  楼主 | 2023-12-27 13:39 | 只看该作者
内部Flash模块构成如下: 内部Flash的擦除功能是一个扇区一个扇区的擦除。

使用特权

评论回复
6
gaonaiweng|  楼主 | 2023-12-27 13:39 | 只看该作者
三、内部Flash的读取
对于内部Flash的读取操作比较简单,可以直接指针寻址读取数据。
具体代码如下:
/**
*@功能:从内部Flash读取指定字节数据
*@参数1:ReadAddress:数据起始地址
*@参数2:*data:      读取到的数据缓存首地址
*@参数3:length:     读取字节个数
*/
void ReadFlashData(uint32_t ReadAddress, uint8_t *data, uint32_t length)
{
    for(uint32_t i=0;i<length;i++)
    {
        data[i]=*(uint8_t*)(ReadAddress+i); //读取数据
    }
}

使用特权

评论回复
7
gaonaiweng|  楼主 | 2023-12-27 13:39 | 只看该作者
四、内部Flash的写入
内部Flash 写入数据之前需要判断以前的数据是否为0xFF,如果不是0xFF,需要擦除,才可以正确写入新的数据。

使用特权

评论回复
8
gaonaiweng|  楼主 | 2023-12-27 13:39 | 只看该作者
例如:
上一次存数据为0x52,下次直接存储数据0x01。
如果不擦除,就写入数据,结果读出来就是0x51。

由于STM32F407的擦除操作,最少是扇区擦除。所以我们写入数据也要一整扇区的写入,不可以分多次对一扇区写入数据,因为下一次的写入擦除会把上一次的数据擦除。

使用特权

评论回复
9
gaonaiweng|  楼主 | 2023-12-27 13:39 | 只看该作者
1. 具体操作步骤
解锁Flash写保护。
擦除Flash数据。
写入Flash数据。
重新锁定Flash写保护。

使用特权

评论回复
10
gaonaiweng|  楼主 | 2023-12-27 13:40 | 只看该作者
2. HAL库函数
(1) Flash解锁和锁定函数
HAL_FLASH_Unlock();    //解锁
HAL_FLASH_Lock();      //上锁

使用特权

评论回复
11
gaonaiweng|  楼主 | 2023-12-27 13:40 | 只看该作者
(2) Flash擦除函数
擦除函数
/*
功能:Flash擦除
参数1:擦除操作的配置信息
参数2:错误扇区的配置信息
*/
HAL_StatusTypeDef HAL_FLASHEx_Erase(FLASH_EraseInitTypeDef *pEraseInit, uint32_t *SectorError);

使用特权

评论回复
12
gaonaiweng|  楼主 | 2023-12-27 13:40 | 只看该作者
(2) Flash擦除函数
擦除函数
/*
功能:Flash擦除
参数1:擦除操作的配置信息
参数2:错误扇区的配置信息
*/
HAL_StatusTypeDef HAL_FLASHEx_Erase(FLASH_EraseInitTypeDef *pEraseInit, uint32_t *SectorError);

使用特权

评论回复
13
gaonaiweng|  楼主 | 2023-12-27 13:40 | 只看该作者
用于擦除操作的配置信息
typedef struct
{
  uint32_t TypeErase;   /*擦除类型:FLASH_TYPEERASE_SECTORS 扇区擦除和 FLASH_TYPEERASE_MASSERASE 批量擦除*/

  uint32_t Banks;       /*当启用批量擦除时,选择要擦除的存储体。*/

  uint32_t Sector;      /*当启用扇区擦除时,要擦除的初始FLASH扇区 */

  uint32_t NbSectors;   /*要擦除的扇区数。此参数的值必须介于1和(最大扇区数-初始扇区的值)之间*/

  uint32_t VoltageRange;/*定义擦除并行性的设备电压范围。*/

} FLASH_EraseInitTypeDef;

使用特权

评论回复
14
gaonaiweng|  楼主 | 2023-12-27 13:40 | 只看该作者
(3) Flash写操作函数
/*
功能:在指定地址写入数据
参数1:写入数据类型:        FLASH_TYPEPROGRAM_BYTE - 8bit,
                                        FLASH_TYPEPROGRAM_HALFWORD - 16bit
                                        FLASH_TYPEPROGRAM_WORD - 32bit
                                        FLASH_TYPEPROGRAM_DOUBLEWORD - 64bit
参数2:指定要写入的地址
参数3:指定要写入的数据
*/
HAL_StatusTypeDef HAL_FLASH_Program(uint32_t TypeProgram, uint32_t Address, uint64_t Data);

使用特权

评论回复
15
gaonaiweng|  楼主 | 2023-12-27 13:41 | 只看该作者
(4) Flash等待函数
//等待FLASH操作完成
HAL_StatusTypeDef FLASH_WaitForLastOperation(uint32_t Timeout);

使用特权

评论回复
16
gaonaiweng|  楼主 | 2023-12-27 13:41 | 只看该作者
3. 具体程序
#define FMC_FLASH_BASE      0x08000000   // FLASH的起始地址
#define FMC_FLASH_END       0x08080000   // FLASH的结束地址

#define FLASH_WAITETIME     50000        //FLASH等待超时时间

//FLASH 扇区的起始地址
#define ADDR_FLASH_SECTOR_0     ((uint32_t)0x08000000)         //扇区0起始地址, 16 Kbytes  
#define ADDR_FLASH_SECTOR_1     ((uint32_t)0x08004000)         //扇区1起始地址, 16 Kbytes  
#define ADDR_FLASH_SECTOR_2     ((uint32_t)0x08008000)         //扇区2起始地址, 16 Kbytes  
#define ADDR_FLASH_SECTOR_3     ((uint32_t)0x0800C000)         //扇区3起始地址, 16 Kbytes  
#define ADDR_FLASH_SECTOR_4     ((uint32_t)0x08010000)         //扇区4起始地址, 64 Kbytes  
#define ADDR_FLASH_SECTOR_5     ((uint32_t)0x08020000)         //扇区5起始地址, 128 Kbytes  
#define ADDR_FLASH_SECTOR_6     ((uint32_t)0x08040000)         //扇区6起始地址, 128 Kbytes  
#define ADDR_FLASH_SECTOR_7     ((uint32_t)0x08060000)         //扇区7起始地址, 128 Kbytes  
#define ADDR_FLASH_SECTOR_8     ((uint32_t)0x08080000)         //扇区8起始地址, 128 Kbytes  
#define ADDR_FLASH_SECTOR_9     ((uint32_t)0x080A0000)         //扇区9起始地址, 128 Kbytes  
#define ADDR_FLASH_SECTOR_10    ((uint32_t)0x080C0000)         //扇区10起始地址,128 Kbytes  
#define ADDR_FLASH_SECTOR_11    ((uint32_t)0x080E0000)         //扇区11起始地址,128 Kbytes

//读取指定地址的字(32位数据)
//faddr:读地址
//返回值:对应数据.
static uint32_t STMFLASH_ReadWord(uint32_t faddr)
{
    return *(uint32_t*)faddr;
}

//获取某个地址所在的flash扇区
//addr:flash地址
//返回值:0~11,即addr所在的扇区
uint8_t STMFLASH_GetFlashSector(uint32_t addr)
{
    if(addr<ADDR_FLASH_SECTOR_1)return FLASH_SECTOR_0;
    else if(addr<ADDR_FLASH_SECTOR_2)return FLASH_SECTOR_1;
    else if(addr<ADDR_FLASH_SECTOR_3)return FLASH_SECTOR_2;
    else if(addr<ADDR_FLASH_SECTOR_4)return FLASH_SECTOR_3;
    else if(addr<ADDR_FLASH_SECTOR_5)return FLASH_SECTOR_4;
    else if(addr<ADDR_FLASH_SECTOR_6)return FLASH_SECTOR_5;
    else if(addr<ADDR_FLASH_SECTOR_7)return FLASH_SECTOR_6;
    else if(addr<ADDR_FLASH_SECTOR_8)return FLASH_SECTOR_7;
    else if(addr<ADDR_FLASH_SECTOR_9)return FLASH_SECTOR_8;
    else if(addr<ADDR_FLASH_SECTOR_10)return FLASH_SECTOR_9;
    else if(addr<ADDR_FLASH_SECTOR_11)return FLASH_SECTOR_10;   
    return FLASH_SECTOR_11;       
}

/**
*@功能:向内部Flash写入数据
*@参数1:WriteAddress:数据要写入的目标地址(偏移地址)
*@参数2:*data: 写入的数据首地址
*@参数3:length:写入数据的个数
*/
void WriteFlashData(uint32_t WriteAddress, uint8_t *data, uint32_t length)
{
    FLASH_EraseInitTypeDef FlashEraseInit;
    HAL_StatusTypeDef FlashStatus=HAL_OK;
    uint32_t SectorError=0;
    uint32_t addrx=0;
    uint32_t endaddr=0;
   
    if( (WriteAddress < FMC_FLASH_BASE) || ( WriteAddress + length >= FMC_FLASH_END) || (length <= 0) )
    return;

    HAL_FLASH_Unlock();              //解锁
    addrx = WriteAddress;            //写入的起始地址
    endaddr = WriteAddress+length;   //写入的结束地址


        while(addrx<endaddr)  //扫清一切障碍.(对非FFFFFFFF的地方,先擦除)
        {
             if(STMFLASH_ReadWord(addrx)!=0XFFFFFFFF)//有非0XFFFFFFFF的地方,要擦除这个扇区
            {   
                FlashEraseInit.TypeErase=FLASH_TYPEERASE_SECTORS;       //擦除类型,扇区擦除
                FlashEraseInit.Sector=STMFLASH_GetFlashSector(addrx);   //要擦除的扇区
                FlashEraseInit.NbSectors=1;                             //一次只擦除一个扇区
                FlashEraseInit.VoltageRange=FLASH_VOLTAGE_RANGE_3;      //电压范围,VCC=2.7~3.6V之间!!
                if(HAL_FLASHEx_Erase(&FlashEraseInit,&SectorError)!=HAL_OK)
                {
                    break;//发生错误了
                }
                }else addrx+=1;
                FLASH_WaitForLastOperation(FLASH_WAITETIME);                //等待上次操作完成
        }
   
    FlashStatus=FLASH_WaitForLastOperation(FLASH_WAITETIME);            //等待上次操作完成
    if(FlashStatus==HAL_OK)
    {
         while(WriteAddress<endaddr)//写数据
         {
            if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE,WriteAddress,*data)!=HAL_OK)//写入数据
            {
                break;        //写入异常
            }
            WriteAddress+=1;
            data++;
        }  
    }
    HAL_FLASH_Lock();           //上锁
}

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

68

主题

688

帖子

3

粉丝