twl_mcu/I2C_selfprog.c
2024-12-17 04:24:29 -05:00

273 lines
6.6 KiB
C

#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 );
}