mirror of
https://github.com/rvtr/twl_mcu.git
synced 2025-06-18 06:35:40 -04:00
529 lines
14 KiB
C
529 lines
14 KiB
C
/*****************************************************************************
|
||
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
|
||
|
||
}
|