こんにちは。koraです。
前回までの投稿で迷路探索ができるようになりました。今回は迷路の壁情報をFlashメモリに書き込む方法についてまとめます。
マイコンのRAMに保存されている情報は電源を切ると消えてしまいますが、Flashメモリに保存しておけば電源を入れなおした後でも読み込むことができます。
STM32のFlashメモリの基本的な使い方は、idさんのブログを参考にさせていただきました。
STM32F7のFlashメモリについて
私のマウスはSTM32F7を使用しているので、公式のマニュアルを参照します。68ページ目にFlashのSector表が記載されていました。STM32F732には、全部で7つのSectorがあり、Sector 0~3は16Kbyte、Sector 4は64Kbyte、Sector 5~7は128Kbyteのサイズになっていることがわかります。
ただし、どのSectorでも自由に使えるというわけではなく、Sector 0にはシステムによって割り込みベクタテーブルが配置されるそうです。なので、Sector 1にマップデータ、Sector 2以降に実行プログラムが書き込まれるようにリンカスクリプトを編集します。
リンカスクリプト
STM32CubeMXとSW4STM32を使った環境では、プロジェクトディレクトリの直下にある.ldファイルがリンカスクリプトです。
MEMORYコマンド
リンカスクリプトではMEMORYコマンドでメモリ領域を定義しています。デフォルトではRAM領域とFLASH領域のみ定義されていますが、まずこの部分を変更します。
RAM領域はそのまま、新たにFLASH_SECTOR0とFLASH_SECTOR1を追加します。また、元のFLASH領域の開始アドレスをSector 0の0x80000000からSector 2の0x8008000に変更し、領域のサイズを512Kから480Kに変更します。
/* 変更前 */ /* Specify the memory areas */ MEMORY { RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 256K FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 512K }
/* 変更後 */ /* Specify the memory areas */ MEMORY { RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 256K FLASH_SECTOR0 (rx) : ORIGIN = 0x08000000, LENGTH = 16K FLASH_SECTOR1 (rx) : ORIGIN = 0x08004000, LENGTH = 16K FLASH (rx) : ORIGIN = 0x8008000, LENGTH = 480K }
SECTIONコマンド
次に以下のSECTIONSコマンドを変更します。
.isr_vectorは割り込みベクタテーブルを表していて、STM32CubeMXで生成されたコード内で定義されています。先ほどFLASH領域をSector 2~7に変更したので、割り込みベクタテーブルがSector 0に配置されるようFLASHをFLASH_SECTOR0に変更します。
.backup_flashが今回マップデータを保存するセクションです。これをFLASH_SECTOR1に配置します。また、_backup_flash_startという変数にこのセクションの開始アドレスを代入します。この変数は実際にFlashへ書き込む際に使用します。
/* 変更前 */ /* Define output sections */ SECTIONS { /* The startup code goes first into FLASH */ .isr_vector : { . = ALIGN(4); KEEP(*(.isr_vector)) /* Startup code */ . = ALIGN(4); } >FLASH /* 以下略 */
/* 変更後 */ /* Define output sections */ SECTIONS { /* The startup code goes first into FLASH */ .isr_vector : { . = ALIGN(4); KEEP(*(.isr_vector)) /* Startup code */ . = ALIGN(4); } >FLASH_SECTOR0 /* backup */ .backup_flash : { _backup_flash_start = .; . = . + LENGTH(FLASH_SECTOR1); } >FLASH_SECTOR1 /* 以下略 */
マップデータの書き込み・読み込み
大まかな流れは次の通りになります。ソースコードはidさんのものとだいたい同じになるのでここでは割愛します。
書き込みの流れ
- あらかじめRAM上にマップデータ受け渡し用の領域を確保しておく
- マップデータをRAM上の一時領域に展開
- HAL_FLASH_Unlock関数でFlashの制御を許可
- HAL_FLASHEx_Erase関数でFlash上の指定Sectorのデータを消去
- HAL_FLASH_Program関数でRAMに展開されたマップデータをFlashにコピー
- HAL_FLASH_Lock関数でFlashの制御をロック
読み込みの流れ
- memcpy関数でFlash上のデータをRAM上の領域にコピーする
- コピーしたメモリから、マップデータの構造体に落とし込む
おわり
これで探索後のマップデータを保存できるようになりました。電源を入れなおしても重ね探索や最短走行にトライできるので、かなり便利になりました。