(HAL库)STM32F407IGT6内部Flash使用方法

目录

一、STM32F4存储器介绍

二、STM32F407IGT6内部Flash简介

三、FLASH操作流程

四、Flash读写操作代码

1. 写入先前擦除Flash数据

2. 向指定地址写入数据

3. 读取指定地址的数据

4. Flash读写操作代码头文件

五、Debug调试示例


一、STM32F4存储器介绍

STM32存储器分为以下两种:

1. 随机存储器—RAM
       RAM是与CPU直接交换数据的内部存储器,也叫主存(内存)。它可以随时读写,而且速度很快,通常作为操作系统或其他正在运行中的程序的临时数据存储媒介。当电源关闭时RAM数据消失,如果需要保存数据,就必须把写入一个长期的存储设备中(如硬盘等)。

2. 只读存储器—ROM

       ROM所存数据,一般是装入整机前事先写好的,整机工作过程中只能读出,而不像随机存储器那样能快速地、方便地加以改写。ROM存储数据稳定,断电后所存数据不丢失。

STM32F4系列Flash容量
型号ROM(字节)RAM(字节)
STM32F407xE512Kb192Kb
STM32F407xG1024Kb192Kb

         本文使用的是STM32F407IGT6芯片,keil5环境下默认的内存配置如下图所示:

        由图可知:STM32F407IGT6的ROM区域 是0x8000000开始,大小是512K字节。RAM区域 是0x20000000开始,大小是192K字节。

二、STM32F407IGT6内部Flash简介

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

       由上图所示的Flash架构图可知,STM32F407IGT6分为主存储器、系统存储器、OTP区域和选项字节四部分。其中:

        Flash主存储器,用于存放代码和数据常数(如const 类型的数据)。从上图可以看出主存储器的起始地址就是 0X08000000 。当 B0 、 B1 都接 GND 的时候,就是从 0X08000000 开始运行代码的。
        系统存储器,用来存放STM32的 bootloaderr代码,此代码是出厂时就固化在 STM32F4 里面了,专门来给主存储器下载代码。当 B0 接 V3.3 B1 接 GND 的时候,从该存储器启动(即进入串口下载模式)。
        OTP 区域,即一次性可编程区域,共 528 字节,被分成两个部分,前面 512 字节( 32 字节为 1 块,分成 16 块),可以用来存储一些用户数据(一次性,写完一次,永远不可以擦除!),后面 16 字节,用于锁定对应块。这里的一次性是指写入一次后,再次写入的话是前后相与的值,两次不相同则会置零  。

        字节选项:用于配置读保护、BOR 级别、看门狗以及器件处于待机或停止模式下的复位。

        STM32会根据自身Flash容量的大小,将Flash分为每页1K字节或每页2K字节。超过256K容量的每页为2K字节。对于本次使用的SMT32F407IGT6,其容量为1024K,则内部分为每页2K字节。

三、FLASH操作流程

        STM32的Flash操作属于嵌入式设备底层操作,可直接对地址进行存取。其操作流程如下:

1. 确定要写入Flash的首地址
2. 解锁Flash写保护
3. 对Flash进行操作(写入数据)
4. 对Flash重新上锁

       首地址确定: SMT32F407IGT6的Flash起始地址为0X0800 0000,由于STM32运行代码从地址0X0800 0000开始,因此,使用内部Flash时开始地址应该往后偏移,否则会将程序部分覆盖掉,导致系统死机。本文使用的FLASH范围是0X08010000-0X0801FFFF。

        解锁Flash写保护:HAL_FLASH_Unlock( );

       对Flash进行写操作:Flash的写操作,需要擦除一整页后再重新写入,不能对特定处进行修改,写的时候可以分多次写入。注意:擦写次数较多数据的不建议使用内部Flash进行存储,手册中给的数据是擦写1W次。

        对Flash重新上锁:HAL_FLASH_Lock( );

四、Flash读写操作代码

1. 写入先前擦除Flash数据

       擦除Flash内容示例代码:

#include "flash.h"
//清除扇区
//StartAddress:取值范围(0x08000000~0x0807FFFF)

//F407IGT6 1024k 11个扇区
uint32_t sectStartAddr[12]=
{
    0x08000000,//0
    0x08004000,//1
    0x08008000,//2
    0x0800c000,//3
    0x08010000,//4
    0x08020000,//5
    0x08040000,//6
    0x08060000,//7
	0x08080000,//8
	0x080A0000,//9
	0x080C0000,//10
	0x080E0000,//11
};

//获取Sector的编号
int GetSectorFromAddress(uint32_t address)
{
    int sect;
    if( address < 0x08000000 || address > 0x080FFFFF )
        return -1;
    for( int i=0; i<11; i++ )
    {
        if( address >= sectStartAddr[i] && address < sectStartAddr[i+1] )
        {
            sect = i;
            break;
        }
    }
    return sect;
}

