MAXQ7665のページ消去可能な(PE)プログラム/データフラッシュのインアプリケーションプログラミング(IAP)

要約

このアプリケーションノートでは、内蔵のユーティリティROMを使用してMAXQ7665マイクロコントローラ(µC)のプログラムとデータフラッシュの消去/書込みを行う方法について説明します。この情報は、ページ消去可能な(PE)フラッシュを備えたMAXQ7665フラッシュベースのµCに適用されます。

はじめに

このアプリケーションノートでは、ページ消去可能な(PE)フラッシュメモリを備えたMAXQ7665フラッシュベースのマイクロコントローラ(µC)における内部データとプログラムフラッシュの管理方法について説明します。この説明には、プログラムフラッシュのインアプリケーションプログラミング(IAP)を実行するための一般的な情報が含まれます。

メモリマップ

この項では、一般的なフラッシュの情報、およびMAXQ7665µCファミリのさまざまなメモリサイズについてのメモリ構成について詳しく説明します。MAX7665デバイスでは、3種類のフラッシュメモリが利用可能です。すなわち、セクタ消去、単一ワード消去、および2ページ消去です。このアプリケーションノートでは、2ページ消去のデータフラッシュのPEフラッシュを備えたMAXQ7665デバイスのみを説明しています。この説明は、セクタ消去のみのデバイスや単一ワードの消去が可能なデータフラッシュを備えたデバイスには適用されません。MAXQ7665セクタ消去可能な(SE)デバイスの情報については、アプリケーションノート3575「MAXQ7665のセクタ消去可能なプログラム/データフラッシュのインアプリケーションプログラミング(IAP)」を参照してください。単一ワード消去のデータフラッシュを備えたMAXQ7665 PEデバイスの情報については、アプリケーションノート3579「単一ワード消去のデータフラッシュを備えたMAXQ7665のページ消去可能な(PE)フラッシュのインアプリケーションプログラミング(IAP)」を参照してください。

表1表3は、プログラムフラッシュ、ユーティリティROM、およびデータSRAMからコードをそれぞれ実行するときの16KBデバイスのメモリマップを示します。図1図2は、16KBと256Bのプログラムフラッシュのセクタとページの構造を図表にしたものです。これ以外のフラッシュオプションも利用可能です。全リストについては、MAXQ7665のデータシートを参照してください。

表1. 16KBメモリ空間—プログラムフラッシュからの実行
Table 1

表2. 16KBメモリ空間—ユーティリティROMからの実行
Table 2

表3. 16KBメモリ空間—データSRAMからの実行
Table 3

図1. 16KBプログラムフラッシュのセクタ/ページ構造
図1. 16KBプログラムフラッシュのセクタ/ページ構造

図2. 256Bデータフラッシュのセクタ/ページ構造
図2. 256Bデータフラッシュのセクタ/ページ構造

データフラッシュを使用してデータを保存

フラッシュを使用すると、システムの動作中に一度だけ、または定期的にプログラムする必要のあるシステムデータを確実に保存することができます。EEPROMとは異なり、MAXQ7665のPEフラッシュはバイト/ワード消去することができません。一度に2ページを消去する必要があります。これには通常、10msかかりますが、ワーストケースの状態ではさらに長くかかることがあります。この間、ユーザコードは停止状態となるため、その他の処理を行うことはできません。

データをフラッシュに保存するには複数の手法があり、アプリケーションに適切な方法を選択するときには、いくつかの要因を考慮する必要があります。新しいデータが完全に書き込まれるまで、現在のデータが変更されないことをアプリケーションが保証する必要がありますか? その必要がある場合、新しいデータが書き込まれるときに現在のデータが失われないようにするため、何らかのバンクスイッチング手法が必要となります。製品寿命の間に消去/書込みが何サイクル発生しますか? 消去/書込みのサイクル数がデータシートに規定された最大値を超える場合、制限キュー手法を使用し、データフラッシュの複数ページにわたってこれらのサイクルを分散させることによって、消去/書込みの総サイクル数を大幅に増大させることができます。定期的にデータの保存が必要なニーズでは、ほとんどの場合、バンクスイッチングや制限キューの手法によってシステムの信頼性要件と要求を満たすことができます。各手法の簡単な例を以下に示します。

バンクスイッチング

