/* ======================================================== 自己アップデータ ======================================================== */ #pragma SFR #pragma di #pragma ei #pragma nop #pragma stop #pragma halt #include "incs_loader.h" #include #include "fsl_user.h" #include "i2c_ctr.h" // ======================================================== const u8 fsl_fx_MHz_u08 = 8; const u8 fsl_low_voltage_u08 = 1; // 自己フラッシュパラメータ #define SAM_BLOCK_SIZE 1024 #define SELF_UPDATE_BUFF_SIZE 256 #define SELF_UPDATE_SPLIT_WRITE_NUM ( SAM_BLOCK_SIZE / SELF_UPDATE_BUFF_SIZE ) #define SAM_WORD_SIZE 4 // ↓ブロック番号(1ブロック=1kB) #define INACTIVE_BOOTSECT_TOP 4 #define FIRM_TOP 8 #define FIRM_SIZE 12 #define UPDATE_BLOCK_LAST ( FIRM_TOP + FIRM_SIZE - 1 ) #ifdef _MCU_BSR_ #define ACKD ACKD1 #define ACKE ACKE1 #define COI COI1 #define IICAEN IICA1EN #define IICAPR0 IICAPR10 #define IICRSV IICRSV1 #define IICA IICA1 #define IICAIF IICAIF1 #define IICAMK IICAMK1 #define IICAPR1 IICAPR11 #define IICCTL0 IICCTL01 #define IICE IICE1 #define IICF IICF1 #define IICS IICS1 #define IICWH IICWH1 #define IICWL IICWL1 #define LREL LREL1 #define SPD SPD1 #define SPIE SPIE1 #define STCEN STCEN1 #define STD STD1 #define SVA SVA1 #define WREL WREL1 #define WTIM WTIM1 #endif // ======================================================== static void FSL_Open( void ); static void FSL_Close( void ); err firm_restore( ); static err my_FSL_Init(); static err firm_duplicate( __far u8 * p_rom, u8 block_dest ); // ======================================================== extern u16 pool[]; // 0.D以降 新アップデータ向け #define N_MGC_L 0x1FF6 #define N_MGC_T 0x4FF6 /* ======================================================== I2Cで受信して、 書き込み、 チェックOK → 新ファームに切り替えて再起動     NG → 旧(現)ファームに戻して再起動 (この関数からは戻りません) ======================================================== */ err firm_update( ) { u8 target_block; u8 split_write_count; // ブロックへちまちま書き込むカウンタ // 書き替え前準備 ///////////////////////////////////// my_FSL_Init(); /* ファームのバックアップ 0x2000 - 0x4FFF を 0x5000 - 0x7FFF (ブロック 20 - 31) にコピー */ firm_duplicate( ( __far u8 * ) 0x2000, ( 0x5000 / 0x0400 ) ); // 全ブロック削除 ///////////////////////////////////// // 電源断を判定するため、最初に全クラスタ消去する //(新ファームが書かれるところに残ってる、以前のファームのフッタを消したい) for( target_block = INACTIVE_BOOTSECT_TOP; target_block <= UPDATE_BLOCK_LAST; target_block += 1 ) { FSL_Erase( target_block ); } // 書き替え /////////////////////////////////////////// // ●ストップコンディションが来るまで続ける // ●終わったら、スタートアップルーチンに飛ぶ for( target_block = INACTIVE_BOOTSECT_TOP; target_block <= UPDATE_BLOCK_LAST; target_block += 1 ) { // 新ファーム領域削除 FSL_Erase( target_block ); // 分割書き込み for( split_write_count = 0; ( ( split_write_count < SELF_UPDATE_SPLIT_WRITE_NUM ) && ( !SPD ) ); split_write_count += 1 ) { u8* p_buffer = pool; u8 buffer_fill = 0; WDT_Restart( ); // I2Cから書き込みデータをバッファにためる do { while( !IICAIF && !SPD ){;} IICAIF = 0; *p_buffer = IICA; WREL = 1; p_buffer += 1; buffer_fill += 1; } while( ( buffer_fill != ( u8 ) SELF_UPDATE_BUFF_SIZE ) && !SPD ); // 書き込み // 最後だと、ゴミをパディングするが別にかまわない if( FSL_Write( ( fsl_u32 ) ( target_block * SAM_BLOCK_SIZE + split_write_count * SELF_UPDATE_BUFF_SIZE ), ( fsl_u08 ) ( SELF_UPDATE_BUFF_SIZE / SAM_WORD_SIZE ) ) != FSL_OK ) { // 書き込み後のチェックエラー // リブートののち、リストア // FSL_ForceReset(); // リセット FSL_SwapBootCluster( ); // FSL_Close( ); return ( ERR_ERR ); } } // 1ブロック書き込み完了。内部ベリファイを行う if( FSL_IVerify( target_block ) != FSL_OK ){ // todo 再度消去→書き込み ベリファイを繰り返すだけじゃダメでした... NOP(); } if( SPD ) { break; } } LREL = 1; // 書き込んだファームのチェック // { u8 i; u8 comp = 0; // ローダーのマジックと、本文の末尾のマジックは同じか確認 for( i = 0; i < sizeof( __TIME__ ); i++ ) { comp += ( *( u8 * ) ( N_MGC_L + i ) == *( u8 * ) ( N_MGC_T + i ) ) ? 0 : 1; } if( comp == 0 ) { FSL_InvertBootFlag( ); FSL_SwapBootCluster( ); // リセットせずに頭から。FSL_Closeは不要 // FSL_ForceReset(); // リセット // FSL_SwapActiveBootCluster(); // ←スワップされてしまうので、続けられず暴走! // 戻ってこない // } else { // データエラー // リブートののち、リストア // FSL_ForceReset(); // リセット FSL_SwapBootCluster( ); // FSL_Close( ); // 戻ってこない // } } } /* ========================================================  ■ファームをバックアップ領域からリストアします。  チェック後、最後の最後でブートスワップするので、  ここではブートスワップは不要です。 ======================================================== */ err firm_restore( ) { my_FSL_Init(); /* ファームのリストア 0x4800 - 0x7FFF (ブロック 18 - 27) から 0x2000 - 0x47FF (ブロック 8 - 17) へコピー */ firm_duplicate( ( __far u8 * ) 0x5000, FIRM_TOP ); // todo //  リストア失敗したら、LEDちかちかとかさせて、サービス送りにしてもらう // リブート // スワップは不要です! FSL_SwapBootCluster(); // FSL_ForceReset( ); return ( ERR_SUCCESS ); } // ======================================================== static void FSL_Open( void ) { /* save the configuration of the interrupt controller and set */ #ifdef FSL_INT_BACKUP fsl_MK0L_bak_u08 = MK0L; /* if (interrupt backup required) */ fsl_MK0H_bak_u08 = MK0H; /* { */ fsl_MK1L_bak_u08 = MK1L; /* */ fsl_MK1H_bak_u08 = MK1H; /* save interrupt controller */ fsl_MK2L_bak_u08 = MK2L; /* configuration */ fsl_MK2H_bak_u08 = MK2H; /* */ MK0L = FSL_MK0L_MASK; /* */ MK0H = FSL_MK0H_MASK; /* */ MK1L = FSL_MK1L_MASK; /* prepare interrupt controller */ MK1H = FSL_MK1H_MASK; /* for selfprogramming */ MK2L = FSL_MK2L_MASK; /* */ MK2H = FSL_MK2H_MASK; /* } */ #endif // 何か前準備? // todo DMAを止める while( DST1 ){;} DEN1 = 0; MK0 = 0xFFFF; MK1 = 0xFFFF; MK2 = 0xFFFF; FSL_FLMD0_HIGH; // フラッシュ書き替え許可 } /*----------------------------------------------------------------------------------------------*/ /* leave the "user room" and restore previous conditions */ /*----------------------------------------------------------------------------------------------*/ static void FSL_Close( void ) { // 何か後始末? FSL_FLMD0_LOW; // フラッシュライトプロテクト #ifdef FSL_INT_BACKUP MK0L = fsl_MK0L_bak_u08; /* do{ */ MK0H = fsl_MK0H_bak_u08; /* restore interrupt controller */ MK1L = fsl_MK1L_bak_u08; /* configuration */ MK1H = fsl_MK1H_bak_u08; /* */ MK2L = fsl_MK2L_bak_u08; /* */ MK2H = fsl_MK2H_bak_u08; /* } */ #endif } /* ========================================================  マイコン内でファームをコピーします。 __far u8 * p_rom コピー元の先頭アドレス block_dest コピー先の先頭ブロック コピー先に書けるようにmy_FSL_Initをあらかじめ実行する必要があります。 ======================================================== */ static err firm_duplicate( __far u8 * p_rom, u8 block_dest ) { u8 target_block; u8 split_write_count; // ブロックへちまちま書き込むカウンタ // 書き込み先ブロックの数だけ繰り返す for( target_block = block_dest; target_block < block_dest + FIRM_SIZE; target_block += 1 ) { WDT_Restart( ); // ブロック消去 while( FSL_BlankCheck( target_block ) != FSL_OK ) { FSL_Erase( target_block ); } // 分割書き込み分繰り返す for( split_write_count = 0; split_write_count < SELF_UPDATE_SPLIT_WRITE_NUM; split_write_count += 1 ) { u8 buffer_fill; u8* p_buff; // 書き込みデータをバッファにためる buffer_fill = 0; p_buff = pool; do { *p_buff = *p_rom; p_rom += 1; p_buff += 1; buffer_fill +=1; } while( buffer_fill != ( u8 ) SELF_UPDATE_BUFF_SIZE ); // 書き込み if( FSL_Write( ( fsl_u32 ) ( target_block * SAM_BLOCK_SIZE + split_write_count * SELF_UPDATE_BUFF_SIZE ), ( fsl_u08 ) ( SELF_UPDATE_BUFF_SIZE / SAM_WORD_SIZE ) ) != FSL_OK ) { FSL_Close( ); return ( ERR_ERR ); } } // 1ブロック書き込み完了。内部電圧チェックを行う while( FSL_IVerify( target_block ) != FSL_OK ){ // todo ; } } return( ERR_SUCCESS ); } /* ======================================================== ======================================================== */ static err my_FSL_Init() { RTCE = 0; // 書き替え前準備 // DI( ); FSL_Open( ); // 割り込み禁止など FSL_Init( pool ); // ライブラリ初期化。割り込み中断考慮せず FSL_ModeCheck( ); // ライトプロテクトチェック。失敗することを考慮せず return( ERR_SUCCESS ); } task_status_immed tski_mcu_reset() { // 普通に再起動 my_FSL_Init(); FSL_Close( ); // FSL_SwapBootCluster(); FSL_ForceReset(); // リセット // 保険? // WDTE = 0xAA; // WDTで再起動(テスト向け) return( ERR_SUCCESS ); // no reach }