ctr_mcu/snake_trunk/task_sys.c

686 lines
19 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.

/* ========================================================
task_sys
電源周りを司るのタスク
$Id$
======================================================== */
#ifndef _WIN32
#pragma SFR
#pragma NOP
#pragma HALT
#pragma STOP
#endif
#include "incs.h"
#include "i2c_twl.h"
#include "i2c_ctr.h"
#include "led.h"
#include "accero.h"
#include "pm.h"
#include "rtc.h"
#include "sw.h"
#include "adc.h"
#include "self_flash.h"
#include "i2c_mcu.h"
#include "vreg_twl.h"
//=========================================================
#define WAIT_SHIROBAKO_POW_CONTROL 240
//=========================================================
extern void nop8();
static void chk_emergencyExit();
static void force_off_check();
static void send_getup_to_soc();
#ifdef _DBG_CHK_OFF_LEAK_
static void leak_check();
#endif
//=========================================================
extern bit info_led_off;
extern bit going_to_sleep;
extern bit bt_authorized;
static u8 timeout_sleep;
extern u8 chg_led_override;
#ifdef i2c_timeout_test
extern bit i2c_mcu_time_out_error;
#endif
//=========================================================
#define PWSW_POWON_TIME (u8)( 20 / SYS_INTERVAL_TICK ) // [ms] // INTERVAL_TSK_SW で割らない。値が元から小さいので
#define PWSW_ON_CHECK_TIMEOUT 100 // 適当 電源onの為に電源スイッチが操作されたとき、この時間経過したらmcuを省電力に戻す
/********************************************//**
電源の立ち上げやスリープなどを管理
***********************************************/
void tsk_sys( )
{
static u8 pwsw_timeout = 0; // 電源ボタンチャタリング回避。 タイムアウトするまでに電源投入確定しないとoffに戻る
hal_update();
switch ( system_status.pwr_state )
{
case ON_CHECK: //-------------------------------------------------------
// 強制電源断カウントダウンタイマクリア
clear_pow_off_countdown();
// 他の割り込みでHALT(スリープ)が解除 / アダプタ有時
// 電源スイッチでHALT解除 //
if( system_status.poweron_reason == RSN_PWSW )
{
if( PM_EXTDC_n )
{
// アダプタなし
if( SW_pow_count != 0 )
{
pwsw_timeout = 0;
}
else
{
pwsw_timeout ++;
}
if( pwsw_timeout > PWSW_ON_CHECK_TIMEOUT )
{
SW_pow_count = 0;
system_status.pwr_state = OFF_TRIG; // スイッチはノイズだった。寝る。
renge_task_interval_run_force = true;
return;
}
}
else
{
BT_chk();
}
if( SW_pow_count < PWSW_POWON_TIME )
{
// 押し時間が短くて電源onに到達していない
return;
}
}
// else { if( system_status.poweron_reason == RSN_TRIAL、… ) 電源投入 }
SW_pow_mask = true; // pwsw押しっぱなしで電源入/切 を繰り返さないように
// 電源投入 //
iic_mcu_start( );
bt_force_update = false;
BT_chk(); // 実機やバッテリの判定、電池残量ICの設定
#ifndef _ALLOW_NOBATT_
if( system_status.model == MODEL_JIKKI_NOBATT )
{
renge_task_interval_run_force = true;
system_status.pwr_state = OFF_TRIG;
return;
}
#endif
// 残量チェック
BT_get_left(); // 先に、BT_chk()が実行されている必要があります。
if(
// ( vreg_ctr[VREG_C_BT_REMAIN] < 1 ) // こっちで判定すると電池がほとんど無いときに
// // アダプタ差しても数分起動できなくなっちゃう
( vreg_ctr[VREG_C_BT_VOLTAGE] < ( V_TH_ZERO / 256 ) ) // 電池空っぽ
)
{
// 電池が少ないので起動させない(電圧チェックもされてる)
renge_task_interval_run_force = true;
system_status.pwr_state = OFF_TRIG;
return;
}
// ポートの方向設定 電源入れる前に。
PM_SW_WIFI_n = 1;
PM_SW_HOME_n_JIKKI = 1;
PM_WL_TX = 1;
PM_SW_SEL_n = 1;
PM_ACCEL_INT1 = 1;
PM_ACC_VALID = 1;
if( PM_sys_pow_on( ) != ERR_SUCCESS )
{ // 電源起動不可エラー
renge_task_interval_run_force = true;
system_status.pwr_state = OFF_TRIG;
return;
}
// ここまで来ると、電源投入確定 //
// プルアップon
PU_BT_IN_CHG_n = 1;
PU7 = bits8(0,0,0,1, 1,1,0,1); // 4:SW_WIFI 3:SW_PWSW 2:PM_IRQ 0:PM_EXTDC_n
PU_SW_HOME_n_JIKKI = 1; // SW_HOME
reset_release();
if( system_status.poweron_reason == RSN_PWSW ||
system_status.poweron_reason == RSN_TRIAL )
{
// 電源ボタンでのonの時は、LEDを点灯させる
vreg_ctr[VREG_C_LED_POW] = LED_POW_ILM_AUTO;
}
else
{
// とりあえず、LED消灯状態で起動させる
vreg_ctr[VREG_C_LED_POW] = LED_POW_ILM_OFF;
}
system_status.pwr_state = ON_TRIG;
PM_LCD_vcom_set( ); // LCDの対向電圧値など書き込み
break;
case ON_TRIG: //-------------------------------------------------------
#ifdef i2c_timeout_test
LED_duty_pow_blu = 0; // debug
LED_duty_3d = 0;
LED_duty_notify_red = 0;
LED_duty_notify_grn = 0;
LED_duty_notify_blu = 0;
LED_pow_red = 0;
LED_CAM = 0;
i2c_mcu_time_out_error = false;
#endif
/// ここでやるべきでは?
// プルアップon
PU_BT_IN_CHG_n = 1;
PU7 = bits8(0,0,0,1, 1,1,0,1); // 4:SW_WIFI 3:SW_PWSW 2:PM_IRQ 0:PM_EXTDC_n
PU_SW_HOME_n_JIKKI = 1; // SW_HOME
IIC_ctr_Init( );
IIC_twl_Init( );
vreg_twl_init( );
vreg_ctr_reset( );
KRM = bits8(0,0,0,0, 0,0,0,0);
PIF0 = 0;
system_status.poweron_reason = NONE;
renge_task_interval_run_force = true;
MK0 = INT_MSK0_RSV;
MK1 = INT_MSK1_RSV;
iic_mcu_start();
// MK2 = ~( INT_MSK2_IIC_TWL | INT_MSK2_WIFI_TX_BSR | INT_MSK2_CODEC_PMIRQ );
// PMK21 = 0; // wifi 使わない
PMK6 = 0; // pm_irq
// リブート時、ステータスを辻褄合わせ
if( system_status.reboot )
{
u8 bl_status_temp;
// LCD 電源onだったか ステータスの更新をする。
/// ファーム更新時、必ず液晶offかも
if( read_pmic( PM_REG_ADRS_VDD_LCD ) != 0 )
{
vreg_ctr[ VREG_C_STATUS ] |= REG_BIT_LCD_POW;
// LCD_AMOL_HV_CTRL = 1; 不要。ファーム更新時、ピン状態は保持のため。
}
// バックライトが点いていた? ステータスの更新をする。
bl_status_temp = read_pmic( PM_REG_ADRS_BL );
vreg_ctr[ VREG_C_STATUS ] |= (( bl_status_temp & 0x03 ) << 5 );
// バッテリ&本体識別
BT_chk();
}
LED_init( ); // reboot時の↑BT_Chk,BT_chk後に行いたい
system_status.reboot = 0;
system_status.pwr_state = ON;
// WDTリセット時、I2Cの初期化まで割り込み保留
// ほんとはここにべた書きしたくないが...
if( ( vreg_ctr[ VREG_C_MCU_STATUS ] & REG_BIT_STATUS_WDT_RESET ) != 0 )
{
set_irq( VREG_C_IRQ0, REG_BIT_IRQ_WDT_RESET );
}
break;
case ON: //---------------------------------------------
// PMICによる強制電源断チェック
// デバッガがreset1をアサートすることもある。そのときは全部リセット
chk_emergencyExit();
// SLP監視
if( going_to_sleep ) // 絶対に SLP_REQ の前に予告が来る
{
timeout_sleep ++;
if( timeout_sleep == 0 || // オーバーフローを期待。sleepするって言ったけど一瞬で起きて気がつかなかった
( PIF0 && !SLP_REQ )) // slp割り込みが入った気がしたが、もう起きてしまった
{
PIF0 = 0;
send_getup_to_soc();
}
if( PIF0 && SLP_REQ ){
PIF0 = 0;
PM_VDD_ecoMode();
system_status.pwr_state = SLEEP;
renge_task_interval_run_force = true;
}
}
// 強制offカウント
force_off_check();
#ifndef _TAIKENDAI_SEISAN_SPECIAL_
if( system_status.taikendai ) // アダプタが抜けたら自動で電源off
{
if( PM_EXTDC_n )
{
system_status.pwr_state = OFF_TRIG;
}
}
#endif
break;
case SLEEP: //------------------------------------------
chk_emergencyExit();
// スリープから復帰
if( !SLP_REQ ){
PM_VDD_normMode();
wait_ms( 5 ); // tdly_sw
send_getup_to_soc();
system_status.pwr_state = ON;
}
force_off_check();
// leak_check();
#ifndef _TAIKENDAI_SEISAN_SPECIAL_
if( system_status.taikendai ) // アダプタが抜けたら自動で電源off
{
if( PM_EXTDC_n )
{
system_status.pwr_state = OFF_TRIG;
}
}
break; // ←ここでよい。
#else
/* FALLTHROUGH */
#endif
default: //---------------------------------------
system_status.pwr_state = OFF_TRIG; // あり得ないステート。デバッグ用
// dbg_nop();
/* FALLTHROUGH */
case OFF_TRIG: //---------------------------------------
// LED消灯を待つ
vreg_ctr[ VREG_C_LED_POW ] = LED_POW_ILM_OFF;
vreg_ctr[ VREG_C_LED_WIFI ] = WIFI_LED_OFF;
vreg_ctr[ VREG_C_LED_3D ] = LED_3D_ILM_OFF;
info_led_off = true;
if( LED_duty_pow_blu != 0 )
{
return;
}
// 強制電源断カウントダウンタイマクリア
clear_pow_off_countdown();
// 加速度センサ停止
vreg_ctr[ VREG_C_ACC_CONFIG ] = 0x00;
tski_acc_setup();
EI(); // DI状態でかえって来るので、I2C_mcu 完了させるのに必要を
// その他ペリフェラル停止
LED_stop( );
IIC_ctr_Stop( );
IIC_twl_Stop( );
RTC_32k_off();
// 電源オン条件の割り込みセット
// PWSW KR3 押すとL
// BG24 KR4
// ふた開け INTP5 閉じるとL
// ACアダプタ INTP4 アダプタありでL
// RTC
while( iic_mcu_busy )
{;}
// irqマスク設定
KRM = ( KR_SW_POW ); // Mask ではなく、Modeなのだそうだ。紛らわしい
MK0 = ~( INT_MSK0_EXTDC | INT_MSK0_WDTI );
MK1 = ~( INT_MSK1_KR | INT_MSK1_RTCINTVAL ); // INT_MSK1_RTCALARM | RTCアラーム封印中
MK2L = 0xFF;
// irqフラグクリア
vreg_ctr[VREG_C_IRQ0] = 0;
vreg_ctr[VREG_C_IRQ1] = 0;
vreg_ctr[VREG_C_IRQ2] = 0;
vreg_ctr[VREG_C_IRQ3] = 0;
// PU5 そのまま
PU7 = bits8(0,0,0,0, 1,0,0,1); // PWSWI,PM_EXTTDC,( IRQ0_deactive(), PM_IRQ_deactive )
PU_SW_HOME_n_JIKKI = 0; // SW_HOME 停止
IF0 = 0;
IF1 = 0;
IF2 = 0;
IRQ0_disable;
PM_sys_pow_off( ); // 電源カットオフ
// ポート類を停止モードに。こういう回路でも、L出力にしなきゃだめだそうな。
SW_WIFI_n_RAW = 0;
PM_SW_WIFI_n = 0;
SW_HOME_n_JIKKI_RAW = 0;
PM_SW_HOME_n_JIKKI = 0;
WL_TX = 0;
PM_WL_TX = 0;
SW_SEL_n = 0;
PM_SW_SEL_n = 0;
ACCEL_INT1 = 0;
PM_ACCEL_INT1 = 0;
ACC_VALID = 0;
PM_ACC_VALID = 0;
system_status.pwr_state = OFF;
SW_pow_mask = true;
SW_pow_count = 0;
// HALデバッグリセット 忘れると電源on出来なくなることが…
hal_reset();
/* FALLTHROUGH */
case OFF:
// 注:現状では電源ボタンしか電源投入はありません。
system_status.poweron_reason = NONE;
pwsw_timeout = 0;
LCD_AMOL_HV_CTRL = 0; // 異常終了時、アモルファスLCD用電源を切り忘れてしまう
if( !PM_EXTDC_n
|| chg_led_override != 0 ) // これがゼロになるまで待つ
{
// アダプタ有り /////////////////////////////// または、アダプタさして秒は充電LEDを点けている期間
// 電源ボタン押しチェックへ
system_status.poweron_reason = RSN_PWSW;
system_status.pwr_state = ON_CHECK;
#ifndef _TAIKENDAI_SEISAN_SPECIAL_
// 試遊台なら自動で電源再投入
if( system_status.taikendai )
{
vreg_ctr[ VREG_C_HAL_OVW_CONT0 ] = vreg_ctr[ VREG_C_HAL_OVW_CONT1 ] = 0;
wait_ms(46); // pmicの電源再投入仕様のため
system_status.poweron_reason = RSN_TRIAL;
system_status.pwr_state = ON_CHECK;
}
#endif
}
else
{
// アダプタなし ///////////////////////////////
// 省電力へ移行
iic_mcu_stop( );
pm_chk_adapter();
PM_Chg_Stop();
bt_force_update = true;
while( RWST )
{;}
// 割り込み待ちで寝る //
RTCIMK = 1; // systick用インターバルタイマー割り込みマスク
#ifdef _DBG_CHK_OFF_LEAK_
leak_check();
#endif
CKC = bits8(0,0,0,0, 1,0,0,1); // 4MHzに落として(bit0)からSTOPしなくてはならない
OSMC = bits8(0,0,0,0, 0,0,0,0); // 5MHz以下モードへ。
if( PM_EXTDC_n_RAW ) // きわどいタイミングで挿抜が起きることがある。HAL通さないべきoff中ですし
{
STOP();
}
// 起きる //
// 起きる条件は
// ・KeyReturn割り込み電源ボタン
// ・RTCアラーム現在封印
// クロック復帰
OSMC = bits8(0,0,0,0, 0,0,0,1); // 8MHz動作準備
renge_flg_interval = 0;
hal_update();
CKC = bits8(0,0,0,0, 1,0,0,0); // OSMC.FSEL = 1 後3clk以上開ける
// 起きた理由は?
if( !PM_EXTDC_n ){
system_status.pwr_state = OFF; // 一回回ってきて、ON_CHECKに行く
}
/* // RTCアラーム。封印中
else if( vreg_ctr[ VREG_C_IRQ1 ] & REG_BIT_RTC_ALARM )
{
system_status.poweron_reason = RSN_RTC_ALARM;
system_status.pwr_state = ON_CHECK;
}
// else if( 他の割り込みで電源on ){
// 現状他の要因では起きない
// }
*/
else // if( !SW_POW_n ) // (それ以外なら)電源ボタンで起きた
{
SW_pow_mask = false;
system_status.poweron_reason = RSN_PWSW;
system_status.pwr_state = ON_CHECK;
}
RTCIMK = 0; // sys tick タイマー有効
#ifndef _TAIKENDAI_SEISAN_SPECIAL_
if( system_status.taikendai )
{
system_status.pwr_state = OFF_TRIG;
}
#endif
}
}
}
/********************************************//**
PMICが電源異常で止めたか確認
***********************************************/
static void chk_emergencyExit(){
static u8 shirobako_power_control_count;
// wifi モジュールキャリブレーションモードでreset1を自分から下げてるときはチェックをパス
if( is_wifi_calib_resets_ast )
{
return;
}
if( shirobako_power_control_count == 0 )
{
if( !RESET1_n ) // PM_chk_LDSW() はI2C_mを使用し、高コスト
{
if( !PM_chk_LDSW() )
{
// リセットが下がってる
/// PMICが異常終了判断をした
system_status.pwr_state = OFF_TRIG;
renge_task_interval_run_force = true;
}
else
{
// 白箱の仕業
shirobako_power_control_count = 1;
}
}
}
else
{
if( shirobako_power_control_count == WAIT_SHIROBAKO_POW_CONTROL ) // マジックナンバー
// デバッガが何かした。reset1を解除するまでは無視
{
if( RESET1_n ) // リセットネゲート待ち
{
shirobako_power_control_count = 0;
}
else
{
// nothing to do
}
}
else if( shirobako_power_control_count == 200 ) // * (sys_tick)[ms]
// デバッガが何かしたいらしい
{
#ifndef _RVD_
// 白箱は電源を切りたいらしい
system_status.pwr_state = OFF_TRIG;
renge_task_interval_run_force = true;
shirobako_power_control_count = WAIT_SHIROBAKO_POW_CONTROL;
#endif
}
else
{
if( !RESET1_n )
{
if( shirobako_power_control_count != 255 )
shirobako_power_control_count ++;
}
else
{
// (TSボードで手動で/デバッガが)リセットをかけたらしい
send_cmd_pmic( PM_REG_ADRS_BL, 0 );
vreg_ctr[VREG_C_STATUS] = ( vreg_ctr[VREG_C_STATUS] & bits8(1,0,0,1, 1,1,1,1) );
vreg_ctr[VREG_C_COMMAND0] |= REG_BIT_RESET1_REQ;
renge_task_immed_add( tski_do_command0 );
shirobako_power_control_count = WAIT_SHIROBAKO_POW_CONTROL;
}
}
}
}
/********************************************//**
- 電源ボタン長押し
- 電池切れ
- 電池抜け
での強制OFF。発動すると解除不能
***********************************************/
static void force_off_check()
{
if( force_off )
{
system_status.pwr_state = OFF_TRIG;
renge_task_interval_run_force = true;
}
}
/********************************************//**
SoCを起こす
  電圧が通常に戻ってから呼んで下さい。
***********************************************/
void send_getup_to_soc()
{
going_to_sleep = false;
timeout_sleep = 0;
#ifdef _MODEL_CTR_
SLP_ACK = 1;
nop8();
SLP_ACK = 0;
#endif
}
/********************************************//**
自己アップデート firm_update() を呼ぶisr中から実行できないので
task_status_immed型 を返すようにすればいいのですが...
***********************************************/
task_status_immed tski_firm_update(){
firm_update();
return( ERR_SUCCESS );
}
#ifdef _DBG_CHK_OFF_LEAK_
/********************************************//**
pin設定ミスチェック
***********************************************/
static void leak_check()
{
volatile u8 ports_i[12];
volatile u8 ports_o[12];
ports_i[0] = ( PM0 & PU0 & ~P0 ); // プルアップ切り忘れ?
ports_i[1] = ( PM1 & PU1 & ~P1 );
ports_i[2] = 0;
ports_i[3] = ( PM3 & PU3 & ~P3 );
ports_i[4] = ( PM4 & PU4 & ~P4 );
ports_i[5] = ( PM5 & PU5 & ~P5 );
ports_i[6] = 0;
ports_i[7] = ( PM7 & PU7 & ~P7 );
ports_i[8] = ( PM12 & PU12 & ~P12 );
ports_i[9] = ( PM14 & PU14 & ~P14 );
ports_i[10] = 0;
ports_i[11] = ( PM20 & PU20 & ~P20 );
ports_o[0] = ( ~PM0 & P0 ); // H 出力しちゃってるかも
ports_o[1] = ( ~PM1 & P1 );
ports_o[2] = ( ~PM2 & P2 );
ports_o[3] = ( ~PM3 & P3 & ~POM3 );
ports_o[4] = ( ~PM4 & P4 ); // bit3はchg_enなので1でもよい
ports_o[5] = ( ~PM5 & P5 );
ports_o[6] = ( ~PM6 & P6 );
ports_o[7] = ( ~PM7 & P7 );
ports_o[8] = ( ~PM12 & P12 );
ports_o[9] = ( ~PM14 & P14 );
ports_o[10] = ( ~PM15 & P15 );
ports_o[11] = ( ~PM20 & P20 );
NOP(); // ←ブレーク置くため
}
#endif _DBG_CHK_OFF_LEAK_