アプリケーションノート 3569

セクタ消去可能なプログラムのインアプリケーションプログラミングとMAXQマイクロコントローラのデータフラッシュ

筆者: Jon Wallace

要約: このアプリケーションノートでは、プログラムとデータフラッシュについて記述し、そして内蔵のユーティリティROMを使用してフラッシュの消去/書込みを行う方法を説明します。このアプリケーションノートは、セクタ消去可能なフラッシュを使用するMAXQフラッシュベースのマイクロコントローラに適用されます。

はじめに

このアプリケーションノートでは、セクタ消去可能なフラッシュを使用するMAXQマイクロコントローラにおける内部データとプログラムフラッシュの管理方法について説明します。一般的な情報では、プログラムフラッシュのインアプリケーションプログラミングを行うためのブートローダアプリケーションの構築方法について説明します。注:このアプリケーションノートは、ページ消去可能なフラッシュを使用するMAXQマイクロコントローラには適用されません。すなわち、消去する量が少ないフラッシュには適用されないということです。各MAXQのデータシートに、そのマイクロコントローラで使用するフラッシュのタイプが記載されています。

フラッシュの概要

メモリマップ
このアプリケーションノートでは、各種メモリサイズについてフラッシュメモリマップの例を示していますが、どのMAXQ製品にも正確には一致していません。これらのマップは、このアプリケーションノートの例を示すための単なる参考です。それぞれのMAXQデータシートにその製品のメモリマップオプションが記載されています。

ブート、プログラム、およびデータフラッシュの各セクタに動作の違いはありません。ブートローダアプリケーションが、最初のフラッシュセクタで提供されるスペースよりも広いスペースを必要とした場合、次のセクタにまでアプリケーションを拡張することが可能です。しかし、ラベリングは、異なるセクタがこのアプリケーションノートでどう使用されるかを示すため、以下の例において異なります。

表1. フラッシュメモリマップの例

データフラッシュ
データフラッシュを使用すると、システムの動作中に一度だけ、または定期的にプログラミングを必要とするシステムデータを確実に保存することができます。データフラッシュのサイズは、特定のMAXQ製品によって異なりますが、概して128~2kワードです。

データフラッシュの使用には制限があります。EEPROMとは異なり、データフラッシュではワードを消去することはできません。一度にセクタ全体を消去する必要があります。通常、セクタを消去するのに約0.7秒かかりますが、ワーストケースの状態では15秒もかかることがあります。この間、ユーザコードは停止状態となるため、その他の処理を行うことはできません。システム要件に適したソフトウェア手法を選択するときには、これらの制限を慎重に考慮する必要があります。定期的にデータの保存が必要な場合、大半は、限定キューやバンクスイッチングの手法によって、システムの信頼性要件を満たすことができます。バンクスイッチングと限定キューの手法の簡単な例を以下に示します。

限定キュー
限定キューの手法は、一定の項目数によってキューを限定する方法です。この手法は通常、定期的にデータを処理するときに必ず使用されます。たとえば、2kワードのデータフラッシュは、32~64ワードのエントリに分けることが可能であるため、結果として表2のようなメモリマップになります。

初期化後、起動ルーチンは次に利用可能なキュー内のエントリを確定するためにキューエントリをスキャンすることができます。キューがいっぱいになると、他のエントリを書き込む前にキューが消去される必要があります。すべてのエントリを必要とする場合は、2つの異なるセクタを交互に入れ替えてすべてのデータを維持する必要があります。フラッシュの消去が完了すれば、新しいエントリを書き込むことができます。この手法の欠点は、消去処理中に電源がオフになると、すべてのデータが失われる可能性があるということです。図1は、限定キュー内のエントリのフローを示しています。簡単なCのソースコード例については、付録Aを参照してください。

限定キューの手法を使用してシステム要件が満たされない場合、バンクスイッチングも必要となります。

表2. 限定キューのメモリマップの例

FLASHQueue[ ]
Queue Index Data Flash Address
31 0xF7C0-0xF7FF
30 0xF780-0xF7BF
29 0xF740-0xF77F
. . . . . . . .
2 0xF080-0xF0BF
1 0xF040-0xF07F
0 0xF000-0xF03F

Figure 1. Bounded queue flow.
図1. 限定キューのフロー

バンクスイッチング
バンクスイッチングは、長いセクタ消去サイクルの間の、データの消失や破損を防止する効果的な方法です。このアプリケーションノートで使用する「バンク」という用語は、「セクタ」という用語と同等です。バンクスイッチングは、セクタサイズが合計データサイズよりわずかに大きいときに有効に機能します。バンクスイッチングのマイナス点は、少なくとも2つのデータフラッシュのセクタを必要とするということです。書き込むデータサイズの合計がセクタサイズよりかなり小さいときの最良の手法は、バンクスイッチングと限定キューの方法を組み合わせることです。

