フラッシュを使用すると、システムの動作中に一度だけ、または定期的にプログラムする必要のあるシステムデータを確実に保存することができます。フラッシュの任意のセクタを使用してデータを保存することができますが、通常4K x 16の2セクタが最も用途に適しています。EEPROMとは異なり、MAXQ7665上のフラッシュはワード消去することができません。一度にセクタ全体を消去する必要があります。通常、セクタを消去するのに約0.7秒かかりますが、ワーストケースの状態では15秒もかかることがあります。この間、ユーザコードは停止状態となるため、その他の処理を行うことはできません。システム要件に適したソフトウェア手法を選択するときには、これらの制限を慎重に考慮する必要があります。定期的にデータの保存が必要なニーズでは、ほとんどの場合、有界キューやバンク切替の手法によってシステムの信頼性要件を満たすことができます。バンク切替と有界キューの手法の簡単な例を以下に示します。
有界キュー
有界キューとは、一定の項目数によって制限されるキューのことです。この手法は通常、定期的にデータを処理するときに必ず使用されます。たとえば、4K x 16のフラッシュセクタは、64ワードの64エントリに分割することが可能であるため、結果として、128kBの製品の場合、表2のようなメモリマップになります。
バンク切替は、長いセクタ消去サイクル間のデータの消失や破損を防止する効果的な方法です。この方法は、セクタサイズが合計データサイズよりわずかに大きいときに有効に機能します。バンク切替のマイナス点は、少なくとも2つのデータフラッシュのセクタを必要とするということです。書き込むデータサイズの合計がセクタサイズよりかなり小さいときの最良の手法は、バンク切替と有界キューの方法を組み合わせることです。アプリケーションでバンク切替を必要とする場合、MAXQ7665の4K x 16の2つのフラッシュセクタをデータストレージとして使用することができます。
表3は、2つの4K x 16フラッシュセクタを使用するときのメモリマップの例を示します。図2は、バンクスイッチの書込み/消去のフローを示しています。
簡単なCのソースコード例については、付録Aを参照してください。
表3. バンク切替のメモリマップの例
Flash Sectors
Sector Number
Data Flash Address
0
0xF000-0xFFFF
1
0xE000-0xEFFF
図2. バンク切替のフロー
有界キューとバンク切替
有界キューとバンク切替を併用する方法は、最も確実で柔軟性のある手法です。この組み合わせが有効に機能するのは、少量のデータを定期的にフラッシュに保存する必要があって、データの完全性を維持する必要があるときです。表4に、64等分のエントリに分割された2つの4K x 16セクタを使用するメモリマップの例を示します。図3は、2つのセクタ間での、有界キューのデータのフローを示します。
; This routine is callable by C code using the following prototype
; u16 flashWrite(void *pAddress, u16 iData);
;
flashWrite:
move APC, #0 ; No auto inc/dec of accumulator.
move DP[0], #0800Dh ; This is where the address of the table is
; stored.
move ACC, @DP[0] ; Get the location of the routine table.
add #14 ; Add the index to the flashWrite routine.
move DP[0], ACC
move ACC, @DP[0] ; Retrieve the address of the routine.
call ACC ; Execute the routine.
ret ; Status returned in A[0].
; This routine is callable by C code using the following prototype
; u16 flashEraseSector(void *pAddress);
;
flashEraseSector:
move APC, #0 ; No auto inc/dec of accumulator.
move DP[0], #0800Dh ; This is where the address of the table is
; stored.
move ACC, @DP[0] ; Get the location of the routine table.
add #1 ; Add the index to the flashEraseSector routine.
move DP[0], ACC
move ACC, @DP[0] ; Retrieve the address of the routine.
call ACC ; Execute the routine.
ret ; Status returned in A[0]
; This routine is callable by C code using the following prototype
; void flashEraseAll(void);
;
flashEraseAll:
move APC, #0 ; No auto inc/dec of accumulator.
move DP[0], #0800Dh ; This is where the address of the table is
; stored.
move ACC, @DP[0] ; Get the location of the routine table.
add #2 ; Add the index to the flashEraseAll routine.
move DP[0], ACC
move ACC, @DP[0] ; Retrieve the address of the routine.
call ACC ; Execute the routine.
ret