STM32 内蔵フラッシュメモリへのデータ保存

HALライブラリを利用し、STM32の内蔵フラッシュメモリへデータを保存します。これにより電源を切ってもデータを残したままにすることができます。下記参考ページにも詳細な内容がありますので、併せてご参照ください。
STM32 + HAL Flashの書き込み・読み込み



フラッシュメモリへのデータ保存時には、単純に書き込み関数を呼び出せばよいわけではなく、あらかじめ書き込む場所を消去しておく必要があります。さらに、消去等の操作前にはロックを解除しなければいけません。つまり下記の流れとなります。
・ロック解除→消去→書き込み→再度ロック

フラッシュメモリはセクタという単位に分割されており、消去操作時にはセクタごとに消去します。STM32F401REのセクタ7の場合、フラッシュメモリの終わり側128kB分が全て消えることになります。

<STM32F4、F7での書き込みサンプルコード>
テストとして配列を書き込みます。NUCLEO-F401REで動作確認しました。セクタの開始アドレスはそれぞれのICのリファレンスマニュアルをご確認ください。
const uint32_t flash_addr = 0x08060000; // データ保存先(セクタ7)開始アドレス
uint16_t testData[8] = {1, 3, 5, 7, 2, 4, 6, 8}; // 書き込むデータ

void saveData()
{
/* フラッシュ ロック解除 */
HAL_FLASH_Unlock();

/* フラッシュ 消去 */
FLASH_EraseInitTypeDef erase; // 消去に関する構造体を定義
uint32_t error = 0; // エラーコードを格納する変数
erase.TypeErase = FLASH_TYPEERASE_SECTORS; // 消去方法: セクタ消去
erase.Sector = FLASH_SECTOR_7; // 消去するセクタ: セクタ7
erase.NbSectors = 1; // 消去するセクタの数: 1
erase.VoltageRange = FLASH_VOLTAGE_RANGE_3; // 電圧設定
HAL_FLASHEx_Erase(&erase, &error); // 消去

/* フラッシュ 書き込み */
uint32_t addr = flash_addr; // 書き込み先アドレスを代入
for (int i = 0; i < 8; i++)
{
HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, addr, testData[i]); // 書き込み
addr += 2; // 2バイト(16ビット)分アドレスを進める
}

/* フラッシュ ロック */
HAL_FLASH_Lock();
}
今回は16ビットのデータを書き込んでいますが、8ビットであれば「FLASH_TYPEPROGRAM_BYTE」を使い、アドレスは1バイトずつ進めます(32ビットであれば「FLASH_TYPEPROGRAM_WORD」を使い、アドレスは4バイトずつ進めます)。

<データ読み出し>
保存したデータを読み出す場合は特別な操作は必要なく、下記のように記載します。
uint32_t addr = flash_addr;
testData[0] = *((uint16_t*)addr);
「(uint16_t*)」で書き込み先アドレスをポインタ型へキャストし、そのポインタ(アドレス)にあるデータを「*」で読み出しています。何も書き込まれていない場合は、ビットが全て1のデータ(uint16_tなら65535)が読み出されます。



<STM32H7での書き込みサンプルコード>
セクタの他にバンク1と2があるため、バンク指定が追加になっています。また、書き込みはFLASHWORD(256ビット)単位限定で、256ビットのデータを準備しなければいけないようです。データ読み出しについては上記と同じです。NUCLEO-H743ZI2で動作確認しました。
const uint32_t flash_addr = 0x081E0000; // データ保存先(バンク2 セクタ7)開始アドレス
uint16_t testData[16] = {1, 3, 5, 7, 2, 4, 6, 8, 9, 7, 5, 3, 0, 8, 6, 4}; // 書き込むデータ

void saveData()
{
/* フラッシュ ロック解除 */
HAL_FLASH_Unlock();

/* フラッシュ 消去 */
FLASH_EraseInitTypeDef erase; // 消去に関する構造体を定義
uint32_t error = 0; // エラーコードを格納する変数
erase.TypeErase = FLASH_TYPEERASE_SECTORS; // 消去方法: セクタ消去
erase.Banks = FLASH_BANK_2; // 消去するバンク: バンク2
erase.Sector = FLASH_SECTOR_7; // 消去するセクタ: セクタ7
erase.NbSectors = 1; // 消去するセクタの数: 1
erase.VoltageRange = FLASH_VOLTAGE_RANGE_3; // 電圧設定
HAL_FLASHEx_Erase(&erase, &error); // 消去

/* フラッシュ 書き込み */
uint32_t addr = flash_addr; // 書き込み先アドレスを代入
HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, addr, (uint32_t)testData); // 書き込み
addr += 32; // 続けて他のデータを書き込む場合は32バイト(256ビット)分アドレスを進める

/* フラッシュ ロック */
HAL_FLASH_Lock();
}



<リンカスクリプトについて>
内蔵フラッシュメモリにはプログラムが書き込まれています。万が一大きなプログラムとなった場合には、データ保存したいフラッシュ領域と重なってしまうおそれがあります。そこで、プログラムの領域とデータ保存の領域を分けておきます。

STM32CubeIDEのプロジェクトフォルダ内に、リンカスクリプトと呼ばれるSTM32○○○○_FLASH.ldというファイルがあります。このファイル内のMEMORYの記述を変更すればOKです。例えばSTM32F401REのセクタ7(開始アドレス0x08060000)をデータ保存領域(DATA)とする場合は下記の記述とします。
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 96K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 384K
DATA (rx) : ORIGIN = 0x08060000, LENGTH = 128K
}

タグ : マイコン 

コメントの投稿

非公開コメント

管理人

管理人

自己紹介のページ
記事一覧
Twitter
GitHub

ブログ内検索
カテゴリー
タグ

自作エフェクター   レイアウト   回路図   歪み   周波数特性   マイコン   PureData   波形・倍音   RaspberryPi   エレキギター   アンプ   歪率   エフェクター自作方法   エレキベース   真空管   コーラス   ピックアップ   静音ギター   ヘッドフォンアンプ   擬似ギター出力   市販エフェクター   アコースティックギター   ブースター   コンデンサ   ソロギター   ポールピース   イコライザー   コンプレッサー   ビブラート   フェイザー   トレモロ   TAB譜   ディレイ   DIY_Layout_Creator   ワウ   オートワウ   バッファー   

最近の記事
最新コメント
Twitter
RSS
メールフォーム
当ブログに関するお問い合わせはこちらからお願いします。 ※FAQ(よくある質問)もお読みください。

お名前
メールアドレス
件名
本文

アクセスカウンター