アプリケーションでバンクスイッチングを必要とする場合、少なくとも2つのデータフラッシュのセクタを備えたバージョンのMAXQを選択してください。表3は、2つの1K x 16フラッシュセクタのメモリマップの例を示します。図2は、バンクスイッチの書込み/消去のフローを示しています。

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

表3. バンクスイッチングのメモリマップの例

Flash Sectors
Sector Number Data Flash Address
0 0xF000-0xF3FF
1 0xE000-0xE3FF

Figure 2. Bank switching flow.
図2. バンクスイッチングのフロー

限定キューとバンクスイッチングのフローの併用
限定キューとバンクスイッチングフローを併用する方法は、データフラッシュを管理するための最も確実で柔軟性のある手法です。この組み合わせが有効に機能するのは、少量のデータを定期的にフラッシュに保存する必要があって、データの完全性を維持する必要があるときです。表4に、32等分のエントリに分割された2つの2K x 16セクタのメモリマップの例を示します。図3は、2つのセクタ間での限定キューのデータのフローを示します。

この2つを併用する手法のコーディングは、限定キューだけの場合に比べてわずかに複雑です。簡単なCのソースコード例については、付録Aを参照してください。

表4. 限定キューとバンクスイッチングのメモリマップの例

FQueueBank0[ ]
Queue Index Data Flash Address
31 0xF7C0-0xF7FF
30 0xF780-0xF7BF
29 0xF740-0xF77F
. . . . . . . .
2 0xF080-0xF0BF
1 0xF040-0xF07F
0 0xF000-0xF03F

FQueueBank0[ ]
Queue Index Data Flash Address
31 0xE7C0-0xE7FF
30 0xE780-0xE7BF
29 0xE740-0xE77F
. . . . . . . .
2 0xE080-0xE0BF
1 0xE040-0xE07F
0 0xE000-0xE03F


Figure 3. Bounded queue and bank switch flow.
図3. 限定キューとバンクスイッチのフロー

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

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

直接アクセス手法では、今後のROMバージョンとの上位互換性は確保されないことに留意してください。

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

表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(u16 *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(u16 *pAddress, u16 iData);
;
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.
    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 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)
要約 ブートローダセクタを含む、すべてのプログラムとデータのフラッシュメモリを消去します。このルーチンは通常、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 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

インアプリケーションプログラミング

フラッシュを用いたほとんどのシステムで重要となる要件は、システムが最終製品にインストールされている間にファームウェアをアップデートする機能です。これは、インアプリケーションプログラミング(IAP)と呼ばれます。この項では、IAPアプリケーションを作成するための一般的なガイドラインの概要を説明します。

上述のユーティリティROMフラッシュのルーチンがフラッシュROMの消去と書込みに必要なすべての動作を実行します。これによって、エンドユーザのアプリケーションがフラッシュメモリに対する操作を行えるようになります。他のサブルーチン呼出しと同様、ルーチンの完了後に制御はエンドユーザのコードに戻ります。

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

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

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

 
コードを実行しているのと同一のフラッシュセクタからは消去またはプログラムすることはできません。IAP中はフラッシュブートセクタを消去すべきでないため、これは通常問題になりません。
flashEraseSector()ルーチンが呼び出される前にリセットを始動させずにこのルーチンを完了させるには、ウォッチドッグをイネーブルにさせないか、ウォッチドッグタイムアウトを適度に長く設定する必要があります。消去が完了する前にウォッチドッグのタイムアウトが起こると、製品はリセットされてしまいます。セクタの消去には通常0.7秒、最悪条件下では最大15秒かかることもあります。
ユーティリティROMにアクセスするにはシステム制御レジスタビットのSC.UPAは0に設定される必要があるため、ROMのユーティリティルーチンは、プログラムメモリアドレス0x8000から直接呼び出すことはできません。ユーティリティROMルーチンへ上位メモリ(0x8000)のプログラムからアクセスする必要がある場合は、プログラムは下位メモリ(0x8000未満)に属するルーチンから間接的にROMルーチンを呼び出さなければなりません。これによってブートローダは実質64kB (32kB x 16)に制限されます。

図4のフローチャートは、リセット状態から抜け出したときにMAXQが行う作業を示しています。ROMの初期化コードは、ROM自体を診断し、フラッシュの準備ができていることを確認した後、アドレス0x0000に直接ジャンプします。該当するデータシートとユーザガイドを読んで、ご利用のMAXQマイクロコントローラがこのブートシーケンスに沿っているのかどうかを確認してください。

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

