#pragma section @@CODE c_flash #pragma section @@BITS c_f_bits AT 0xFE88 #pragma section @@DATA c_f_data AT 0xFE90 #pragma HALT #pragma NOP #include "macrodriver.h" #include "user_define.h" #include "jhl_defs.h" #include "I2C_selfprog.h" #include "SelfLib.h" #include "user_define.h" #include "Timer.h" extern sreg UCHAR EntryRAM[]; bit self_prog_mode; u8 writeBuffer[16]; struct stWordAddress self_prog_settings; /***************************************************************************** I2Cから自己書き換え 書き換える範囲は 0x0000 - 0x1FFFまで。 I2Cをほかで使っているので、フラグなどで飛んできてください。 書き換え完了後は電源再投入が必要です。 マイコンは停止します。 *****************************************************************************/ void self_programming(){ u8 status; self_write_init(); led_wifi = 1; FlashStart(); FlashEnv( EntryRAM ); if( self_write_eraseall() != 0 ){ led_R_on; FlashEnd(); LREL0 = 1; while(1){} } led_wifi = 0; /// フラッシュの準備 /// self_prog_settings.WriteBank = 0; //// 各行の処理 //// while( 1 ){ led_wifi = 1; status = i2c_firm_rcv_line(); if( status != 0 ){ led_G_on; FlashEnd(); LREL0 = 1; LSRSTOP = 0; WDTE = 0x4A; // リセット while(1){} } led_wifi = 0; status = write_firm_line(); if( ( status & 0x80 ) != 0 ){ // フラッシュ異常中断 FlashEnd(); LREL0 = 1; while(1){} } led_wifi = 0; } FlashEnd(); WDTE = 0x01; // リセット while(1){} } /***************************************************************************** 下準備 *****************************************************************************/ static void self_write_init(){ // SPIE0 = 1; WTIM0 = 1; // ウェイトコンディションをだす。(仮) // B // TMHE1 = 0; /* stop TimerH0 */ TOEN1 = 0; /* disable output */ led_G_pwm; // R // TMHE0 = 0; /* stop TimerH0 */ TOEN0 = 0; /* disable output */ led_R_pwm; // Y // TCE50 = 0; /* TM50 counter disable */ TOE50 = 0; /* output disabled */ // TM50_Stop(); // LED_Wifi これ使っちゃだめ! led_wifi = 1; LSRSTOP = 1; // WDT停止 DI(); MK0 = 0xFFFF; MK1 = 0xFFFF; EI(); } /***************************************************************************** 書き込み対象の部分を消去 *****************************************************************************/ static u8 self_write_eraseall(){ u8 flash_status = 0; u8 temp; flash_we = 1; if( CheckFLMD() != 0 ){ return( 128 + 1 ); } for( temp = 0; temp != (u8)( ( 0x2800 & 0xFC00 ) >> 10 ); temp++ ){ if( FlashBlockBlankCheck( 0, temp ) == 0x1B ){ flash_status |= FlashBlockErase( 0, temp ); } } if( flash_status != 0 ){ return( 128 + 2 ); } } /***************************************************************************** 一行分受信。データ足りない部分は0xFFでパディングするようになってるけど、 元データをちゃんとしてあるので本来不要 *****************************************************************************/ static u8 i2c_firm_rcv_line(){ u8 rec_length; u8 data_counter; u8 temp; // ':' レコードマーク do{ IICIF0 = 0; WREL0 = 1; while( ( IICIF0 == 0 ) && ( SPD0 == 0 ) ){ ; } if( SPD0 == 1 ){ return( 1 ); // 書き換え終了。 } }while( IIC0 != ':' ); // タイムアウトとかなしで永遠ループ // レコード長 rec_length = rcvHex2bin(); // アドレス temp = rcvHex2bin(); // 上位 self_prog_settings.WriteAddress = (u8*)( ( (u16)temp << 8 ) + rcvHex2bin() ); // 下位 // "00" (レコードタイプ) if( rcvHex2bin() == 01 ){ return( 2 ); // 書き換え終了。 } // ここからデータ for( data_counter = 0; data_counter < rec_length; data_counter++){ writeBuffer[ data_counter ] = rcvHex2bin(); } // サム(読み捨て) rcvHex2bin(); // 改行コード \r\n はここでは見ないよ // 0xFFで残りをパディング while( data_counter < 16 ){ writeBuffer[ data_counter ] = 0xFF; data_counter++; } return( 0 ); } /***************************************************************************** 実書き込み 4ワード16バイトずつ。 *****************************************************************************/ static u8 write_firm_line(){ // ライターアップデート1は、 // 0x0000 - 0x1FFF ブート&本体を動かすコード // 0x2000 - 0x27FF 自己書き換えコード // 0x2800 - 空き。 // // ライターアップデート2`は、 // 0x0000 - 0x1FFF ブート&本体を動かすコード // 0x2000 - 0x27FF (空き) // 0x2800 - 自己書き換えコード // です if( self_prog_settings.WriteAddress >= (u8*)0x2800 ){ // EEPエミュレーションで書き換えない範囲 return( 2 ); }else{ // 書き換える範囲 led_R_on; if( FlashWordWrite( &self_prog_settings, 4, writeBuffer ) != 0 ){ return( 128 + 64 + 1 ); } led_G_on; if( FlashBlockVerify( 0, (u8)( ( (u16)(self_prog_settings.WriteAddress) & 0xFC00 ) >> 10 ) ) != 0 ){ // ライト リトライ led_R_pwm; if( FlashWordWrite( &self_prog_settings, 4, writeBuffer ) != 0 ){ return( 128 + 64 + 2 ); } if( FlashBlockVerify( 0, (u8)( ( (u16)(self_prog_settings.WriteAddress) & 0xFC000 ) >> 10 ) ) != 0 ){ // 内部電荷診断エラー return( 128 + 64 + 3 ); } } // 1行完了しました。 led_G_pwm; led_R_pwm; } return( 0 ); } /***************************************************************************** 2バイト分のヘキサを受信してバイナリを返す。 0x31 0x33 → 0x13 エラー処理とかしてないです。 ポーリングです。 *****************************************************************************/ static u8 rcvHex2bin(){ u8 dat; u8 temp; IICIF0 = 0; WREL0 = 1; while( IICIF0 == 0 ){ ; } temp = IIC0; if( ( '0' <= temp ) && ( temp <= '9' ) ){ dat = ( temp - '0' ); }else if( ( 'A' <= temp ) && ( temp <= 'Z' ) ){ dat = ( temp - 'A' + 10 ); }else if( ( 'a' <= temp ) && ( temp <= 'z' ) ){ dat = ( temp - 'a' + 10 ); } dat <<= 4; IICIF0 = 0; WREL0 = 1; while( IICIF0 == 0 ){ ; } temp = IIC0; if( ( '0' <= temp ) && ( temp <= '9' ) ){ dat |= ( temp - '0' ); }else if( ( 'A' <= temp ) && ( temp <= 'Z' ) ){ dat |= ( temp - 'A' + 10 ); }else if( ( 'a' <= temp ) && ( temp <= 'z' ) ){ dat |= ( temp - 'a' + 10 ); } return( dat ); }