バンクスイッチングは、消去/書込みサイクルの間の、データの消失や破損を防止する効果的な方法です。この方法は、少なくとも1つのデータコピーを常に保持することによって有効に機能します。バンクスイッチングのマイナス点は、制限キュー手法に比べて2倍のデータフラッシュを必要とするという点です。つまり、バンクスイッチングは、実際にはキューサイズが2の制限キュー手法になります。したがって、詳細については、制限キューの実装方法に関する次項を参照してください。

制限キュー

制限キューは、一定の項目数によって制限されたキューであり、通常、定期的にデータを処理するときに必ず使用されます。制限キューは、所望のデータブロックサイズに等しい、「エントリ」の固定長キューを作成することによって構成されます。エントリサイズはアプリケーションに固有な値です。また、最も近いページ消去の境界に切り上げる必要があります。注:消去することのできる最小サイズは2ページ/ワードです。データフラッシュは、アプリケーションの要件に応じて、さまざまな方法で分割することが可能ですが、データフラッシュには2ページ消去の制限があるため、エントリは2ページの倍数に限定されます。たとえば、512 x 16のデータフラッシュは16ワードの32エントリに分けることが可能であり、結果として、表4のようなメモリマップになります。

初期化後、起動ルーチンでキューエントリをスキャンすることで、次に利用可能なキュー内のエントリを知ることができます。キューがいっぱいになると、先頭に戻ることが可能です。データフラッシュのエントリの消去が完了すれば、新しいエントリを書き込むことができます。図3は、制限キュー内のエントリのフローを示しています。

簡単なCのソースコード例については、付録Aを参照してください。

表4. 制限キューのメモリマップの例

FLASHQueue[ ]
Queue Index Data Flash Address
31 0xC1F0-0xC1FF
30 0xC1E0-0xC1EF
29 0xC1D0-0xC1DF
. . . . . . . .
2 0xC020-0xC05F
1 0xC010-0xC03F
0 0xC000-0xC00F

図3. 制限キューのフロー図
図3. 制限キューのフロー図

ユーティリティROMのフラッシュルーチン

MAXQ7665マイクロコントローラには、フラッシュのプログラミング、消去、および検証のため、ROM (読取り専用メモリ)内にオンチップフラッシュのサポートルーチンが用意されています。これらのルーチンにアクセスするには、2つの方法があります。直接アクセスとルックアップテーブルによる間接アクセスです。最速の方法は直接アクセスであり、ルーチンをじかに呼び出します。これを実行するには、以下に示す行にヘッダファイルを設けます。

u16 flashErasePage(void *);
u16 flashEraseSector(void *);
u16 flashEraseAll(void);

u16 dataFlashWrite(u16 *pAddress, u16 iData);
u16 dataFlashErasePage(void *);
u16 dataFlashEraseSector(void *);
u16 dataFlashEraseAll(void);
次に、リンカ定義を追加して、各ルーチンに適切なアドレスを割り当てますIARリンカのファイルの場合、追加された行は、次のようになります。
-DflashEraseSector=0x8XXX
-DflashErasePage=0x8XXX
-DflashEraseAll=0x8XXX
ルーチンごとに0x8XXXを適切なメモリアドレスに置き換えます。他のコンパイラは、これらのリファレンスを追加するのに別の手法を使用する場合があります。

flashWrite()ユーティリティルーチンは、引数の引渡しがC言語に適していないため、Cからじかに呼び出すことはできません。以下に示すような小さなアセンブリルーチンを記述する必要があります。

注:直接アクセス手法では、今後のROMバージョンとの上位互換性は確保されません。

第2の方法は、テーブル参照を用いた間接アクセスです。この手法は、今後のROMバージョンとの互換性に優れていますが、実行時間が長くなります。以下に示す各ルーチンの後、アセンブリルーチンは、テーブル参照方法を使用して、ROMユーティリティルーチンのアドレスを取得します。表5は、ユーティリティROMが供給するフラッシュルーチンを示します。ユーティリティのROMルーチンの全体リストについては、MAXQ7665のユーザガイドを参照してください。

表5. フラッシュユーティリティのROMルーチン

Routine Number Routine Name Entry Point ROMTable = ROM[800Dh] Entry Point Physical Address
1 flashWrite ROM[ROMTable] 0x8XXX
2 flashErasePage ROM[ROMTable + 1] 0x8XXX
3 flashEraseAll ROM[ROMTable + 2] 0x8XXX
4 moveDP0 ROM[ROMTable + 3] 0x8XXX
16 flashEraseSector ROM[ROMTable + 15] 0x8XXX
17 dataFlashWrite ROM[ROMTable + 16] 0x8XXX
19 dataFlashErasePage ROM[ROMTable + 18] 0x8XXX
20 dataFlashEraseSector ROM[ROMTable + 19] 0x8XXX
21 dataFlashEraseAll ROM[ROMTable + 20] 0x8XXX

