2018年8月14日火曜日

Flashの配置


FlashをMSCに使うとして、どういう配置にするか、ちょっと考えてみた。

 STM32F405は1バンクあたり128KiB(Flashの後半の場合)なので、この領域をうまく使えればいい。
 とりあえず、1セクタ512バイトに分割すると、1バンクあたり256セクタになる。この内、最初の1セクタを管理領域として使うと、1バンクあたり255セクタのデータ領域となる。
 最初は1バンク全体が0xFFで初期化されている。データを書き込みたい場合、管理領域からidxが0xFFFFになっている場所を探す。0xFFFFが見つかれば、その場所にデータを書き込み、また管理領域にそこに書き込んだセクタ番号を書き込む。
 読み出す場合は、管理領域の最後から前に戻りながら目的のセクタ番号を探し、見つかればその場所のデータを返す。

 同じバンクに上書きしたい場合は、空いているところに書き込むので、後に書き込んだデータが後ろにくる。そのため、読み出し時に後ろから探せば一番新しいデータを見つけることができる。

 書き込める場所がなくなった場合は別のバンクに転送する必要がある。
 後ろから読み出していくのは同じだが、別のバンクに書き込む前に、再び後ろ向きに捜索し、そのセクタが最新であることを確認する。
 別バンクへの移動が終わったら、古いバンクはイレースし、全体を0xFFで埋める。

 使用中のバンクの識別は、管理領域の最初のバンクのバンク番号を確認することで行える。イレースしてしまえば0xFFFFになるので、そのバンクは未使用とわかるし、そのセクタを使うときは必ず最初のバンクから使うので、使えば0xFFFF以外の値が書き込まれる。

 バンク番号0xFFFFはマジックナンバーとして使うが、それでも0x0000から0xFFFEまでは使えるので、32M-512byteまで使用できる。マイコンのFlashが最大1Mなので、実際は多くても256KiB程度だろうから、十分に余裕がある。

 この方法の場合、特定のアドレスだけが早く消耗することがない、というのも利点。1つのセクタを書き込めば、そのバンクが埋まるまではそのセクタが再利用されることは無い。また、少なくとも2つのバンクを交互に使うので、2つのバンクが均等に消耗される。
 ただし、複数のバンクを使う場合、例えばMSCの容量を128KiB以上にする場合は、バンク間の平均化はかなり難しい。(このバンクが何回書き込まれたか、をどうやって管理するかが問題)。
 また、読み込み・書き込み共にある程度のスキャンが必要なので、実行時間が固定じゃないのも問題か。それでも16bit変数256個読むだけなので、ミリ秒レベルはかからないはず。

 もっとも、平均化の問題は、STM32のFlashは書き込み回数が最小1万回保証なので、そこまで気にする必要もないのかもしれないが。
 reserveの16bit領域を使えば、何回書き込んだか(=何回イレースしたか)を記録できるから、6万回程度までならイレース回数が一番小さいバンクに書き込む、といった工夫ができる。Flash書き換えが1万回程度だから、16bitで管理できれば十分。

***

 何をやりたいかというと、mbedのように、MSCでプログラムをマイコンに入れたい、と思っている次第。そして、そのプロプログラムは機械語コードではなく、Luaスクリプトを想定している。
 例えば、ちょっとしたLEDの点滅だったりといった、簡単な処理を行うのであれば、Luaでも用は足りるはず。そして、Luaスクリプトであれば128KiBもあれば十分に転送できるはず。
 以前、C#とLuaで図形を印刷するプログラムを作ったが、その時に作ったAIM-120のペーパークラフトのLuaコードは約1160行で35KiBだった。単純に考えれば、128KiBあれば4000行くらいのLuaコードを実行できる。関数名や変数名をケチったり、インデントをケチったりすればもっと多くの処理ができるかもしれない。それでも足りないようであれば、PC側でバイトコードに変換してしまうという手もある。
 とにかく、スクリプトを入れるだけなら大容量のメモリは必要ないはず。
 ただ、スクリプトを走らせるにはRAMがかなり必要で、特にフラグメンテーションが大変そうな感じ。

 プラモデルの電飾とか、作ったら面白いんじゃないかなぁと思っているんだが。2年くらい前から考えてるんだが全く進まない。
 ウイングスパン2mくらいのB787のラジコン飛行機とか作って、電飾したら楽しいだろうなぁ。

追記
 PCで簡単に試してみた。


 ヒープ領域から256KiB確保してFlashと想定し、いろいろ処理した後にバイナリファイルで書き出して画像化。黒は00h、白はFFhの領域。

 上半分の、128KiB-512byteをFatFsで使うようにして、f_mkfsでファイルシステムを作ってる。
 適当に30個ほどファイルを作るとトータルで234セクタを使用し、内93セクタは重複した(古い部分は捨てて良い)セクタ。
 下半分は、上半分から重複を省いてコピーした部分。全体で141セクタを使用して、重複はゼロ。

 ということで、なんとか動きそうな雰囲気はしてきた。実際にマイコンでどれくらいパフォーマンスが出るか。。


追記
 試しにUSB Dev MSCで、WriteとReadを処理するプログラムを書いてみた。
 最初は全体が0xFFで初期化されているので、ファイルシステムはなにもない。なのでWinからはフォーマットの催促が来る。
 で、フォーマットするとマイコンがハングアップしてしまう。Flash書き込みでコケてるっぽい。
 同じようなコードで、適当なFreeRTOSタスクからFlashへの書き込みを試したら、ちゃんと書き込める。
 もしかしたらISRの中からはFlash書き込みは不可? 有り得そうなシナリオ。(←誤解でした)
 USB MSCちょーめんどくさい。

 とりあえず適当なバッファを作っておいて、Write要求ではバッファに突っ込んでOKを返して、RTOSタスクでバッファからFlashへ転送、という感じか。

 あと、Flashが0xFFの領域に、0x7Fを書き込み、その後に同じ場所に0x3Fを書き込むと、ちゃんと0x3Fとして書き込まれてる。ということで、bit clear操作は可能で、bit set操作が不可、ということなのだろう。
 例えば管理領域を0x0001-0x7FFFの範囲で使って、そのセクタが不要になった場合(Trimとか)は、管理領域を0x0000にクリアする、みたいな使い方はできそう。
 もっとも、CubeMXのUSB MSCではTrimはなさそうだが。

 とりあえず、明日、気が向いたらRTOS taskでFlashを書き換えるようなのを試してみる。

0 件のコメント:

コメントを投稿