/* ======================================================== 自己アップデータ ======================================================== */ #ifndef _WIN32 #pragma SFR #pragma di #pragma ei #pragma nop #pragma stop #pragma halt #endif #include "incs_loader.h" #include #include "fsl_user.h" #include "i2c_ctr.h" #include "pool.h" #include "magic.h" #include "pm.h" // ======================================================== const u8 fsl_fx_MHz_u08 = 8; const u8 fsl_low_voltage_u08 = 1; // 自己フラッシュパラメータ #define SAM_BLOCK_SIZE 1024 // ↓256バイト以上はまとめてかけません。 #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 ALTERNATE_FIRMTOP 20 #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 #ifndef _WIN32 #define LED_POW1 P1.5 #define LED_PM_POW1 PM1.5 #else #define LED_POW1 mcuRegP[ _P1_5 ] #define LED_PM_POW1 mcuRegPM[ _P1_5 ] #endif // ======================================================== static void FSL_Open( void ); static void FSL_Close( void ); void firm_restore( ); static err my_FSL_Init(); static err firm_duplicate( u8 block_src, u8 block_dest ); #ifdef _DBG_LED_PRINT_ void alert( u8 ); void led_print( u8 ); #else # define alert( x ) ; # define led_print( x ) ; #endif // ======================================================== extern uni_pool pool; // 0.D以降 新アップデータ向け // 新ファームは大丈夫? #define N_MGC_L 0x1FF6 #define N_MGC_T 0x4FF6 /* ======================================================== I2Cで受信して、 書き込み、 チェックOK → 新ファームに切り替えて再起動     NG → 旧(現)ファームに戻して再起動 (この関数からは戻りません) ======================================================== */ void firm_update( ) { u8 target_block; u8 split_write_count; // ブロックへちまちま書き込むカウンタ // 書き替え前準備 ///////////////////////////////////// my_FSL_Init(); /* ファームのバックアップ 開始アドレス、書き込み先の先頭”ブロック番号” (サイズは FIRM_SIZE) 0x2000 - 0x4FFF を 0x5000 - 0x7FFF (ブロック 20 - 31) にコピー */ firm_duplicate( FIRM_TOP, ALTERNATE_FIRMTOP ); // 全ブロック削除 ///////////////////////////////////// // 電源断を判定するため、最初に全クラスタ消去する //(新ファームが書かれるところに残ってる、以前のファームのフッタを消したい) for( target_block = INACTIVE_BOOTSECT_TOP; target_block < ALTERNATE_FIRMTOP; target_block ++ ) { FSL_Erase( target_block ); } // 書き替え /////////////////////////////////////////// // ●ストップコンディションが来るまで続ける // ●終わったら、スタートアップルーチンに飛ぶ for( target_block = INACTIVE_BOOTSECT_TOP; target_block < ALTERNATE_FIRMTOP; target_block ++ ) { u8 my_spd; /* すでに消してある。でないと中断されたとき終了してるか判別出来ない // // 新ファーム領域削除 // FSL_Erase( target_block ); */ // 分割書き込み for( split_write_count = 0; split_write_count < SELF_UPDATE_SPLIT_WRITE_NUM; split_write_count ++ ) { u8* p_buffer = &pool.self_update_work[0]; u16 buff_written_size = 0; WDT_Restart( ); // I2Cから書き込みデータをバッファにためる do { while( !IICAIF && !SPD ) {;} my_spd = SPD; IICAIF = 0; *p_buffer = IICA; WREL = 1; p_buffer ++; buff_written_size ++; } while( ( buff_written_size != SELF_UPDATE_BUFF_SIZE ) && !SPD ); my_spd += 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 ) { alert(1); // 書き込み後のチェックエラー // リストア firm_duplicate( ALTERNATE_FIRMTOP, FIRM_TOP ); FSL_ForceReset(); // リセット // FSL_SwapBootCluster( ); // ブートスワップ「せずに」再起動って出来ないらしい // 戻ってこない // } if( my_spd != 0 ) { break; } } // 1ブロック書き込み完了。内部ベリファイを行う if( FSL_IVerify( target_block ) != FSL_OK ){ alert(2); // 再度消去→書き込み ベリファイを繰り返すだけじゃダメでした... /// 再書き込みすべき? // リストア firm_duplicate( ALTERNATE_FIRMTOP, FIRM_TOP ); FSL_ForceReset(); // リセット // FSL_SwapBootCluster( ); // ブートスワップ「せずに」再起動って出来ないらしい // 戻ってこない // } if( my_spd != 0 ) { break; } } LREL = 1; // 書き込んだファームのチェック // { u8 i; u8 comp = 0; // ローダーのマジックと、本文の末尾のマジックは同じか確認 for( i = 0; i < sizeof( __TIME__ ); i++ ) { comp += (u8)(( (*( __far u8 * ) ( N_MGC_L + i )) == (*( u8 * ) ( N_MGC_T + i ) )) ? 0 : 1); } if( *( __far u8 * )( N_MGC_L +2 ) != ':' ) // 消去済のまま { comp ++; } if( comp == 0 ) { // OK! FSL_InvertBootFlag( ); FSL_SwapBootCluster( ); // リセットせずに頭から。FSL_Closeは不要 } else { // データ(マジックナンバーしか見てない)エラー // リストア alert(3); firm_duplicate( ALTERNATE_FIRMTOP, FIRM_TOP ); FSL_ForceReset(); // リセット // FSL_SwapBootCluster( ); // ブートスワップ「せずに」再起動って出来ないらしい } // 戻ってこない // } } /* ========================================================  ■ファームをバックアップ領域からリストアします。  チェック後、最後の最後でブートスワップするので、  ここではブートスワップは不要です。 ======================================================== */ void firm_restore( ) { DBG_LED_on; LED_PM_POW1 = 0; // バックアップは正常? // { u16 i; u8 comp = 0; for( i = 0; i < sizeof( __TIME__ ); i++ ) // sizeof( __TIME__ ) = 8 らし { comp += ( *( __far u8 * )( MGC_LOAD + i ) == *( u8 * )( MGC_HEAD_BKUP + i ) ) ? 0 : 1; comp += ( *( u8 * )( MGC_HEAD_BKUP + i ) == *( u8 * )( MGC_FOOT_BKUP + i ) ) ? 0 : 1; } if( *( u8 * )( MGC_FOOT_BKUP ) == 0xFF ) { comp ++; } if( comp != 0 ) { // バックアップ領域も壊れた... comp = 0; // 3.3Vが上がらないと困る EI( ); iic_mcu_start( ); RESET2_ast; FCRAM_RST_ast; GYRO_DISABLE(); PM_LDSW_on(); wait_ms( 1 + DELAY_PM_TW_PWUP ); PM_VDD_on( ); while(1) { WDT_Restart(); { // 赤LED ピコピコ comp++; LED_POW1 = ( comp == 1 || comp == 3 )? 1: 0; if( comp == 8 ) { comp = 0; } } { // 電源ボタンで電源off static u8 sw_hold_count; if( !SW_POW_n_RAW ) { sw_hold_count++; } else { sw_hold_count = 0; } if( sw_hold_count > 16 ) { sw_hold_count = 0; // 電源off PM_LDSW_off( ); break; } } // ウェイト for( i = 1; i != 0; i++ ) { NOP(); NOP(); NOP(); NOP(); } } { // ど、どうしよう…。 KRM = ( KR_SW_POW ); // Mask ではなく、Modeなのだそうだ。紛らわしい MK0 = 0xFFFF; MK1 = ~( INT_MSK1_KR ); MK2L = 0xFF; // PU5 そのまま PU7 = bits8(0,0,0,0, 1,0,0,0); // PWSWI PU20 = bits8(0,0,0,0, 0,0,0,0);; // SW_HOME 停止 STOP( ); mcu_wdt_reset; } } } if( my_FSL_Init() != ERR_SUCCESS ){ alert(1); } /* ファームのリストア 0x4800 - 0x7FFF (ブロック 18 - 27) から 0x2000 - 0x47FF (ブロック 8 - 17) へコピー */ if( firm_duplicate( ALTERNATE_FIRMTOP, FIRM_TOP ) != ERR_SUCCESS ) { alert(2); } DBG_LED_off; // todo リストア失敗したら、LEDちかちかとかさせて、サービス送りにしてもらう? /* // リブート if( FSL_InvertBootFlag() != ERR_SUCCESS ) { alert(3); } */ FSL_ForceReset(); // リセット // FSL_SwapBootCluster( ); // ブートスワップ「せずに」再起動って出来ないらしい } // ======================================================== 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 while( DST1 ){;} // DMA停止 DEN1 = 0; MK0 = 0xFFFF; MK1 = 0xFFFF; MK2 = 0xFFFF; /* LVIM = bits8(0,0,0,0, 0,0,1,0); LVIS = bits8(0,0,0,0, 1,0,0,0); LVIM = bits8(1,0,0,0, 0,0,1,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 } /* ========================================================  マイコン内でファームをコピーします。 __far u8 * p_rom コピー元の先頭アドレス block_dest コピー先の先頭ブロック コピー先に書けるようにmy_FSL_Initをあらかじめ実行する必要があります。 ======================================================== */ //static err firm_duplicate( __far u8 * p_rom, // u8 block_dest ) static err firm_duplicate( u8 block_src, u8 block_dest ) { u8 target_block; u8 split_write_count; // ブロックへちまちま書き込むカウンタ __far u8* p_src = ( __far u8* )( block_src * 0x400 ); u8 retry_error; led_print(1); // 書き込み先ブロックの数だけ繰り返す for( target_block = block_dest; target_block < ( block_dest + FIRM_SIZE ); target_block ++ ) { led_print(2); WDT_Restart( ); // ブロック消去 retry_error = 5 + 1; while( FSL_BlankCheck( target_block ) != FSL_OK ) { led_print(3); FSL_Erase( target_block ); if( -- retry_error == 0 ) { // フラッシュ寿命? FSL_Close( ); return ( ERR_ERR ); // リセット&復帰を試みる どうなるか知らん } } led_print(4); // 分割書き込み分繰り返す for( split_write_count = 0; split_write_count < SELF_UPDATE_SPLIT_WRITE_NUM; split_write_count ++ ) { u16 buff_written_size; u8* p_buff; // 書き込みデータをバッファにためる buff_written_size = 0; p_buff = &pool.self_update_work[0]; do { *p_buff = *p_src; p_src ++; p_buff ++; buff_written_size ++; } while( buff_written_size != 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( ); led_print(5); // while(1){} return ( ERR_ERR ); } } led_print(6); // 1ブロック書き込み完了。内部電圧チェックを行う while( FSL_IVerify( target_block ) != FSL_OK ) { // リカバリはリブート時 // led_print(7); return ( ERR_ERR ); } } return( ERR_SUCCESS ); } /* ======================================================== ======================================================== */ static err my_FSL_Init() { u8 rv; RTCE = 0; // 書き替え前準備 // DI( ); FSL_Open( ); // 割り込み禁止など FSL_Init( &pool.self_update_work[0] ); // ライブラリ初期化。割り込み中断考慮せず rv = FSL_ModeCheck( ); // ライトプロテクトチェック。失敗することを考慮せず return( (err)rv ); } task_status_immed tski_mcu_reset() { // 普通に再起動 my_FSL_Init(); FSL_ForceReset(); // リセット FSL_Close( ); // 保険? // mcu_wdt_reset; return( ERR_SUCCESS ); // no reach } #ifdef _DBG_LED_PRINT_ // P1.5 = led_pow_red_old void alert( u8 num ) { u8 i; while(1) { WDT_Restart(); LED_POW1 = 1; for( i = 0; i < num; i++ ) { DBG_LED_on; DBG_LED_off; } LED_POW1 = 0; } } void led_print( u8 num ) { u8 i; DBG_LED_on; for( i = 0; i < num; i++ ) { LED_POW1 = 1; LED_POW1 = 0; } DBG_LED_off; } #endif