FlashWrite()
ルーチン: u16 flashWrite(u16 *pDest, u16 *pSrc)
要約: プログラムフラッシュメモリの単一ページ(32ワード)をプログラムします。
入力: DP[0]—フラッシュメモリ内のディスティネーションアドレス
DP[1]—書き込む32ワードのデータを保持するSRAM内のソースアドレス
出力: キャリー:エラー時にセットされ、成功時にクリアされます。セットされた場合、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(u16 *pDest, u16 *pSrc);
;
flashWrite:
    move APC, #0           ; No auto inc/dec of accumulator.
    move AP,  #2           ; Set ACC to A[2].
    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.
    push DP[1]             ; Save Frame Pointer on the stack.
    move DP[0],A[0]        ; Move argument 0(dest address) to DP[0].
    move DP[1],A[1]        ; Move argument 1(src address) to DP[1].
    call ACC               ; Execute the routine.
    pop  DP[1]             ; Restore Frame Pointer.
    ret                    ; Status returned in A[0].
FlashErasePage()
ルーチン: u16 flashErasePage(void *pAddress)
要約: プログラムフラッシュメモリの2ページブロックを消去します。
入力: A[0]—消去する2ページブロック(すなわちページ0とページ1)に位置付けられたアドレス。A[0]には、0x0000~0x001Fの任意のアドレスを記入することができます。
出力: キャリー:エラー時にセットされ、成功時にクリアされます。セットされた場合、A[0]には、以下のエラーコードの1つが含まれます。
1: ソフトウェアのタイムアウトによる失敗
2: ハードウェアによって報告される失敗(DQ5/FERR)
4: サポートされていないコマンド
SW_FERR—エラー時にセットされ、成功時にクリアされます。
注: ウォッチドッグを有効にしないでください。あるいはウォッチドッグのタイムアウトを十分に長く設定することによって、リセットが起動されることなくこのルーチンが完了するようにしてください。
; This routine is callable by C code using the following prototype
; u16 flashErasePage(void *pAddress);
;
flashErasePage:
    move APC, #0           ; No auto inc/dec of accumulator.
    move AP,  #1           ; Set ACC to A[1].
    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)
要約: プログラムとデータのフラッシュメモリ全体を消去します。このルーチンはRAMからのみ呼び出すことができます。
入力: なし
出力: キャリー:エラー時にセットされ、成功時にクリアされます。
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 AP,  #0           ; Set ACC to A[0].
    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
moveDP0
ルーチン: moveDP0
要約: フラッシュメモリの単一ワードを読み出します。
入力: DP[0]—フラッシュメモリ内のソースアドレス。プログラムフラッシュを呼び出す0x8000を追加
出力: GRは、指定したアドレスにデータが含まれます。
注: この関数は、引数と戻りのレジスタがCの呼出し仕様に適合していないため、Cからじかに呼び出すことはできません。

以下のアセンブリコードの例では、moveDP0をCで呼出し可能なルーチンに変換しています。アプリケーションで速度が必須となる場合は、特定のタスクに合わせて、カスタムのアセンブリ言語ルーチンを記述する必要があります。このようなユーティリティROMルーチンがいくつかあり、フラッシュからの効率的なデータ転送を記述する場合に役立ちます。
; This routine is callable by C code using the following prototype
; u16 flashRead(u16 *pAddress);
;
flashRead:
    move APC, #0           ; No auto inc/dec of accumulator.
    move AP,  #1           ; Set ACC to A[1].
    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  #3                ; Add the index to the moveDP0 routine.
    move DP[0], ACC
    move ACC, @DP[0]       ; Retrieve the address of the routine.
    push DP[1]             ; Save Frame Pointer on the stack.
    move DP[0],A[0]        ; Move argument 0(src address) to DP[0].
    call ACC               ; Execute the routine.
    pop  DP[1]             ; Restore Frame Pointer.
    move A[0],GR
    ret                    ; Data word 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 AP,  #1           ; Set ACC to A[1].
    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  #15               ; 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].
