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

529 lines
14 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.

/*****************************************************************************
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();
}
// 保存。 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;
}
}
/******************************************************************************
キーの判定。一回呼ばれると上がる。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
}