/* ======================================================== 自己アップデータ ======================================================== */ #pragma SFR #pragma di #pragma ei #pragma nop #pragma stop #pragma halt #include "incs_loader.h" #include "fsl.h" #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 ACKD0 #define ACKE ACKE0 #define COI COI0 #define IICAEN IICA0EN #define IICAPR0 IICAPR00 #define IICRSV IICRSV0 #define IICA IICA0 #define IICAEN IICA0EN #define IICAIF IICAIF0 #define IICAMK IICAMK0 #define IICAPR1 IICAPR10 #define IICCTL0 IICCTL00 #define IICE IICE0 #define IICF IICF0 #define IICS IICS0 #define IICWH IICWH0 #define IICWL IICWL0 #define LREL LREL0 #define SPD SPD0 #define SPIE SPIE0 #define STCEN STCEN0 #define STD STD0 #define SVA SVA0 #define WREL WREL0 #define WTIM WTIM0 #endif // ======================================================== static void FSL_Open(void); static void FSL_Close(void); err firm_restore(); extern void self_update_reboot( u8 flag ); // magic.c の記述と違わないように注意! #define N_MGC_L 0x1FF6 #define N_MGC_T 0x47F6 // ======================================================== u8 boot_ura; // ブートクラスタ 0/1 /* ======================================================== ======================================================== */ err firm_update(){ u8 buffer_fill; u8 target_block; u8 data_buffer[ SELF_UPDATE_BUFF_SIZE ]; u8 split_write_count; // ブロックへちまちま書き込むカウンタ fsl_u08 err; __far u8* p_rom; TOE0 = 0x0000; TOE0 = 0x0020; // 書き替え前準備 // FSL_Open(); // 割り込み禁止など DI(); err = FSL_Init( data_buffer ); // ライブラリ初期化。割り込み中断考慮せず err += FSL_ModeCheck(); // ライトプロテクトチェック。失敗することを考慮せず // ファームのバックアップ // /* 0x2000 - 0x47FF (ブロック 8 - 17) を 0x4800 - 0x7FFF (ブロック 18 - 27) にコピー */ p_rom = (u8*)0x2000; // 書き込み先ブロックの数だけ繰り返す for( target_block = ( FIRM_TOP + FIRM_SIZE ); target_block < ( FIRM_TOP + FIRM_SIZE + FIRM_SIZE ); target_block += 1 ){ WDT_Restart(); // ブロック消去 while( FSL_BlankCheck( target_block ) != FSL_OK ){ err = FSL_Erase( target_block ); } // 分割書き込み分繰り返す for( split_write_count = 0; split_write_count < SELF_UPDATE_SPLIT_WRITE_NUM; split_write_count += 1 ){ // 書き込みデータをバッファにためる buffer_fill = 0; do{ data_buffer[ buffer_fill ] = *p_rom; p_rom += 1; buffer_fill++; }while( buffer_fill != (u8)SELF_UPDATE_BUFF_SIZE ); // 書き込み err = 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 ) ); if( err != FSL_OK ){ FSL_Close(); NOP(); return( ERR_ERR ); } } // 1ブロック書き込み完了。内部電圧チェックを行う while( FSL_IVerify( target_block ) != FSL_OK ){ ; } } // 書き替え // /* ●書き込み中の電源断を判定するため、最初に全クラスタ消去する(フッタを消したい) ●ストップコンディションが来るまで続ける(結局、0x1000 - 0x47FF まですべて書き替えることにはなる) ●終わったら、リセットする。WDTリセットなので自分でわかる。 */ // 全ブロック消去 for( target_block = INACTIVE_BOOTSECT_TOP; target_block <= UPDATE_BLOCK_LAST ; target_block += 1 ){ err = FSL_Erase( target_block ); } // ブロックの数だけ繰り返し for( target_block = INACTIVE_BOOTSECT_TOP; target_block <= UPDATE_BLOCK_LAST; target_block += 1 ){ // 分割書き込み for( split_write_count = 0; (( split_write_count < SELF_UPDATE_SPLIT_WRITE_NUM ) && ( !SPD )); split_write_count += 1 ){ WDT_Restart(); // I2Cから書き込みデータをバッファにためる do{ while( !IICAIF && !SPD ){;} IICAIF = 0; data_buffer[ buffer_fill ] = IICA; WREL = 1; buffer_fill += 1; }while(( buffer_fill != (u8)SELF_UPDATE_BUFF_SIZE ) && !SPD ); // 書き込み // 最後だと、ゴミをパディングするが別にかまわない err = 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 ) ); if( err != FSL_OK ){ FSL_Close(); return( ERR_ERR ); } } // 1ブロック書き込み完了。内部ベリファイを行う while( FSL_IVerify( target_block ) != FSL_OK ){;} if( SPD ){ goto firm_update_end; } } firm_update_end: WREL = 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(); // 戻ってこない // }else{ FSL_Close(); firm_restore(); // 戻ってこない // } } } /* ======================================================== ■ファームをバックアップ領域からリストアします。 0x4800 - 0x7FFF (ブロック 18 - 27)を 0x2000 - 0x47FF (同、8 - 17) にコピーして 再起動します。 ブートスワップは不要です。 ======================================================== */ err firm_restore(){ u8 buffer_fill; u8 target_block; u8 data_buffer[ SELF_UPDATE_BUFF_SIZE ]; u8 split_write_count; // ブロックへちまちま書き込むカウンタ fsl_u08 err; __far u8* p_rom; TOE0 = 0x0000; TOE0 = 0x0080; // 書き替え前準備 // DI(); FSL_Open(); // 割り込み禁止など err = FSL_Init( data_buffer ); // ライブラリ初期化。割り込み中断考慮せず err += FSL_ModeCheck(); // ライトプロテクトチェック。失敗することを考慮せず // ファームのリストア /* 0x4800 - 0x7FFF (ブロック 18 - 27) から 0x2000 - 0x47FF (ブロック 8 - 17) へコピー */ p_rom = (u8*)0x4800; // 転送先ブロックの数だけ繰り返す for( target_block = FIRM_TOP; target_block <= UPDATE_BLOCK_LAST; target_block += 1 ){ WDT_Restart(); // 壊れたファームを消し err = FSL_Erase( target_block ); // 分割書き込み分繰り返す for( split_write_count = 0; split_write_count < SELF_UPDATE_SPLIT_WRITE_NUM; split_write_count += 1 ){ // 書き込みデータをバッファにためる buffer_fill = 0; do{ data_buffer[ buffer_fill ] = *p_rom; p_rom += 1; buffer_fill++; }while( buffer_fill != (u8)SELF_UPDATE_BUFF_SIZE ); // 書き込み err = 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 ) ); if( err != FSL_OK ){ FSL_Close(); return( ERR_ERR ); } } // 1ブロック書き込み完了したので内部ベリファイを行う while( FSL_IVerify( target_block ) != FSL_OK ){ ; } } // todo //  それでもだなら、LEDちかちかとかさせて、サービス送りにしてもらう // リブート // スワップは不要です! FSL_ForceReset(); return( ERR_SUCCESS ); } u8 chk_bootCluster(){ u8 data_buffer[ SELF_UPDATE_BUFF_SIZE ]; u8 err; DI(); FSL_Open(); // 割り込み禁止など err = FSL_Init( data_buffer ); // ライブラリ初期化。割り込み中断考慮せず err |= FSL_ModeCheck(); // ライトプロテクトチェック。失敗することを考慮せず err |= FSL_GetActiveBootCluster( &boot_ura ); FSL_Close(); } // ======================================================== 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を止める 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 }