要約:このアプリケーションノートでは、内蔵のユーティリティROMを使用してMAXQ7665マイクロコントローラ(µC)のプログラムとデータフラッシュの消去/書込みを行う方法について説明します。この情報は、セクタ消去可能な(SE)フラッシュを備えたMAXQ7665フラッシュベースのマイクロコントローラ(µC)にのみ適用されます。
はじめに
このアプリケーションノートでは、セクタ消去可能な(SE)フラッシュメモリを備えたMAXQ7665フラッシュベースのマイクロコントローラ(µC)における内部データとプログラムフラッシュの管理方法について説明します。この説明には、プログラムフラッシュのインアプリケーションプログラミング(IAP)を実行するための一般的な情報が含まれます。
メモリマップ
この項では、一般的なフラッシュの情報、およびMAXQ7665デバイスのさまざまなメモリサイズについてのメモリ構成について詳しく説明します。MAX7665デバイスでは、2種類のフラッシュメモリが利用可能です。このアプリケーションノートではSEフラッシュを備えたMAXQ7665デバイスのみを扱い、ページ消去可能な(PE)デバイスは対象としていません。MAXQ7665 PEデバイスの情報については、アプリケーションノート「MAXQ7665のページ消去可能な(PE)プログラム/データフラッシュのインアプリケーションプログラミング(IAP)」を参照してください。
表1は、128KB、64KB、48KB、および32KBの各デバイスのフラッシュメモリマップを示しています。これ以外のフラッシュオプションもあります。全リストについてはMAXQ7665データシートを参照してください。
表1. フラッシュメモリマップ

フラッシュを使用してデータを保存
フラッシュを使用すると、システムの動作中に一度だけ、または定期的にプログラムする必要のあるシステムデータを確実に保存することができます。フラッシュの任意のセクタを使用してデータを保存することができますが、通常4K x 16の2セクタが最も用途に適しています。EEPROMとは異なり、MAXQ7665上のフラッシュはワード消去することができません。一度にセクタ全体を消去する必要があります。通常、セクタを消去するのに約0.7秒かかりますが、ワーストケースの状態では15秒もかかることがあります。この間、ユーザコードは停止状態となるため、その他の処理を行うことはできません。システム要件に適したソフトウェア手法を選択するときには、これらの制限を慎重に考慮する必要があります。定期的にデータの保存が必要なニーズでは、ほとんどの場合、有界キューやバンク切替の手法によってシステムの信頼性要件を満たすことができます。バンク切替と有界キューの手法の簡単な例を以下に示します。
有界キュー
有界キューとは、一定の項目数によって制限されるキューのことです。この手法は通常、定期的にデータを処理するときに必ず使用されます。たとえば、4K x 16のフラッシュセクタは、64ワードの64エントリに分割することが可能であるため、結果として、128kBの製品の場合、表2のようなメモリマップになります。
初期化後、起動ルーチンでは、キュー内の次に利用可能なエントリを決定するために、キューエントリをスキャンすることができます。キューがいっぱいになると、他のエントリを書き込む前にキューを消去する必要があります(注:すべてのエントリを必要とする場合は、バンク切替も使用してすべてのデータを維持する必要があります)。フラッシュの消去が完了すれば、新しいエントリを書き込むことができます。この手法の欠点は、消去処理中に電源がオフになると、すべてのデータが失われる可能性があるということです。有界キューの手法を使用してシステム要件が満たされない場合、バンク切替も必要となります。
図1は、有界キュー内のエントリのフローを示しています。
簡単なCのソースコード例については、付録Aを参照してください。
表2. 有界キューのメモリマップの例
| FLASHQueue[ ] |
| Queue Index |
Data Flash Address |
| 63 |
0xFFC0-0xFFFF |
| 62 |
0xFF80-0xFFBF |
| 61 |
0xFF40-0xFF7F |
| . . . . |
. . . . |
| 2 |
0xF080-0xF0BF |
| 1 |
0xF040-0xF07F |
| 0 |
0xF000-0xF03F |

