[HAL library] STM32F407----reading and writing of internal Flash

[HAL Library] STM32CubeMX Development----STM32F407----Contents


1. Introduction to STM32 memory

STM32 memory is divided into the following two types:

1. Random access memory—RAM

  • RAM is an internal memory that directly exchanges data with the CPU, also called main memory (memory).
  • It can be read and written at any time , and the speed is very fast, and it is usually used as a temporary data storage medium for operating systems or other running programs.
  • RAM cannot retain data when the power is turned off ( power-off data disappears ). If you need to save data, you must write them to a long-term storage device (such as a hard disk).

2. Read-only memory—ROM

  • The data stored in ROM is generally written in advance before loading into the whole machine, and can only be read out during the working process of the whole machine, unlike random access memory, which can be rewritten quickly and conveniently.
  • The data stored in ROM is stable, and the stored data will not change after power off.

2. Introduction of STM32F407 series memory

According to the memory, the specific classification is as follows:

model ROM capacity (bytes) RAM capacity (bytes)
stm32f407xE 512K 192K
stm32f407xG 1024K 192K

This article uses the STM32F407VET6 chip, and the default memory configuration in the keil5 environment is shown in the figure below:

insert image description here

  • The ROM area starts from 0x8000000 and the size is 512K bytes.
  • The RAM area starts at 0x20000000 and has a size of 192K bytes.

Internal Flash Basics

The internal Flash is the ROM area of ​​the STM32 memory, and the data will not be lost when power is off . However, Flash is more important in STM32, and the program is also stored in this place, so it is easy to prevent users from reading and writing at will to avoid unnecessary problems.

The internal Flash module is composed as follows:
insert image description here

The erase function of the internal Flash is erased sector by sector.

3. Reading of internal Flash

The reading operation of the internal Flash is relatively simple, and the data can be read directly by addressing the pointer.
The specific code is as follows:

/**
 *@功能:从内部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); //读取数据
    }
}

4. Write the internal Flash

Before writing data into the internal Flash, it is necessary to judge whether the previous data is 0xFF. If it is not 0xFF, it needs to be erased to write new data correctly.

For example:
the last stored data is 0x52, and the next time the stored data is 0x01 directly.
If it is not erased, the data is written, and the result is read as 0x51.

Due to the erase operation of STM32F407, at least sector erase . Therefore, when we write data, we need to write a whole sector . We cannot write data to a sector multiple times, because the next write and erase will erase the previous data.

1. Specific operation steps

  1. Unlock Flash write protection.
  2. Erase Flash data.
  3. Write Flash data.
  4. Relock Flash write protection.

2. HAL library function

(1) Flash unlock and lock functions

HAL_FLASH_Unlock();    //解锁
HAL_FLASH_Lock();      //上锁

(2) Flash erase function

erase function

/*
功能:Flash擦除
参数1:擦除操作的配置信息
参数2:错误扇区的配置信息
*/
HAL_StatusTypeDef HAL_FLASHEx_Erase(FLASH_EraseInitTypeDef *pEraseInit, uint32_t *SectorError);

Configuration information for wipe operations

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;

(3) Flash write operation function

/*
功能:在指定地址写入数据
参数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);

(4) Flash waiting function

//等待FLASH操作完成
HAL_StatusTypeDef FLASH_WaitForLastOperation(uint32_t Timeout);

3. Specific procedures

#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();           //上锁
}

Guess you like

Origin blog.csdn.net/MQ0522/article/details/132623409