DataFlashWrite()
ルーチン: u16 dataFlashWrite(void *pAddress, u16 *pData)
要約: データフラッシュメモリの単一ワードをプログラムします。
入力: A[0]—書き込むフラッシュメモリのワードアドレス
A[1]—フラッシュメモリに書き込むワード値
出力: キャリー:エラー時にセットされ、成功時にクリアされます。セットされた場合、A[0]には、以下のエラーコードの1つが含まれます。
1: ソフトウェアのタイムアウトによる失敗
2: ハードウェアによって報告される失敗(DQ5/FERR)
4: サポートされていないコマンド
SW_FERR—エラー時にセットされ、成功時にクリアされます。
注: ウォッチドッグを有効にしないでください。あるいはウォッチドッグのタイムアウトを十分に長く設定することによって、リセットが起動されることなくこのルーチンが完了するようにしてください。

以下のアセンブリコードの例では、間接アドレス指定の手法(ルックアップテーブル)を使用してdataFlashWrite()ユーティリティルーチンを呼び出しています。このルーチンはCコードで呼び出されます。
; This routine is callable by C code using the following prototype
; u16 dataFlashWrite(void *pAddress, u16 iData);
;
dataFlashWrite:
    move APC, #0           ; No auto inc/dec of accumulator.
    move AP,  #2           ; Set ACC to A[2].
    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  #16               ; 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].
DataFlashErasePage()
ルーチン: u16 dataFlashErasePage(void *pAddress)
要約: データフラッシュメモリの2ページを消去します。
入力: A[0]—消去する2ページブロック(すなわちページ0とページ1)に位置付けられたアドレス。A[0]には、0x4000あるいは0x4001のアドレスを記入することができます。
出力: キャリー:エラー時にセットされ、成功時にクリアされます。セットされた場合、A[0]には、以下のエラーコードの1つが含まれます。
1: ソフトウェアのタイムアウトによる失敗
2: ハードウェアによって報告される失敗(DQ5/FERR)
4: サポートされていないコマンド
SW_FERR—エラー時にセットされ、成功時にクリアされます。
注: ウォッチドッグを有効にしないでください。あるいはウォッチドッグのタイムアウトを十分に長く設定することによって、リセットが起動されることなくこのルーチンが完了するようにしてください。
; This routine is callable by C code using the following prototype
; u16 dataFlashErasePage(void *pAddress);
;
dataFlashErasePage:
    move APC, #0           ; No auto inc/dec of accumulator.
    move AP,  #1           ; Set ACC to A[1].
    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  #18               ; Add the index to the dataFlashErasePage 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].
