/***************************************************************************** TWL マイコン de JHL 藤田@開技 nintendo '07 Jun., '07 Dec. 仕事 *ボリューム *リセット *カメラ LED *電源 LED *WiFi LED *CPUとのI2C通信 ******************************************************************************/ #include "incs.h" void reg_init(); void running_immediately(); void running(); void tsk_sw_vol(); // tsk_〜 …イベントループで呼ばれる void tsk_sw_pow(); void tsk_command_exec(); void wait_for_system_boot(); void save_BL_param(); //***************************************************************************** // タスクのインターバル用カウンタ、初期位相 インターバルはいくつにしよう? (1単位5ms) u8 tsk_interval_cnt_adc = 0, tsk_interval_adc = 200/25; // 200/x で x[Hz] u8 tsk_interval_cnt_power_led = 0, tsk_interval_power_led; u8 tsk_interval_cnt_sw_vol = 0, tsk_interval_sw_vol; u8 tsk_interval_cnt_wifi_led = 0, tsk_interval_wifi_led = 10; u8 tsk_interval_cnt_cam_led = 0, tsk_interval_cam_led = 160; // T = 0.8s bit adc_calib_mode; bit flg_interval; bit system_inited; bit vol_mute_start; bit rsv_set_vol; bit rsv_set_BL; bit rsv_set_PMIC_VRSET; bit rsv_set_camLED; bit rsv_set_batt_th; bit rsv_set_powLED; extern bit eeprom_bl_dirty; extern u8 battLvl; extern u8 vregs[]; sleep_status_ sleep_status = Wake; static u8 pwsw_state = 3; // スイッチ無視のためのもの。グローバルでないと困る extern u8 wifi_tx; // WifiLED の点滅ステート //############################################################################ //***************************************************************************** void main( void ){ // hdwinit( void ); // ←はmain()の前に自動で呼ばれています。 TM51_Start(); // イベントタイマ 標準で5ms間隔 // 電池残量少で電源入れた時のため // battLvl = 5; vregs[ REG_INT_ADRS_BATT_INFO ] = BATT_CO; vregs[ REG_INT_ADRS_MODE ] = 0x20; set_batt_th(); // メインループ // while( 1 ){ WDT_Restart(); running_immediately(); // インターバルタイマ外。割り込みなど起動 // // ↓インターバルタイマ内 if( flg_interval ){ // 5ms間隔で呼ばれます。他の割り込みでまわさないため。 flg_interval = 0; if( !system_inited ){ wait_for_system_boot(); // 電池残量 … リセット解除まではHiZ // #ifdef debug_codes dbg_keyCheck(); #endif }else{ if( adc_calib_mode != 0 ){ // ADC補正モード? tsk_adc_calib(); // T=4msに書き換えてしまいます。 }else{ // 通常運転 // #ifdef debug_codes pow_led_demo(); #endif running(); } } } HALT(); } } /****************************************************************************** インターバルを置いて毎周呼ばれるタスク ******************************************************************************/ void running(){ static u8 mcu_mode_in_wake; // 電源スイッチ・リセット線管理 tsk_sw_pow(); tsk_command_exec(); // スリープ/復帰の遷移時などにしなくてはいけないこと // if( ( PM_SLP == 0 ) && ( sleep_status != Wake ) ){ // sleepからwakeに遷移したところ。 sleep_status = Wake; vregs[ REG_INT_ADRS_MODE ] = mcu_mode_in_wake; // 復帰。きれいに書きたい PM_set_VRSET(); // twpwswと、sleep中の省電力設定 set_camled(); // カメラLED復帰 // trig_to_wake_wifiLed(); }else if( ( PM_SLP != 0 ) && ( sleep_status != Sleep ) ){ // wakeからsleepに sleep_status = Sleep; mcu_mode_in_wake = vregs[ REG_INT_ADRS_MODE ]; vregs[ REG_INT_ADRS_MODE ] = 0; PM_set_VRSET(); save_BL_param(); set_camled_stop(); trig_to_sleep_wifiLed(); } // 電源LED // if( vregs[ REG_INT_ADRS_POWER_LED ] == 0 ){ if( ++tsk_interval_cnt_power_led >= tsk_interval_power_led ){ tsk_interval_cnt_power_led = 0; tsk_power_led(); } led_pwm_GR_grad(); } // WiFi LED // if( ++tsk_interval_cnt_wifi_led >= tsk_interval_wifi_led ){ tsk_interval_cnt_wifi_led = 0; tsk_wifi_led(); } // cam LED // if( ++tsk_interval_cnt_cam_led >= tsk_interval_cam_led ){ tsk_interval_cnt_cam_led = 0; tsk_cam_led(); } // 音量/バックライト輝度スイッチ if( ++tsk_interval_cnt_sw_vol >= tsk_interval_sw_vol ){ // 間隔可変 tsk_interval_cnt_sw_vol = 0; tsk_sw_vol(); } // 電池残量 // if( ++tsk_interval_cnt_adc >= tsk_interval_adc ){ // ← 注意! カウンタ再利用してます! tsk_interval_cnt_adc = 0; tsk_adc(); } // 電源off時に、wifi reset をアサート if( PM_OFF ){ n_wifi_reset_ast; } } /****************************************************************************** レジスタ書き込みなどで起動が指示されたタスク ******************************************************************************/ void running_immediately(){ // I2Cで書き込まれたとき。 // ここで書かないと、キー操作でのS/W I2C中に H/W I2Cが入った際にバスが使用中だったりで困る。 if( rsv_set_camLED ){ rsv_set_camLED = 0; set_camled(); } // BL保存。 pmoffもしくは、電池切れそう // PM_OFFは80ms出る。 if( PM_OFF || ( battLvl <= 1 ) ){ save_BL_param(); } if( rsv_set_vol ){ rsv_set_vol = 0; dcp_vol_set(); } if( rsv_set_BL ){ rsv_set_BL = 0; BL_write(); } // NTR or TWLでtw_pww2の値を変える if( rsv_set_PMIC_VRSET ){ rsv_set_PMIC_VRSET = 0; PM_set_VRSET(); } // NAND保護の関係で、電池電圧検出のテーブルを切り替える if( rsv_set_batt_th ){ rsv_set_batt_th = 0; set_batt_th(); } // LED点灯試験のため if( rsv_set_powLED ){ rsv_set_powLED = 0; set_powLED_mode(); } } /****************************************************************************** 起動直後の1秒はブートモード ・vol- が押されたらミュート ******************************************************************************/ void wait_for_system_boot(){ if( !n_sys_reset ){ // リセット解除まで、【何度も】実行 // if( ( n_key_func == 1 ) && ( n_key_minus == 0 ) ){ vol_mute_start = 1; } }else{ // リセット解除後、【一回だけ】実行 // iic2m_bus_reset(); reg_init(); // 仮想レジスタの初期値のセット。(特に初期値セットしていないメモリはスタートアップルーチンで全クリアされる) flash_init(); restore_params(); // バックライト輝度、ADC補正値読んでくる if( vol_mute_start == 1 ){// mute? vregs[REG_INT_ADRS_VOL] = 0; dcp_vol_set(); // DCPへの書き込み、20msかかる。次のアクセス注意 }else{ dcp_vol_read(); // ボリューム読んでくる } iic2m_bus_reset(); pmic_init(); // 電池情報取得など。リセット解除から3msは経ってるはず... set_batt_th(); IIC0_SlaveReceiveStart(); system_inited = 1; } } /****************************************************************************** キーの判定。一回呼ばれると1上がる。T = 16ms で呼べば、約4sでカンストとなる。 マクロ無理やりすぎだ ******************************************************************************/ #define btn_check( btn, cntr ) { \ if( btn == 0 ){ \ if( cntr != 0xFF ){ \ cntr++; \ } \ }else{ \ cntr = 0; \ } \ } /****************************************************************************** ボリューム/バックライト輝度変更 チェック ******************************************************************************/ enum vol_or_bl { VOL, BL }; void tsk_sw_vol(){ static u8 vol_mns_cntr, vol_pls_cntr; static u8 BL_mns_cntr, BL_pls_cntr; if( n_key_func != 0 ){ // VOL操作 if( PM_SLP == 0 ){ btn_check( n_key_plus, vol_pls_cntr ); // 起きていないと vol+ は見ない }else{ vol_pls_cntr = 0; } BL_pls_cntr = 0; BL_mns_cntr = 0; btn_check( n_key_minus, vol_mns_cntr ); if( n_key_plus == 0 && n_key_minus != 0 ){ // キーチェック if( vol_pls_cntr == 1 ){ tsk_interval_sw_vol = 2; }else if( vol_pls_cntr == 5 ){ vol_inc(); }else if( vol_pls_cntr >= 40 ){ vol_inc(); tsk_interval_sw_vol = 32; } }else if( n_key_plus != 0 && n_key_minus == 0 ){ // キーチェック if( vol_mns_cntr == 1 ){ tsk_interval_sw_vol = 2; }else if( vol_mns_cntr == 5 ){ vol_dec(); }else if( vol_mns_cntr >= 40 ){ vol_dec(); tsk_interval_sw_vol = 32; } }else{ tsk_interval_sw_vol = 2; } }else{ // func押されてるとき:バックライト輝度操作 if( PM_SLP == 1 ){ return; } vol_pls_cntr = 0; vol_mns_cntr = 0; btn_check( n_key_plus, BL_pls_cntr ); btn_check( n_key_minus, BL_mns_cntr ); if( n_key_plus == 0 && n_key_minus != 0 ){ if( BL_pls_cntr == 1 ){ tsk_interval_sw_vol = 2; }else if( BL_pls_cntr == 5 ){ BL_inc(); }else if( BL_pls_cntr >= 40 ){ BL_inc(); tsk_interval_sw_vol = 32; } }else if( n_key_plus != 0 && n_key_minus == 0 ){ if( BL_mns_cntr == 1 ){ tsk_interval_sw_vol = 2; }else if( BL_mns_cntr == 5 ){ BL_dec(); }else if( BL_mns_cntr >= 40 ){ BL_dec(); tsk_interval_sw_vol = 32; } }else{ tsk_interval_sw_vol = 2; } } } /****************************************************************************** 1)電源スイッチのカウント、    TWLと、NDSで挙動が違いますよ    チャタリング除去は外でやってくれてます(20ms) 2)I2Cでコマンドかかれたときの動作 ! 方針変えました。    ・NTRのとき、offはPMICに任せます。    ・押したままスリープから復帰したら離すまで無視はします。が、実機ではおこらない ******************************************************************************/ void tsk_sw_pow(){ static u8 rst_cntr; /* if( PM_SLP == 1 ){ // スリープ時は逃げる pwsw_state = 3; // 押したままスリープから復帰なら、離すまで無視フラグ return; } */ if( n_key_pwsw == 0 ){ /// 押されてる /// if( rst_cntr != 255 ){ rst_cntr++; } if( ( pwsw_state == 0 ) && ( rst_cntr >= vregs[ REG_INT_ADRS_TIME_PWSW_DELAY ] ) ){ // 無視時間経過? pwsw_state = 1; if( is_TWL ){ // DI(); vregs[REG_INT_ADRS_IRQ] |= 0x08; n_irq_ast; n_irq_ngt; // EI(); }else{ // 何もしない } return; } if( ( pwsw_state == 1 ) && ( rst_cntr >= vregs[ REG_INT_ADRS_TIME_PWSW_THRESHOLD ] ) ){ // 電源オフ確定 pwsw_state = 2; // /IRQ をかけまくらないように if( is_TWL ){ // DI(); vregs[REG_INT_ADRS_IRQ] |= 0x02; n_irq_ast; n_irq_ngt; // EI(); }else{ // 何もしない } return; } return; // 以降スイッチ無視 }else{ /// 離されてる /// if( pwsw_state == 1 ){ // リセット確定 if( is_TWL ){ // DI(); vregs[REG_INT_ADRS_IRQ] |= 0x01; n_irq_ast; n_irq_ngt; // EI(); }else{ vregs[REG_INT_ADRS_COMMAND] |= 0x01; } } rst_cntr = 0; pwsw_state = 0; } } /****************************************************************************** I2Cでコマンドかかれたときの解釈と、後始末など ******************************************************************************/ void tsk_command_exec(){ static u8 count; // レジスタチェック // if( ( vregs[ REG_INT_ADRS_COMMAND ] & 0x02 ) != 0 ){ // 電源オフ // 将来的には電源オフコマンドを送る...かな }else if( ( vregs[ REG_INT_ADRS_COMMAND ] & 0x01 ) != 0 ){ // リセット処理 n_sys_reset_ast; } // リセットボタン処理 // if( n_sys_reset == 0 ){ if( count < 2 ){ count++; }else{ vregs[ REG_INT_ADRS_IRQ ] = 0; vregs[ REG_INT_ADRS_COMMAND ] = 0; vregs[ REG_INT_ADRS_CAM ] = 0; set_camled_stop(); vregs[ REG_INT_ADRS_MODE ] = 0; // ↑ volSteps32 = 0 // is_TWL = 0 // with_NAND = 0 vregs[ REG_INT_ADRS_POWER_SAVE ] = 0x07; set_batt_th(); rsv_set_PMIC_VRSET = 1; if( vregs[ REG_INT_ADRS_POWER_LED ] != 0 ){ vregs[ REG_INT_ADRS_POWER_LED ] = 0; set_powLED_mode(); } wifi_tx = 0; n_irq_ngt; n_sys_reset_ngt; EI(); pwsw_state = 3; } }else{ count = 0; } } /****************************************************************************** バックライト輝度保存 sleep中 or PM_OFF 時、NTRモードで電池が無くなったら即時記録。 ******************************************************************************/ void save_BL_param(){ u8 status; if( eeprom_bl_dirty == 1 ){ if( flash_write( DAT_BL_BRIGHT, &vregs[REG_INT_ADRS_BL] ) == 0 ){ eeprom_bl_dirty = 0; } } } void SystemInit( void ){ CG_ReadResetSource(); /*Process of reset*/ Clock_Init(); /*initialize the clock generator*/ PORT_Init(); /*Initialize the I/O ports*/ IIC0_Init(); /*Initialize the IIC0*/ ADC_Init(); TM51_Init(); /*Initialize TM51 function*/ TMH0_Init(); /*Initialize TMH0 function*/ TMH1_Init(); /*Initialize TMH1 function*/ TM50_Init(); /*Initialize TM50 function*/ } void hdwinit( void ){ DI(); IMS = MEMORY_IMS_SET; SystemInit(); EI(); } void reg_init(){ #ifdef after_x6 // Ver.3(TWL,X6以降改造(RxPE監視), Rev.0(自己書き換え対応) // 1(Func + +/- がおかしい件) vregs[ REG_INT_ADRS_VER_INFO ] = 0x33; #else // Ver.2(TWL), Rev.1(K,TS-X4以降) // Ver.2(TWL), Rev.2(自己書き換え対応) vregs[ REG_INT_ADRS_VER_INFO ] = 0x25; #endif vregs[ REG_INT_ADRS_POWER_SAVE ] = 0x07; vregs[ REG_INT_ADRS_TIME_PWSW_DELAY ] = ( 80 ) / 5; vregs[ REG_INT_ADRS_TIME_PWSW_THRESHOLD ] = ( 500 ) / 5; #ifdef wifi_led_blink_default_on // ランチャー対応待ち、WiFiLEDブリンクデフォルトON vregs[ REG_INT_ADRS_WIFI ] = 0x02; #endif }