ctr_mcu/trunk/self_flash.c
n2232 df4fdc2473 ■2.0F
・充電状況割り込みをtask_status -> task_batt へ統合
・Doxgenで処理できるように関数の看板を変更、追記など
コードそのものはお蔵入りになると思うのですが...
・include を少し整理

git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-05-23%20-%20ctr.7z%20+%20svn_v1.068.zip/ctr/svn/ctr_mcu@406 013db118-44a6-b54f-8bf7-843cb86687b1
2011-09-05 09:26:54 +00:00

636 lines
18 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* ========================================================
自己アップデータ
$Id$
======================================================== */
#ifndef _WIN32
#pragma SFR
#pragma di
#pragma ei
#pragma nop
#pragma stop
#pragma halt
#endif
#include "incs_loader.h"
#include <fsl.h>
#include "fsl_user.h"
#include "i2c_ctr.h"
#include "i2c_mcu.h"
#include "pool.h"
#include "magic.h"
#include "pm.h"
#include "WDT.h"
#include "util_funcs.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 P4.2
#define LED_PM_POW1 PM4.2
#else
#define LED_POW1 mcuRegP[ _P4_2 ]
#define LED_PM_POW1 mcuRegPM[ _P4_2 ]
#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( );
// pwsw待ちで寝る
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; // 無限ループするのはよくないと思う
// while(1){
// NOP(); // こない
// }
}
}
// ウェイト
for( i = 1; i != 0; i++ )
{
NOP();
NOP();
NOP();
NOP();
}
}
}
}
// else{ // バックアップは生きていた
while( my_FSL_Init() != ERR_SUCCESS ){ // FSL初期化失敗するようならもう救えない...
// todo リトライ回数上限?
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ちかちかとかさせて、サービス送りにしてもらう
FSL_ForceReset(); // リセット、戻ってこない
}
/********************************************//**
内蔵フラッシュの書き換えのための前準備
***********************************************/
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; // フラッシュ書き替え許可
}
/********************************************//**
内蔵フラッシュの書き換え終了処理
***********************************************/
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( 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 );
}
/********************************************//**
MCUリセット
system_status.reboot が立ちます。
***********************************************/
task_status_immed tski_mcu_reset()
{
// 普通に再起動
my_FSL_Init();
FSL_ForceReset(); // リセット
FSL_Close( );
// 保険? //
mcu_wdt_reset;
return( ERR_SUCCESS ); // no reach
}
/********************************************//**
書き換え中にエラーが発生した際にLEDを点滅させてエラーを通知
人が見るようではなく、オシロなどでパルス数をチェックする
デバッガが使えない区間なので LEDprintf デバッグのため。
***********************************************/
#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;
}
}
/********************************************//**
書き換え中にエラーが発生した際にLEDを点滅させてエラーを通知
人が見るようではなく、オシロなどでパルス数をチェックする
デバッガが使えない区間なので LEDprintf デバッグのため。
***********************************************/
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