DataFlashEraseSector()
ルーチン: u16 dataFlashEraseSector(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 dataFlashEraseSector(void *pAddress);
;
dataFlashEraseSector:
    move APC, #0           ; No auto inc/dec of accumulator.
    move AP,  #1           ; Set ACC to A[1].
    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  #19               ; Add the index to the dataFlashEraseSector 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].
dataFlashEraseAll
ルーチン: void dataFlashEraseAll(void)
要約: データフラッシュメモリ全体を消去します。
入力: なし
出力: キャリー:エラー時にセットされ、成功時にクリアされます。
SW_FERR—エラー時にセットされ、成功時にクリアされます。
注: ウォッチドッグを有効にしないでください。あるいはウォッチドッグのタイムアウトを十分に長く設定することによって、リセットが起動されることなくこのルーチンが完了するようにしてください。
; This routine is callable by C code using the following prototype
; void dataFlashEraseAll(void);
;
dataFlashEraseAll:
    move APC, #0           ; No auto inc/dec of accumulator.
    move AP,  #0           ; Set ACC to A[0].
    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  #20               ; 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の消去と書込みに必要なすべての動作を実行します。これによって、エンドユーザのアプリケーションがフラッシュメモリに対する操作を行えるようになります。他のサブルーチンの呼出しと同様、ルーチンが完了すると制御はエンドユーザのコードに戻ります。

信頼性の高いIAPを実現するには、ブートローダアプリケーションをメインのアプリケーションから分離する必要があります。こうすることで、再プログラミングシーケンスが完了しなかった場合に再プログラミング手順を確実に再試行することが可能になります。

ブートローダ

ROMは初期化後、アドレス0x0000にジャンプします。したがって、ブートローダアプリケーションのエントリポイントは0x0000に配置する必要があります。ブートローダアプリケーションは、フラッシュのセクタ/ページを必要な数にまで拡張することが可能ですが、使用済みのいずれのページも、ユーザのアプリケーションコードで利用することはできません。フラッシュの消去と書込みを行うときに満たさなければならない特定の要件を表6に示します。

表6. フラッシュユーティリティROMのルーチンを呼び出す場合の要件

 
コードを実行しているフラッシュページと同じフラッシュページから消去またはプログラムすることはできません。これは通常、問題にはなりません。フラッシュのブートローダアプリケーションはIAPの間に決して消去してはならないからです。
ウォッチドッグを有効にしないでください。あるいはウォッチドッグのタイムアウトを十分に長く設定することによって、flashEraseSector()またはflashErasePage()のルーチンを呼び出す前に、リセットが起動されることなくこのルーチンが完了するようにしてください。消去が完了する前にウォッチドッグのタイムアウトが発生すると、製品がリセットされます。
ユーティリティROMにアクセスするためには、システム制御レジスタビットSC.UPAを0に設定する必要があるため、0x8000あるいはこれよりも上位のプログラムメモリからじかにユーティリティROMルーチンを呼び出すことはできません。上位のメモリ(≧ 0x8000)のプログラムからユーティリティROMルーチンにアクセスする必要がある場合、下位のメモリ(< 0x8000)に置かれたルーチンを通してROMルーチンを間接的に呼び出す必要があります。この制約があるため、実質的にブートローダは64KB (32KB x 16)に制限されます。

図4のフローチャートは、リセット状態から抜け出したときのMAXQ7665の動作を示しています。ROMそのものを診断し、フラッシュの準備が完了していることを確認した後、ROM初期化コードは、直ちにアドレス0x0000にジャンプします。

図4. 簡易ROM初期化のフローチャート
図4. 簡易ROM初期化のフローチャート

図5のフローチャートは、簡易ブートローダアプリケーションの機能を示しています。簡易アプリケーションのヘッダは、次のようになります。

typedef struct {
    u16 iSize;  // The size of the application in words
    u32 iCRC;   // The CRC of the application
    u8 ID[8];   // ID string for current application
} APPLICATION_HEADER;
このヘッダの情報を使用することによって、ブートローダは、要求がある場合に、メインアプリケーションプログラムの妥当性を検査し、バージョンの識別番号を報告することができます。

図5. 簡易フラッシュブートローダのフローチャート
図5. 簡易フラッシュブートローダのフローチャート

プログラミングのシーケンスそのものは非常に簡単です。flashEraseSector()やflashErasePage()の呼出しを通じてメインアプリケーションコードを含む各セクタ/ページを消去します。次に、プログラムする必要のある32ワードごとにflashWrite()を呼び出すことによって、一度に1ページを書き込みます。CRC照合の誤る可能性を最小限にするため、アプリケーションヘッダを格納するページを最初に消去し、CRCデータを最後にプログラムするようにしてください。シリアルポートを経由してデータを取得するマイクロコントローラをリフラッシュするための極めて簡易なルーチンは、次のようになります。

/*
// VerySimpleReFlash()
//    As simple as it gets.
//    Step 1. Wait for erase command, then erase flash.
//    Step 2. Wait for program command, program flash one word at a time.
*/
void VerySimpleReFlash()
{
u16 iStatus;             // The status returned from flash utility ROM calls
s32 iSize;               // The size of the main code to program
u16 *pAddress = 0x2000;  // The starting address of the main application
u16 i;

    InitializeCOMM();    // Can be CAN or UART.
    WaitForEraseCommand();

    // Assume that application starts at the beginning of a sector.
    for (i=C_START_SECTOR;i 0)
    {
        u16 iData[32];
        Get32WordsFromCOMM(iData);
        iStatus = flashWrite(pAddress, iData);
        if (iStatus)
            break;
        pAddress += 32;
        iSize -= 32;
        UpdateWatchdog();    // Prevent timeout
    }

    SendFlashWriteResponse(iStatus);
    ResetMicro();
}

付録A. コード例


ダウンロード(DOC 33kB)

著者

Jon Wallace

Jon Wallace

Jon Wallaceは、アナログ・デバイセズのシニア・ディレクタです。2005年にMaxim Integrated(現在はアナログ・デバイセズに統合)に入社。車載用の電源やそれに関連する製品の定義を担当してきました。それらの製品による収益は、現在までで8億米ドル(約1256億円)以上に達しています。以前は、TRWAutomotiveで11年間にわたりソフトウェア/ハードウェア技術者として業務に従事。安全性に関連する電子システムのハードウェア/ソフトウェアを開発していました。これまで30年にわたり自動車業界に携わっています。車両用のバス通信とソフトウェア・アルゴリズムに関する25件の米国特許を取得。パデュー大学でコンピュータ工学と電気工学の学士号を取得しました。