図5のフローチャートは、簡単なブートローダアプリケーションがどのようなものかを示しています。IAPのブートローダを使用するとき、メインアプリケーションのエントリポイントは通常、アドレス0x2000 + ヘッダのオフセット(16kB (8K x 16)のブートローダオプションの場合)、およびアドレス0x4000 + ヘッダのオフセット(32kB (16K x 16)ブートローダオプションの場合)になります。簡単なアプリケーションのヘッダは、次のようになります。

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;
このヘッダの情報を使用することによって、ブートローダは、要求があればメインアプリケーションプログラムの妥当性を検査し、バージョンの識別を報告します。

Figure 5. Simplified flash boot-loader flowchart.
図5. フラッシュのブートローダの簡易フローチャート

プログラミングのシーケンス自体は、非常に簡単です。flashEraseSector()への呼出しによってメインアプリケーションコードを含んだ各セクタを消去します。次に、プログラミングを行うあらゆるワードについて、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, then program flash one word
//            at a time.
*/
void VerySimpleReFlash()
{
u16 iStatus;             // The status returned from flash utility ROM calls
u16 iSize;               // The size of the main code to program
u16 *pAddress = 0x2000;  // The starting address of the main application

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

    SlowDownWatchdog();  // If watchdog enabled set update > 15s

    iStatus = flashEraseSector(C_ADDRESS_SECTOR_1);
    if (iStatus == 0)
        iStatus = flashEraseSector(C_ADDRESS_SECTOR_2);

    UpdateWatchdog();    // Prevent watchdog timeout

    SendFlashErasedResponse(iStatus);

    if (iStatus)
        ResetMicro();

    iSize = WaitForProgramCommand();
    while (iSize--)
    {
        u16 iData = GetWordFromCOMM();
        iStatus = flashWrite(pAddress, iData);
        if (iStatus)
            break;
        ++pAddress;
        UpdateWatchdog();    // Prevent watchdog timeout
    }

    SendFlashWriteResponse(iStatus);
    ResetMicro();
}
ブートローダアプリケーションが使用していないプログラムスペースは、他のルーチンや常時データ保存に使用することができることを思い出してください。この良い例が、上記の「ユーティリティROMのフラッシュルーチン」の項に記載したように、ユーティリティROMルーチンを間接的に呼び出す場合に、すべてのルーチンを保存するというものです。ブートローダと同じセクタにその他の情報を保存するには、1つの制限があります。ブートローダアプリケーション自体をすべて(またはその一部を)消去することなく、他の情報を消去することはできないということです。

RAMベースのフラッシュルーチンを使用するIAP
RAMベースのフラッシュルーチンは、障害の回復が必要でないときの、MAXQマイクロコントローラのリフラッシュに使用することができます。この方法では、メインアプリケーションが、再配置可能な小さなフラッシュプログラミングルーチンをRAMにコピーし、次にそのルーチンにジャンプすることが必要となります。表7に、RAMからコードを実行するときに考慮すべきいくつかの制限事項を示します。

表7. RAMからコードを実行するときの制限事項

 
RAMベースのルーチンを実行する前に、SC.UPAを0に設定する必要があります。これは、アプリケーションがコードセグメントP0およびP1からRAMルーチンに飛ばなければならないことを意味しています。
データおよびプログラムとして同時にRAMにアクセスすることはできません。データ保存に使用できるのは、レジスタとハードウェアスタックのみとなります。
割込みがイネーブルの場合、割込みベクトルはRAMルーチンを指す必要があります。RAMの再フラッシュルーチンが簡単であるため、通常割込みはオフにされ、ポーリングが使用されます。

標準では、フラッシュルーチンは、UARTまたはCANインタフェースのいずれかを用いて通信を行います。より強固なエラー回復メカニズムを実現するには、通常、小さなデータパケットを受信し、何らかの確認応答を送信することが最良です。リフラッシュルーチンのフローを図6に示します。電源が消失するまでに再プログラミングが成功しなければ、JTAGポートを通じてマイクロコントローラの再プログラミングが必要になります。

Figure 6. Simplified RAM reflash routine flowchart.
図6. RAMリフラッシュルーチンの簡易フローチャート

付録A. コード例
ダウンロード:付録A (PDF)


次のステップ
EE-Mail EE-Mail配信の登録申し込みをして、興味のある分野の最新ドキュメントに関する自動通知を受け取る。
© , Maxim Integrated Products, Inc.
このウェブサイトのコンテンツは米国および各国の著作権法によって保護されています。コンテンツの複製を希望される場合は お問い合わせください。.
APP 3569:
アプリケーションノート 3569,AN3569, AN 3569, APP3569, Appnote3569, Appnote 3569