gombeのブログ

マイコンの電子工作系PIC32/KiCad/C/C++/3D/

STM32 FLASHをEEPROM的に使う(2)

前回の続きです。STMのフラッシュを利用する時はロックを解除し一ページを消去、ブランクチェックの後に書き込みを実行、その後に照合をし、ロックをかけて完了でしたね。

今回はリンカスクリプトの解説をちょっとだけしたいと思います。リンカスクリプトとはマイコンのメモリアドレスの定義、エントリーポイントの設定などでしたね 。どのようなアドレスにどのような空間が広がっていてどこがどういう動作(r、wなど)ができるのかを定義するところでしたね。では早速リンカスクリプトの一部を出します。

[c] / Entry Point / ENTRY(Reset_Handler)

/ Highest address of the user mode stack / estack = 0x20005000; / end of RAM / / Generate a link error if heap and stack don't fit into RAM / Min_Heap_Size = 0x200; / required amount of heap / _Min_Stack_Size = 0x400; / required amount of stack /

/ Specify the memory areas / MEMORY { FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 128K RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K }

/ Define output sections / SECTIONS { / The startup code goes first into FLASH / .isr_vector : { . = ALIGN(4); KEEP((.isr_vector)) / Startup code */ . = ALIGN(4); } >FLASH

/ The program code and other data goes into FLASH / .text : { . = ALIGN(4); [/c]

今回使用したマイコンのフラッシュは128KiBです。ここから一ページ分の容量だけ利用したい場合、先頭を移動させるか後方を移動させます。今回は後方を1KiB減らします。で、どのように減らすのかはsizeを減らすだけです。

書き込み方は私はHALを使いました。メーカー純正の更新が続いているものを利用するといいでしょう。サンプルも豊富で利用者が少ないのが何故なのかよくわかりません。まあ癖があるのは納得だけどね。

[c] / * Created on: 2016/07/29 * Author: oishi /

include "MW_flash.h"

include <stdlib.h>

include <stdint.h>

static flashError_t MW_flashUnlock(void); static flashError_t MW_flashLock(void); static flashError_t MW_flashElase(/!erase here!/ const void *flash_add, size_t size);

static FLASH_EraseInitTypeDef elase_hand;

static flashError_t MW_flashElase(/!erase here!/ const void flash_add, size_t size){ /消去から。一ページ削除。周辺にコードを置かないようにリンカスクリプトを変更すること。*/ { uint32_t page_err; elase_hand.Banks = FLASH_BANK_1; elase_hand.TypeErase = FLASH_TYPEERASE_PAGES; elase_hand.NbPages = 1; elase_hand.PageAddress = (uint32_t)flash_add; if( HAL_FLASHEx_Erase(&elase_hand, &page_err) != HAL_OK ){ return MW_FLASH_ERASE_FAILURE; } }

{ uint32_t i; for( i = 0; i + 1 < size / 2; i++ ){ if(((const uint16_t*)flash_add )[i] != 0xFFFF ){ return MW_FLASH_ERASE_VERIFY_FAILURE; } } } return MW_FLASH_OK; }

static flashError_t MW_flashUnlock(void){ if( HAL_FLASH_Unlock() != HAL_OK ){ return MW_FLASH_UNLOCK_FAILURE; } return MW_FLASH_OK; }

static flashError_t MW_flashLock(void){ if( HAL_FLASH_Lock() != HAL_OK ){ return MW_FLASH_LOCK_FAILURE; } return MW_FLASH_OK; }

flashError_t MW_flashWrite(const void ptr, /!write here!/ const void flash_add, size_t size){ uint32_t address; flashError_t err;

err = MW_flashUnlock(); if( err != MW_FLASH_OK ){ return err; }

/消去から。一ページ削除。周辺にコードを置かないようにリンカスクリプトを変更すること。/ err = MW_flashElase(flash_add, size); if( err != MW_FLASH_OK ){ return err; }

address = (uint32_t)flash_add; for(; address + 1 < (uint32_t)flash_add + size; address += 2 ,ptr += 2){ if( HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, address, (const uint16_t)ptr) != HAL_OK ){ return MW_FLASH_WRITE_FAILURE; } if( (const uint16_t)ptr != (uint16_t)address ){ return MW_FLASH_WRITE_VERIFY_FAILURE; } }

err = MW_flashLock(); if( err != MW_FLASH_OK ){ return err; }

return EXIT_SUCCESS; } / MW_flashWrite /

[/c]

ヘッダも(;勘弁ください。めんどくさいです。

あと最後に注意点。コードを消去する際ページごとの消去です。当然ながらコードを破壊しないように一ページ分の大きさ(デバイスによっておおきくかわる)分だけ確保するのは怠らないように。また、確保してその分消去する前にバックアップもとると自由度が上がります。上記のコードにはそのようなコードはありません。また、ワードの境界にsize、アドレスがあるとエラーが発生します。ご注意くださいね。