void FlashErase(uint32_t StartAddress)
{
    int sect = 0;
    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);//清除一些错误标志
                          
    sect = GetSectorFromAddress(StartAddress);//获取地址所在的扇区
    FLASH_Erase_Sector(4,FLASH_VOLTAGE_RANGE_3);//擦除指定的闪存扇区(0~11)
    HAL_FLASH_Lock();//上锁
}

2. 向指定地址写入数据

        向Flash写入数据示例代码:

//返回当前要操作的扇区
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;	
}

//写入Data_flash
void STMFLASH_Write(uint32_t Addr,uint32_t *pBuffer,uint32_t Num)	
{ 
	FLASH_EraseInitTypeDef FlashEraseInit;
	HAL_StatusTypeDef FlashStatus=HAL_OK;
	uint32_t SectorError=0;
	uint32_t addrx=0;
	uint32_t endaddr=0;	
	WriteAddr=Addr;
	if(WriteAddr<STM32_FLASH_BASE||WriteAddr%4)return;	//错误地址
    
	HAL_FLASH_Unlock();         //解锁flash
	addrx=WriteAddr;			//写入起始地址
	endaddr=WriteAddr+Num*4;	//写入结束地址
    
	if(addrx < 0x08010000)
	{
		while(addrx<endaddr)		
		{
			 if(STM32_FLASH_ReadWord(addrx)!=0XFFFFFFFF)		
			 {   
				FlashEraseInit.TypeErase=FLASH_TYPEERASE_SECTORS;       //扇区擦除
				FlashEraseInit.Sector=STMFLASH_GetFlashSector(addrx);   //擦除的扇区
				FlashEraseInit.NbSectors=1;                             //擦除1个扇区
				FlashEraseInit.VoltageRange=FLASH_VOLTAGE_RANGE_3;      //电压范围2.7-3.6
				if(HAL_FLASHEx_Erase(&FlashEraseInit,&SectorError)!=HAL_OK) 
				{
					break;//写入错误
				}
			 }
			 else addrx+=4;
			 FLASH_WaitForLastOperation(FLASH_WAITETIME);                //等待操作完成
		}
	}
	FlashStatus=FLASH_WaitForLastOperation(FLASH_WAITETIME);         //等待操作完成
	if(FlashStatus==HAL_OK)
	{
		 while(WriteAddr<endaddr)//写数据
		 {
			if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,WriteAddr,*pBuffer)!=HAL_OK)
			{ 
				break;
			}
			WriteAddr+=4;
			pBuffer++;
		}  
	}
	HAL_FLASH_Lock();           //flash上锁

3. 读取指定地址的数据

       读取Flash指定地址的数据示例代码:

//读取指定地址的字(32位数据) 
//faddr:读地址 
//返回值:对应数据.
uint32_t WriteAddr = 0x08010000;

uint32_t STM32_FLASH_ReadWord(uint32_t faddr)
{
	return *(__IO uint32_t*)faddr; 
}

//从指定地址开始读出指定长度的数据
//ReadAddr:起始地址
//pBuffer:数据指针
//NumToRead:字(32位)数
void STM32_FLASH_Read(uint32_t  ReadAddr,uint32_t  *pBuffer,uint32_t  NumToRead)   	
{
	uint32_t  i;
	for(i=0;i<NumToRead;i++)
	{
		pBuffer[i]=STM32_FLASH_ReadWord(ReadAddr);//读取4个字节.
		ReadAddr+=4;//偏移4个`字节.	
	}
}

4. Flash读写操作代码头文件

       Flash读写操作代码头文件

#ifndef __FLASH_H
#define __FLASH_H
#include "main.h"
 
#define STM32_FLASH_BASE 0x08000000 	//flash起始地址
#define FLASH_WAITETIME  50000          //FLASH等待超时时间

void FlashErase(uint32_t StartAddress);
int GetSectorFromAddress(uint32_t address);
void FlashWrite(uint32_t StartAddress,uint32_t data);
uint32_t FlashRead(uint32_t StartAddress); 
//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 
 
//读取数值
uint32_t STM32_FLASH_ReadWord(uint32_t faddr);  
//flash写入,参数一为写入的地址,参数二为写入的缓冲区,参数三为写入的数据长度
void STMFLASH_Write(uint32_t Addr,uint32_t *pBuffer,uint32_t Num);
//flash读取	
void STM32_FLASH_Read(uint32_t  ReadAddr,uint32_t  *pBuffer,uint32_t  NumToRead);  
extern  uint32_t WriteAddr;
#endif

完整代码链接:https://pan.baidu.com/s/1bovod11KH79YByg-lUAR3Q?pwd=1234 提取码: 1234 

参考文章:http://t.csdnimg.cn/BfnkW


五、Debug调试示例


//将flash_write_pressure数组中的4个数据存储到WRITE_P_ADDRFlash内存地址中(0x0801 0000)
STMFLASH_Write(WRITE_P_ADDR,(uint32_t*)flash_write_pressure,4);

//从READ_P_ADDR地址读出4个数据存储到flash_read_pressure数组中(0x0801 0000)
STM32_FLASH_Read(READ_P_ADDR,(uint32_t*)flash_read_pressure,4);

  • 16
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值