アプリケーションでバンクスイッチングを必要とする場合、少なくとも2つのデータフラッシュのセクタを備えたバージョンのMAXQを選択してください。表3は、2つの1K x 16フラッシュセクタのメモリマップの例を示します。図2は、バンクスイッチの書込み/消去のフローを示しています。
簡単なCのソースコード例については、付録Aを参照してください。
表3. バンクスイッチングのメモリマップの例
Flash Sectors
Sector Number
Data Flash Address
0
0xF000-0xF3FF
1
0xE000-0xE3FF
図2. バンクスイッチングのフロー
限定キューとバンクスイッチングのフローの併用
限定キューとバンクスイッチングフローを併用する方法は、データフラッシュを管理するための最も確実で柔軟性のある手法です。この組み合わせが有効に機能するのは、少量のデータを定期的にフラッシュに保存する必要があって、データの完全性を維持する必要があるときです。表4に、32等分のエントリに分割された2つの2K x 16セクタのメモリマップの例を示します。図3は、2つのセクタ間での限定キューのデータのフローを示します。
; 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]
; 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]
; 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
ユーティリティROMにアクセスするにはシステム制御レジスタビットのSC.UPAは0に設定される必要があるため、ROMのユーティリティルーチンは、プログラムメモリアドレス0x8000から直接呼び出すことはできません。ユーティリティROMルーチンへ上位メモリ(0x8000)のプログラムからアクセスする必要がある場合は、プログラムは下位メモリ(0x8000未満)に属するルーチンから間接的にROMルーチンを呼び出さなければなりません。これによってブートローダは実質64kB (32kB x 16)に制限されます。
図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;
/*
// 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();
}