図1. 有界キューのフロー
バンク切替
バンク切替は、長いセクタ消去サイクル間のデータの消失や破損を防止する効果的な方法です。この方法は、セクタサイズが合計データサイズよりわずかに大きいときに有効に機能します。バンク切替のマイナス点は、少なくとも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つのセクタ間での、有界キューのデータのフローを示します。
この2つを併用する手法のコーディングは、有界キューだけの場合に比べて、少しだけ複雑です。簡単なCのソースコード例については、付録Aを参照してください。
表4. 有界キューのメモリマップの例
| FQueueBank0[ ] |
| Queue Index |
Data Flash Address |
| 63 |
0xFFC0-0xFFFF |
| 62 |
0xFF80-0xFFBF |
| 61 |
0xFF40-0xFF7F |
| . . . . |
. . . . |
| 2 |
0xF080-0xF0BF |
| 1 |
0xF040-0xF07F |
| 0 |
0xF000-0xF03F |
| FQueueBank1[ ] |
| Queue Index |
Data Flash Address |
| 63 |
0xEFC0-0xEFFF |
| 62 |
0xEF80-0xEFBF |
| 61 |
0xEF40-0xEF7F |
| . . . . |
. . . . |
| 2 |
0xE080-0xE0BF |
| 1 |
0xE040-0xE07F |
| 0 |
0xE000-0xE03F |

