/* ======================================================== 自己アップデータ ======================================================== */ #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 #define INACTIVE_BOOTSECT_TOP 4 #define UPDATE_BLOCK_LAST 17 #define FIRM_TOP 8 #define FIRM_SIZE 10 #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 u8 pool[]; // magic.c の記述と違わないように注意! #define N_MGC_L 0x1FF6 #define N_MGC_T 0x47F6 /* ======================================================== I2Cで受信して、 書き込み、 チェックOK → 新ファームに切り替えて再起動     NG → 旧(現)ファームに戻して再起動 (この関数からは戻りません) ======================================================== */ err firm_update( ) { u8 target_block; u8 split_write_count; // ブロックへちまちま書き込むカウンタ TOE0 = 0x0000; TOE0 = 0x0020; // 書き替え前準備 // my_FSL_Init(); /* ファームのバックアップ 0x2000 - 0x47FF (ブロック 8 - 17) を 0x4800 - 0x7FFF (ブロック 18 - 27) にコピー */ firm_duplicate( ( __far u8 * ) 0x2000, ( FIRM_TOP + FIRM_SIZE ) ); // 書き替え // /* ●書き込み中の電源断を判定するため、最初に全クラスタ消去する(フッタを消したい) ●ストップコンディションが来るまで続ける(結局、0x1000 - 0x47FF まですべて書き替えることにはなる) ●終わったら、リセットする。WDTリセットなので自分でわかる。 */ // ブロックの数だけ繰り返し 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_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_Close( ); firm_restore( ); // 戻ってこない // } } } /* ======================================================== ■ファームをバックアップ領域からリストアします。 0x4800 - 0x7FFF (ブロック 18 - 27)を 0x2000 - 0x47FF (同、8 - 17) にコピーして 再起動します。 ブートスワップは不要です。 ======================================================== */ err firm_restore( ) { my_FSL_Init(); /* ファームのリストア 0x4800 - 0x7FFF (ブロック 18 - 27) から 0x2000 - 0x47FF (ブロック 8 - 17) へコピー */ firm_duplicate( ( __far u8 * ) 0x4800, FIRM_TOP ); // todo //  リストア失敗したら、LEDちかちかとかさせて、サービス送りにしてもらう // リブート // スワップは不要です! 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; 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 } /* ========================================================  マイコン内でファームをコピーします。 block_dest コピー元の先頭ブロック __far u8 * p_rom コピー先のアドレス コピー先に書けるように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 ){;} } return( ERR_SUCCESS ); } /* ======================================================== ======================================================== */ static err my_FSL_Init() { RTCE = 0; // 書き替え前準備 // DI( ); FSL_Open( ); // 割り込み禁止など FSL_Init( pool ); // ライブラリ初期化。割り込み中断考慮せず FSL_ModeCheck( ); // ライトプロテクトチェック。失敗することを考慮せず return( ERR_SUCCESS ); }