はじめに
こんにちは、槇原です。前回はADCについて書いていました。今回はSTM32マイコンのフラッシュへのデータの書き込みについて書いていきます。
フラッシュの設定
今回利用しているマイコンは512KBのフラッシュが搭載されているSTM32G474CEU6です。STM32G47X/G48XはDBANKレジスタによってシングルバンクとデュアルバンクの切り替えを行うことができます。DBANKはデフォルトだと1でデュアルバンクの設定になっているので今回はこのままの設定を使います。もし修正する必要がある場合STM32CubeProgrammerなどで修正することができます。
リファレンスマニュアルでデュアルバンクの場合にメモリのアドレスがどのようになっているか確認することができます。今回は一番後ろの方のBank 2のPage126,127の4 KB分を利用します。
リンカスクリプトの修正
STM32G474CEUX_FLASH.ldを修正してプログラムを書き込む領域の一部をユーザーが使う領域として確保します。Bank 2のPage126のアドレスはメモリマップを見ると0x0807 F000であることが分かるのでこれを指定します。
元の状態は以下のようになっています。
/* Memories definition */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 512K
}
ビルドした際のBuild Analyzerのタブを確認するとRAMとFLASHの状態を確認することができます。
これを次のように修正します。MYDATAという名前のFLASH領域を確保します。アドレスの先頭をORIGINにデータ長はLENGTHで指定します。
/* Memories definition */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 508K
MYDATA (rx) : ORIGIN = 0x807F000, LENGTH = 4K
}
プログラム
フラッシュにデータを書き込む際は一度ページ単位で削除したのち新しいデータを書き込みます。
今回はBank2の127ページを削除します。データは1から0にすることしかできないため、データ削除時はすべてのビットを1にします。
データを書き換える際はHAL_FLASH_Unlock()、HAL_FLASH_Lock()でプロテクトを解除した状態で書き換え操作を行います。データ削除はFLASH_EraseInitTypeDefで消すページを指定してHAL_FLASHEx_Erase()で削除します。
uint32_t FlashEraseData(){
HAL_FLASH_Unlock();
FLASH_EraseInitTypeDef erase;
erase.TypeErase=FLASH_TYPEERASE_PAGES;
erase.Banks=FLASH_BANK_2;
erase.Page=127;
erase.NbPages=1;
uint32_t error=0;
HAL_FLASHEx_Erase(&erase, &error);
HAL_FLASH_Lock();
return error;
}
データ書き込みにはHAL_FLASH_Program()で書き込み単位とアドレス、データを引数にとって書き込みします。ここでは迷路データの配列をフラッシュに書き込むサンプルです。迷路データは8bitに一区画の情報を格納しています。書き込むデータは64bit単位で書き込むので一つの64bitのデータに8マス分のデータを入れてフラッシュに書き込みます。
const uint32_t start_addr=0x0807F800;
void FlashSetMazeData(int data[MAZESIZE_X][MAZESIZE_Y]){
FlashEraseData();
HAL_FLASH_Unlock();
int i=0;
for(int y=0;y< MAZESIZE_Y;y++){
uint64_t data64bit1=0;
uint64_t data64bit2=0;
for(int x=0;x<MAZESIZE_X;x++){
if(x<8)data64bit1|=(uint64_t)data[x][y]<<(8*(x));
else data64bit2|=(uint64_t)data[x][y]<<(8*(x-8));
}
HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, start_addr+1*(y*MAZESIZE_X), data64bit1);
HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, start_addr+1*(y*MAZESIZE_X)+8, data64bit2);
}
HAL_FLASH_Lock();
}
データの読み取りはmemcpyで直接メモリにアクセスします。
void FlashGetData(int maze_data[MAZESIZE_X][MAZESIZE_Y]){
uint8_t flash_data[MAZESIZE_X*MAZESIZE_Y];
memcpy(flash_data,(uint32_t*)start_addr,MAZESIZE_X*MAZESIZE_Y);
for(int y=0;y<MAZESIZE_Y;y++){
for(int x=0;x<MAZESIZE_X;x++){
maze_data[x][y]=flash_data[x+y*MAZESIZE_X];
}
}
}
これによって迷路データをフラッシュに保存して、クラッシュなどによってマウスの電源を切っても迷路データを保持することができます。