【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. 具体的な操作手順
- フラッシュ書き込み保護のロックを解除します。
- フラッシュデータを消去します。
- フラッシュデータを書き込みます。
- フラッシュ書き込み保護を再ロックします。
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(); //上锁
}