【HALライブラリ】STM32F407---内蔵フラッシュの読み書き

【HALライブラリ】STM32CubeMX開発----STM32F407----目次


1. STM32 メモリの概要

STM32 メモリは次の 2 種類に分類されます。

1. ランダム アクセス メモリ - RAM

  • RAMはCPUと直接データをやり取りする内部メモリで、メインメモリ(メモリ)とも呼ばれます。
  • いつでも読み書きでき、速度も非常に速いため、通常はオペレーティング システムやその他の実行中のプログラムの一時的なデータ記憶媒体として使用されます。
  • RAM は電源を切るとデータを保持できない(電源オフ時のデータが消えてしまう)ため、データを保存する必要がある場合は、長期記憶装置(ハードディスクなど)に書き込む必要があります。

2. 読み取り専用メモリ - ROM

  • ROM に保存されているデータは、通常、マシン全体にロードされる前に事前に書き込まれ、迅速かつ便利に書き換えることができるランダム アクセス メモリとは異なり、マシン全体の作業プロセス中にのみ読み出すことができます。
  • ROM に保存されているデータは安定しており、電源を切っても保存されたデータは変化しません。

2. STM32F407シリーズメモリの紹介

記憶によれば、具体的な分類は次のとおりです。

モデル ROM容量(バイト) RAM容量(バイト)
stm32f407xE 512K 192K
stm32f407xG 1024K 192K

この記事では STM32F407VET6 チップを使用しており、keil5 環境のデフォルトのメモリ構成を次の図に示します。

ここに画像の説明を挿入

  • ROM 領域は0x8000000 から始まり、サイズは 512K バイトです。
  • RAM 領域は0x20000000 から始まり、サイズは 192K バイトです。

内蔵フラッシュの基本

内部フラッシュは STM32 メモリの ROM 領域であり、電源がオフになってもデータが失われることはありませんが、STM32 ではフラッシュの方が重要であり、プログラムもこの場所に保存されているため、不必要な問題を避けるために、ユーザーが自由に読み書きできないようにします。

内部フラッシュモジュールは次のように構成されています。
ここに画像の説明を挿入

内蔵フラッシュの消去機能はセクタごとに消去されます。

3. 内蔵フラッシュの読み出し

内蔵フラッシュの読み取り動作は比較的簡単で、ポインタをアドレス指定することでデータを直接読み取ることができます。
具体的なコードは次のとおりです。

/**
 *@功能:从内部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. 内蔵フラッシュへの書き込み

内蔵 Flash にデータを書き込む前に、前のデータが 0xFF であるかどうかを判定する必要があり、0xFF でない場合は、新しいデータを正しく書き込むために、そのデータを消去する必要があります。

例:
最後に保存されたデータは 0x52 で、次回保存されるデータはそのまま 0x01 になります。
消去されていない場合はデータが書き込まれ、結果は 0x51 として読み取られます。

STM32F407 の消去動作により、少なくともセクタ消去が行われますしたがって、データを書き込むときは、セクター全体に書き込む必要がありますが、次の書き込みと消去によって前のデータが消去されるため、1 つのセクターにデータを複数回書き込むことはできません。

1. 具体的な操作手順

  1. フラッシュ書き込み保護のロックを解除します。
  2. フラッシュデータを消去します。
  3. フラッシュデータを書き込みます。
  4. フラッシュ書き込み保護を再ロックします。

2. HALライブラリ関数

(1) フラッシュのロック解除・ロック機能

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

(2) フラッシュ消去機能

消去機能

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

ワイプ操作の構成情報

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) フラッシュ書き込み動作機能

/*
功能:在指定地址写入数据
参数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操作完成
HAL_StatusTypeDef FLASH_WaitForLastOperation(uint32_t Timeout);

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

おすすめ

転載: blog.csdn.net/MQ0522/article/details/132623409