/* ======================================================== 自己アップデータ ======================================================== */ #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( ); // 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 = ( __far 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 ); } WREL = 1; // ブロックの数だけ繰り返し 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: 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_ForceReset(); // リセット // FSL_SwapActiveBootCluster(); // ←スワップされてしまうので、続けられず暴走! // 戻ってこない // } 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; RTCE = 0; 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 = ( __far 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 ); } void 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を止める 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 }