図3. 有界キューとバンクスイッチのフロー
ユーティリティROMのフラッシュルーチン
MAXQ7665マイクロコントローラには、フラッシュのプログラミング、消去、および検証のため、ROM (読取り専用メモリ)内にオンチップフラッシュのサポートルーチンが用意されています。これらのルーチンにアクセスするには、2つの方法があります。第1の方法、かつ最速の方法である直接アクセスは、ルーチンをじかに呼び出します。これを実行するには、以下に示す行にヘッダファイルを設けます。
u16 flashEraseSector(void *);
u16 flashEraseAll(void);
u16 flashWrite(void *pAddress, u16 iData);
次に、リンカ定義を追加して、各ルーチンに適切なアドレスを割り当てますIARリンカのファイルの場合、追加された行は、次のようになります。
-DflashEraseSector=0x8XXX
-DflashEraseAll=0x8XXX
-DflashWrite=0x8XXX
ルーチンごとに0x8XXXを適切なメモリアドレスに置き換えます。他のコンパイラは、これらのリファレンスを追加するのに別の手法を使用する場合があります。
注:直接アクセス手法では、今後のROMバージョンとの上位互換性は確保されません。
第2の方法の間接アドレス指定では、テーブルルックアップを使用します。この手法は、今後のROMバージョンとの互換性に優れていますが、実行時間が長くなります。以下の各ルーチンの記述の後、アセンブリルーチンは、テーブルルックアップ方法を使用して、ROMユーティリティルーチンのアドレスを取得します。表5は、ユーティリティROMが供給するフラッシュルーチンを示します。ROMユーティリティルーチンの全体リストについては、マキシムのウェブサイトにあるMAXQ7665のユーザガイドを参照してください。
表5. フラッシュユーティリティのROMルーチン
| Routine Number |
Routine Name |
Entry Point ROMTable = ROM[800Dh] |
Entry Point Physical Address |
| 2 |
flashEraseSector |
ROM[ROMTable + 1] |
0x8XXX |
| 3 |
flashEraseAll |
ROM[ROMTable + 2] |
0x8XXX |
| 15 |
flashWrite |
ROM[ROMTable + 14] |
0x8XXX |
flashWrite
| ルーチン: |
u16 flashWrite(void *pAddress, u16 iData) |
| 要約: |
フラッシュメモリの単一ワードをプログラムします。 |
| 入力: |
A[0]—書き込むフラッシュメモリのワードアドレス A[1]—フラッシュメモリに書き込むワード値 |
| 出力: |
キャリー:エラー時にセットされ、成功時にクリアされます。セットされた場合、A[0]には、以下のエラーコードの1つが含まれます。
1: ソフトウェアのタイムアウトによる失敗
2:ハードウェアによって報告される失敗(DQ5/FERR)
4:サポートされていないコマンド
SW_FERR—エラー時にセットされ、成功時にクリアされます。 |
| 注: |
ウォッチドッグを有効にしないでください。あるいはウォッチドッグのタイムアウトを十分に長く設定することによって、リセットが起動されることなくこのルーチンが完了するようにしてください。 |
以下のアセンブリコードの例では、間接アドレス指定の手法(ルックアップテーブル)を使用してflashWrite()ユーティリティルーチンを呼び出しています。このルーチンはCコードで呼び出されます。
; 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].
flashEraseSector
| ルーチン: |
u16 flashEraseSector(void *pAddress) |
| 要約: |
フラッシュメモリの単一セクタを消去します。 |
| 入力: |
A[0]—消去するセクタに位置付けられたアドレス |
| 出力: |
キャリー:エラー時にセットされ、成功時にクリアされます。セットされた場合、A[0]には、以下のエラーコードの1つが含まれます。
1:ソフトウェアのタイムアウトによる失敗
2:ハードウェアによって報告される失敗(DQ5/FERR)
4:サポートされていないコマンド
SW_FERR—エラー時にセットされ、成功時にクリアされます。 |
| 注: |
|
|
ウォッチドッグを有効にしないでください。あるいはウォッチドッグのタイムアウトを十分に長く設定することによって、リセットが起動されることなくこのルーチンが完了するようにしてください。 |
; 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]
flashEraseAll
| ルーチン: |
void flashEraseAll(void) |
| 要約: |
ブートローダセクタを含む、すべてのプログラムとデータのフラッシュメモリを消去します。このルーチンは通常、IAPでは使用されません。消去/プログラミングのシーケンスが中断されないことを確実に保証する必要があるからです。 |
| 入力: |
なし |
| 出力: |
キャリー:エラー時にセットされ、成功時にクリアされます。 SW_FERR—エラー時にセットされ、成功時にクリアされます。 |
| 注: |
ウォッチドッグを有効にしないでください。あるいはウォッチドッグのタイムアウトを十分に長く設定することによって、リセットが起動されることなくこのルーチンが完了するようにしてください。 |
; 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
インアプリケーションプログラミング(IAP)
フラッシュを用いたほとんどのシステムで重要となる要件は、システムが最終製品にインストールされている間にファームウェアをアップデートする機能です。これは、インアプリケーションプログラミング(IAP)と呼ばれます。この項では、IAPアプリケーションを作成するための一般的なガイドラインの概要を説明します。
上述のユーティリティROMフラッシュのルーチンがフラッシュROMの消去と書込みに必要なすべての動作を実行します。これによって、エンドユーザのアプリケーションがフラッシュメモリに対する操作を行えるようになります。他のサブルーチンの呼出しと同様、ルーチンが完了すると制御はエンドユーザのコードに戻ります。
MAXQ7665のセクタ消去のみのバージョンに対して、IAPシーケンスを実行するときには、専用のブートローダフラッシュセクタが存在しないため注意が必要です。完全なフォルト耐性を備えたIAPを設計するには、ブートローダアプリケーションをメインのアプリケーションから分離する必要があります。こうすることで、再プログラミングシーケンスが完了しなかった場合に再プログラミング手順を確実に再試行することができるようになります。IAPが再プログラミングシーケンス中の停電などの障害に対して、耐性を備える必要がある場合は、ページ消去機能を備えたMAXQ7665を選択してください。これによって、ブートローダアプリケーションは0x0000 (リセットエントリポイント)で起動し、メインアプリケーションコードから完全に分離されます。完全なフォルト耐性を備えたIAPを必要としないアプリケーションの場合、IAPはRAMベースのリフラッシュルーチンを使用して実現することができます。
RAMベースのフラッシュルーチンを使用するIAP
RAMベースのフラッシュルーチンは、障害の回復が必要でないときの、MAXQ7665のリフラッシュに使用することができます。この方法では、メインアプリケーションが、再配置可能な小さなフラッシュプログラミングルーチンをRAMにコピーし、次にそのルーチンにジャンプすることが必要となります。RAMからコードを実行するときには、考慮すべきいつくかの制限事項があります。
表6. RAMからコードを実行するときの制限事項
| |
| SC.UPAは、RAMベースのルーチンを実行する前に0に設定する必要があります。これは、アプリケーションがコードセグメントP0およびP1からRAMルーチンにジャンプする必要があることを意味します。 |
| RAMはデータおよびプログラムとして同時にアクセスすることはできません。これは、レジスタおよびハードウェアスタックのみがデータストレージに使用可能であることを意味します。 |
| 割込みがイネーブルされる場合は、割込みベクトルはRAMルーチンを指し示す必要があります。通常は、RAMリフラッシュルーチンはシンプルであるため、割込みはオフになり、ポーリングが使用されます。 |
標準では、フラッシュルーチンは、UARTまたはCANインタフェースのいずれかを用いて通信します。より強固なエラー回復メカニズムを実現するには、通常、小さなデータパケットを受信し、ACKを送信することが最良です。図4は、リフラッシュルーチンの動作を示したフローチャートです。停電が発生する前に再プログラミングが成功しなければ、JTAGポートを通じてマイクロコントローラの再プログラミングが必要になります。

図4. RAMリフラッシュルーチンの簡易フローチャート
付録A:コード例
 ダウンロード(DOC 53.5kB)
フィードバックをお寄せください。 内容に満足されましたか、あるいは満足されていませんか?もっと良いページにできると思いますか?あるいは、単なるコメントでも結構です。フィードバックをお待ちしています。—マキシムはお客様からいただく訂正、提案を元に改善していきます。
このページを評価し、フィードバックを送信する。
自動アップデート
お客様が関心のある分野でアプリケーションノートが新規に掲載された際に自動通知Eメールの受信を希望する場合は、EE-Mail™にご登録ください。
|