/* ======================================================== 対PMIC 藤田@開技 nintendo '08 Dec ======================================================== */ #ifndef _WIN32 #pragma nop #endif #include "incs.h" #include "adc.h" #include "led.h" #include "pm.h" #include "renge\renge.h" #include "batt_params.h" #include #include "fsl_user.h" // ======================================================== u8 raw_adc_temperature; BT_VENDER battery_manufacturer = BT_VENDER_NOT_CHECKED; static u8 ntr_pm_reg_shadow; // NTR PMIC レジスタミラー bit bt_authorized; // バッテリパラメータ送信済。充電開始許可 u8 chg_led_override; // アダプタ差したとき、充電するしないに関わらずしばらく点灯させる static u16 bt_volt16; static bit ntr_pm_bt_low_old; bit BT_IN_CHG_delayed_n; bit temp_zone_charge_disable; // 温度で充電停止する時にヒステリシスを付けるため u8 pmic_version; u8 mgic_version[2]; u8 pm_reg_bit_vddlcd; static bt_param_* p_bt_param; extern const bt_param_ bt_param[]; // ======================================================== static void BT_model_detect(); static void BT_mgic_quick_start(); static void BT_mgic_init(); static void bt_chk_temparature(); static void bt_get_charge_status(); static void bt_param_select(); static void bt_batt_update_twl(); static void bt_batt_update_ntr(); // ラッパー static err send_cmd_mgic_2B( u8 reg, u16 dat ); static err read_mgic_2B( u8 reg, u8* dat ); static err read_BT_SOC( u8* dest ); static err read_BT_voltage( u8* dest ); static u8 conv_ctr_bt_to_twl_bt(); // ======================================================== #define swap_endian_16( x ) (unsigned int)(( x << 8 ) | ( x >> 8 )) // ======================================================== const u8 BT_MANUF_BORDER[] = { 5, 33, 79, 123, 158, 197, 233 }; /* ======================================================== 電池の管理 以下のピンは主にここで操作・監視されます。 ・PM_BT_AUTH 現状、GPI in ・PM_CHARGE_n CCIC /CHG in ・PM_CHARGE_ERR_n /FLT in ・PM_EXTDC_n /DOK INTP4 in ・PM_CHARGE_EN_n /CEN out 以下の物は関係ありそうですが別のところで主に監視されています。 ・LED_Pow R, B, Charge tsk_LED ・BT_TEMP,_P tsk_ADC PM_EXTDCは割り込みメインにするかも ======================================================== */ #define INTERVAL_TSK_BATT 60 // ↑100だと充電エラー時にうまく点滅しないので void tsk_batt( ) { static u8 task_interval; if( task_interval -- != 0 ) { return; } else { task_interval = (u8)( INTERVAL_TSK_BATT / SYS_INTERVAL_TICK ); } // アダプタステータス更新 // pm_chk_adapter(); // 充電 // bt_chk_temparature(); // 温度チェック if( !temp_zone_charge_disable && bt_authorized && !PM_EXTDC_n ) { BT_CHG_ENABLE(); // 温度範囲OKで充電再開 } else { BT_CHG_DISABLE(); // 温度危険! 充電停止 } bt_get_charge_status(); // CCIC制御 if( ! BT_IN_CHG_delayed_n ) // LEDに反映 { LED_CHARGE = 1; } else { LED_CHARGE = 0; } // アダプタつないだ瞬間、満充電でも数秒わざと点灯させる。給電してることをわからせるため。 if( chg_led_override != 0 ){ // ↑から見ればわかるが、瞬間(数クロック)消える事がある。気がつく人いるかな…? chg_led_override --; LED_CHARGE = 1; } // レジスタの充電中ビットはLEDに同期する set_bit( LED_CHARGE, vreg_ctr[VREG_C_STATUS], REG_BIT_BATT_CHARGE ); // set_bitのみ。 // 割り込み // tsk_miscが引き受ける // 電池残量 // BT_get_left(); } #define RAW_TEMP_LH 75 // 50 [degC] #define RAW_TEMP_LL 61 // 55 #define RAW_TEMP_HL 184 // 1 #define RAW_TEMP_HH 189 // -1 #define AVG_COUNT 40 /* ******************************************************* 温度チェック 温度付きヒステリシス ******************************************************* */ void bt_chk_temparature() { static u8 heikinka_h,heikinka_l; if(( RAW_TEMP_LH <= raw_adc_temperature ) && ( raw_adc_temperature <= RAW_TEMP_HL )) { if( heikinka_h < AVG_COUNT ) { heikinka_h++; } else { temp_zone_charge_disable = false; // 充電許可 } } else if(( raw_adc_temperature <= RAW_TEMP_LL ) || ( RAW_TEMP_HH <= raw_adc_temperature )) { if( heikinka_l < AVG_COUNT ) { heikinka_l++; } else { temp_zone_charge_disable = true; // 充電禁止 } } else { // temp_zone_charge_disable そのまま heikinka_h = 0; heikinka_l = 0; } } void bt_get_charge_status() { // CCICの不具合回避のため、/CHGのネゲートをちょっと丁寧に遅延させる static u8 anti_chatter; if( !BT_IN_CHG_n ) { // さらにチャタリング除去 if( anti_chatter < 2 ) // 電池無しでアダプタさして、電極をさわさわ { // すると充電LEDががさがさするので anti_chatter++; } else { BT_IN_CHG_delayed_n = 0; // 充電中 } } else { // "丁寧に遅延" todo:もっといい方法? if( !BT_CHG_Ena_n && vreg_ctr[ VREG_C_BT_REMAIN ] < 60 ) { BT_IN_CHG_delayed_n = 0; // 充電中と扱う。充電が終わっているはずがない } else { BT_IN_CHG_delayed_n = 1; anti_chatter = 0; } } } /******************************************************** アダプタの有無チェック 電源off中のアダプタ抜き差しで外から呼ばれるため分離 ***********************************************************/ void pm_chk_adapter() { static bit pm_extdc_old; if( pm_extdc_old != PM_EXTDC_n ) // HAL を通すため、 PM_EXTDC_n の volatile にする心配なし { pm_extdc_old = PM_EXTDC_n; if( !PM_EXTDC_n ) { // 刺さった set_bit( 1, vreg_ctr[VREG_C_STATUS], REG_BIT_POW_SUPPLY ); set_irq( VREG_C_IRQ1, REG_BIT_BT_DC_CONNECT ); chg_led_override = (u8)( 3000 / INTERVAL_TSK_BATT ); // 誤差蓄積で実測4.5secぐらいだが、もういじらない } else { u8 temp_v[2]; // 抜けた set_bit( 0, vreg_ctr[VREG_C_STATUS], REG_BIT_POW_SUPPLY ); set_irq( VREG_C_IRQ1, REG_BIT_BT_DC_DISC ); chg_led_override = 0; // 電池残量が1%台で、アダプタ有りの時には本体が起動し、ゲームが動くが // 1%台に回復する前にアダプタが抜けたとき、割り込みを入れないと期待通りの // 動作でない。特別対応のためここで if( read_mgic_2B( BT_GAUGE_REG_VCELL, temp_v ) == ERR_SUCCESS ) { bt_volt16 = ( temp_v[0] * 256 + temp_v[1] ); } if(( bt_volt16 < V_TH_ZERO ) || ( vreg_ctr[ VREG_C_BT_REMAIN ] == 0 )) { set_irq( VREG_C_IRQ1, REG_BIT_BT_REMAIN ); } } } } /******************************************************** 電池関係の初期化    ゲージ  | 有り     | 無し   ーーーーーーーーーーーーーーーーーーーーーーー    電池 有り| 実機     | ?   ーーーーーーーーーーーーーーーーーーーーーーー       無し| 白箱     | TS         | 実機電池無し |   ーーーーーーーーーーーーーーーーーーーーーーー   ゲージ有り、電池無し の白箱/実機判別は、  電池温度で判定する 返値: 電池無し 0xFF 電池変わってない 0 電池変わった 1 ***********************************************************/ bit bt_force_update; void BT_chk() { BT_VENDER battery_manufacturer_old; battery_manufacturer_old = battery_manufacturer; BT_model_detect(); bt_param_select(); // バッテリ残量補正パラメータなどセット 非実機でも、とりあえずの値(パナ)指定にしておく。 // 無駄にrcomp計算させるが、未初期化ポインタを参照するのいやだし、非実機なら計算しないとか面倒 if( system_status.model != MODEL_JIKKI ) { bt_authorized = false; return; // おしまい } if(( battery_manufacturer_old != battery_manufacturer ) || bt_force_update ) { bt_force_update = false; iic_mcu_start( ); // 中で初期化フラグをもってるので呼びまくって良い こんなところに…orz if( (( battery_manufacturer_old == BT_VENDER_OPEN ) || ( battery_manufacturer_old == BT_VENDER_NOT_CHECKED )) && !system_status.reboot ) { BT_mgic_quick_start(); } BT_mgic_init(); // 機種判定も行います } bt_authorized = true; renge_task_immed_add( tski_BT_temp_update ); // 電池温度監視 } void BT_model_detect() { u8 temp; BT_DET_P = 1; BT_TEMP_P = 1; wait_ms( 5 ); // 電圧が上がるのに時間が掛かる raw_adc_temperature = get_adc( ADC_SEL_BATT_TEMP ); temp = get_adc( ADC_SEL_BATT_DET ); BT_DET_P = 0; system_status.captureBox = 0; // プラットフォーム判定 // if( raw_adc_temperature > 0xF0 ) { // TS // system_status.model = MODEL_TS_BOARD; } else if( raw_adc_temperature < 4 ) { // 白箱 // system_status.model = MODEL_SHIROBAKO; // もしかして:キャプチャボード // if(( iic_mcu_read_a_byte( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_VERSION ) == 0x01 ) && ( iic_mcu_result == ERR_OK )) { system_status.captureBox = 1; } } else { // 実機、残量IC NACK( バッテリ無しまたは残量IC故障 ) system_status.model = MODEL_JIKKI; // バッテリ無しの時は↓で上書きする } // TSのhomeボタン、実機は未接続なので要端子処理 /// gndにしとけばよかった… if( system_status.model == MODEL_TS_BOARD ) { PM_SW_HOME_n_TSBOARD = 1; } else { PM_SW_HOME_n_TSBOARD = 0; SW_HOME_n_TSBOARD_RAW = 0; /// 実機open どっちでもいいんだけど } // 電池メーカーの識別 // { u8 i; battery_manufacturer = BT_VENDER_OPEN; // デフォルト値 for(i=0; i<=7; i++) { if( temp <= BT_MANUF_BORDER[ i ] ) { battery_manufacturer = (BT_VENDER)i; break; /* BT_VENDER_MAXELL; // = 0 BT_VENDER_1; BT_VENDER_2; BT_VENDER_3; BT_VENDER_4; BT_VENDER_PANA; BT_VENDER_6; BT_VENDER_OPEN; */ } } } if( ( battery_manufacturer == BT_VENDER_OPEN ) && ( system_status.model == MODEL_JIKKI ) ) { system_status.model = MODEL_JIKKI_NOBATT; } } static void BT_mgic_quick_start() { wait_ms( 10 ); // MGICの起動に掛かる // 0. バッテリ残量IC クイックスタート send_cmd_mgic_2B( BT_GAUGE_REG_MODE, swap_endian_16( 0x4000 ) ); wait_ms( 150 ); } #define MGIC_CMD_UNLOCK_KEY 0x4A57 #define MGIC_CMD_RESET 0x5400 static void BT_mgic_init() { u8 origParam[4]; /* // -1. リセットをかけてみる かけちゃだめ! i2c_send_buff_2B._u16 = swap_endian_16( MGIC_CMD_RESET ); send_cmd_mgic_2B( BT_GAUGE_REG_COMMAND ); // こいつはNACKを返す */ if( system_status.model != MODEL_JIKKI ) { return; // おしまい } // 1. ロック解除 if( send_cmd_mgic_2B( BT_GAUGE_REG_LOCK, swap_endian_16( MGIC_CMD_UNLOCK_KEY ) ) != ERR_SUCCESS ) { // 残量IC NACK vreg_ctr[ VREG_C_STATUS_1 ] |= REG_BIT_MGIC_ERR; return; // おしまい } vreg_ctr[ VREG_C_STATUS_1 ] &= ~REG_BIT_MGIC_ERR; // wait_ms( 5 + 1 ); 前にウェイト入れてるので不要 // 2. 初期パラメータを一時保存 iic_mcu_read( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_RCOMP, 4, origParam ); // 3. 一時的にOCVを変更 send_cmd_mgic_2B( BT_GAUGE_REG_OCV, swap_endian_16( p_bt_param->ocv )); // マジックナンバー的なもの。メーカー指定 // 4. 一時的にRCOMPを変更 send_cmd_mgic_2B( BT_GAUGE_REG_RCOMP, swap_endian_16( 0xFF00 ) ); // 5.メーカー別パラメータのロード { u8 loop; // 16バイトごとに区切れとのこと (ノイズ対策とか言うんだけど、意味あるんか?) for( loop = 0; loop < 4; loop ++ ) { iic_mcu_set_wo_dma( ); iic_mcu_write( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_BT_PARAM + loop*16, 16, p_bt_param->mg_param + loop*16 ); } } // 6. 150ms以上待つ wait_ms( 150 + 15 ); // 7. OCVに「とある値」を書く send_cmd_mgic_2B( BT_GAUGE_REG_OCV, swap_endian_16( p_bt_param->ocv ) ); // マジックナンバー的なもの。メーカー指定 // 8. 150〜600ms待つ。600msは厳守 wait_ms( 150 + 15 ); // 9. SOCを読む。ベリファイのため。 { u8 temp; temp = iic_mcu_read_a_byte( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_SOC ); if(( p_bt_param->verify.low <= temp ) && ( temp <= p_bt_param->verify.hi )) { // カスタムモデル書き込みOK! }else{ // 失敗だったらリトライするのか? // dbg_nop(); } } // 10.元のRCOMPとOCVを書き戻す iic_mcu_write( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_RCOMP, 4, origParam ); // 11. ロック send_cmd_mgic_2B( BT_GAUGE_REG_LOCK, swap_endian_16( 0x0000 ) ); // lock key } extern u16 _dbg_rcomp; /* ======================================================== raw_adc_temperatureに入っている値を℃に変換するとともに、 ・レジスタにセット ・残量ICにセット ======================================================== */ task_status_immed tski_BT_temp_update( ) { static u8 rawdat_old; static s8 temperature; s16 newrcomp; static u8 heikinka; /* サーミスタ - 10kΩ分圧点の時、 常用温度では分圧比のカーブがほぼリニアで、 村田 T[℃] = 81.48 - 111.97 x ratio TDK T = 81.406 - 111.81 x ratio */ if( rawdat_old != raw_adc_temperature ) { if( heikinka < 40 ) { heikinka ++; } else { heikinka = 0; rawdat_old = raw_adc_temperature; // temperature = 81.45 - 111.9 * raw_adc_temperature/256.0; // それぞれ256倍してある temperature = (u8)(( 20851 - 112 * raw_adc_temperature + (256/2) ) /256); vreg_ctr[VREG_C_BT_TEMP] = (u8)temperature; newrcomp = 0; if( temperature > 20 ) { newrcomp = ( ( temperature - 20 ) * p_bt_param->rcomp.up )/256; } else { newrcomp = ( ( temperature - 20 ) * p_bt_param->rcomp.down )/256; } newrcomp = p_bt_param->rcomp.rcomp + newrcomp; if( newrcomp > 255 ) { newrcomp = 255; } if( newrcomp < 0 ) { newrcomp = 0; } _dbg_rcomp = newrcomp; if( send_cmd_mgic_2B( BT_GAUGE_REG_RCOMP, newrcomp ) == ERR_SUCCESS ) // swap不要 { rawdat_old = raw_adc_temperature; } else { vreg_ctr[ VREG_C_STATUS_1 ] |= REG_BIT_MGIC_ERR; } } } return ( ERR_FINISED ); } /********************************************************** 電池残量ICから残量を取得し、レジスタに書き込む。  電池残量ICが無い・故障などの時はとりあえず残量99%とする。         ↑は status_1で確認可能。電源投入時にチェックしています。  BT_chk()が実行されている必要があります。 **********************************************************/ void BT_get_left(){ u8 temp[2]; u8 reg_volatile_temp_bt_remain,reg_volatile_temp_bt_remain_fine; // I2Cの非同期読み込みでのちらつき防止 キャップ処理の所為 u8 fuel_cap_by_voltage; // 電圧でキャップに使う // 電池残量 if( system_status.model == MODEL_TS_BOARD || system_status.model == MODEL_SHIROBAKO ) { // TS & 白箱 // if( read_BT_SOC( temp ) == ERR_SUCCESS ) { reg_volatile_temp_bt_remain = temp[0]; reg_volatile_temp_bt_remain_fine = temp[1]; } else { // エミュレーション機能がおかしい //  それで電源断は不便すぎるだろう reg_volatile_temp_bt_remain = 99; reg_volatile_temp_bt_remain_fine = 0; } } else { // 実機 // // 残量リード if( read_BT_SOC( temp ) != ERR_SUCCESS ) { // 残量ICがNACK …バッテリはずれた vreg_ctr[ VREG_C_STATUS_1 ] |= REG_BIT_MGIC_ERR; bt_authorized = false; reg_volatile_temp_bt_remain = 0; force_off = true; } else { u16 temp_u16; // バッテリパラメータの関係でビットシフトが必要 temp_u16 = temp[0] * 256 + temp[1]; temp_u16 /= p_bt_param->v_scale; reg_volatile_temp_bt_remain = (u8)(( temp_u16 >> 8 ) & 0xFF ); if( reg_volatile_temp_bt_remain == 0 ) { // 0%台の時は1.00%に上げ底 // 充電開始後もしばらくは電池残量が減るので // 0%に到達してしまうことがあるのだ reg_volatile_temp_bt_remain = 1; reg_volatile_temp_bt_remain_fine = 0; } else { reg_volatile_temp_bt_remain_fine = (u8)(temp_u16 & 0xFF); } } } // 電池電圧 { if( read_BT_voltage( temp ) != ERR_SUCCESS ) // 2byte read { temp[0] = (u8)( V_BT_4000MV / 256 ); // 電池電圧読めなかったら4000mVだったことにしておく。 temp[1] = 0; } vreg_ctr[ VREG_C_BT_VOLTAGE ] = temp[0]; bt_volt16 = ( temp[0] * 256 + temp[1] ); } // 電圧でキャップ...の準備 { static u16 hysteresis; if( bt_volt16 > V_TH_30 ) { fuel_cap_by_voltage = 100; hysteresis = 0; } else if( bt_volt16 - hysteresis > V_TH_LO ) { fuel_cap_by_voltage = 30; hysteresis = 0; } else if( bt_volt16 > V_TH_EMPTY ) { fuel_cap_by_voltage = BATT_TH_LO; // ここから赤 hysteresis = 500; } else if( bt_volt16 > V_TH_ZERO ) { fuel_cap_by_voltage = BATT_TH_EMPTY; hysteresis = 500; } else if( bt_volt16 > V_TH_FORCE_OFF ) { fuel_cap_by_voltage = 0; hysteresis = 500; } else { force_off = true; hysteresis = 500; } } // 充電許可(=アダプタも刺さってる)のに充電してない // かつ、(少なくとも)素の電池残量が60%以上(CCICバグ回避) // = 充電完了。電池がへたってくるとMGICが100%を返さない if( !BT_CHG_Ena_n && BT_IN_CHG_delayed_n ){ reg_volatile_temp_bt_remain = 100; reg_volatile_temp_bt_remain_fine = 0; } else { // 電圧でのキャップを掛けるか? if( fuel_cap_by_voltage < reg_volatile_temp_bt_remain ) { reg_volatile_temp_bt_remain = fuel_cap_by_voltage; reg_volatile_temp_bt_remain_fine = 0; } } /* 十分に問題ない電圧が供給されてるらしいのでケアせずでよし if( system_status.taikendai_nbd && system_status.model != MODEL_TS_BOARD ) // 電池端子に電源がつながってて値が不正なため上書き。 { reg_volatile_temp_bt_remain = 100; } */ vreg_ctr[ VREG_C_BT_REMAIN ] = reg_volatile_temp_bt_remain; vreg_ctr[ VREG_C_BT_REMAIN_FINE ] = reg_volatile_temp_bt_remain_fine; // twlのレジスタ更新 (CTRに割り込み入れる前に更新しないと割り込みのタイミングがまずいかもしれない) bt_batt_update_twl(); // 残量で割り込み。急激に減ると飛ぶことがある // { static u8 bt_remain_old_ctr; if( bt_remain_old_ctr != reg_volatile_temp_bt_remain ) // CTRに通知 { if( (( vreg_ctr[ VREG_C_BT_REMAIN ] <= BATT_TH_LO ) && ( BATT_TH_LO < bt_remain_old_ctr ))|| (( vreg_ctr[ VREG_C_BT_REMAIN ] <= BATT_TH_EMPTY ) && ( BATT_TH_EMPTY < bt_remain_old_ctr ))|| (( vreg_ctr[ VREG_C_BT_REMAIN ] == 0 ) && ( bt_remain_old_ctr != 0 )) ) { set_irq( VREG_C_IRQ1, REG_BIT_BT_REMAIN ); } } bt_remain_old_ctr = vreg_ctr[ VREG_C_BT_REMAIN ]; } // PMIC-NTRに電池残量を教えてあげる bt_batt_update_ntr(); } /* ======================================================== 液晶系の電源制御  ステータスフラグはすぐに立ててしまう。  不感応時間があるし、 起動失敗であれば電源が落ちる 別のタスクで電源落ちは監視していて、ステータスもクリアする ======================================================== */ // BSR // err PM_LCD_on( ) { u8 rv; PM_VDDLCD_on( ); if( system_status.family == FAMILY_SPFL ) { SPFL_LCD_AMOL_HV_CONT = 1; } wait_ms( DELAY_PM_TSS_50B_AND_TCOM ); PM_TCOM_on( ); wait_ms( DELAY_PM_TCOM_TO_VCS ); PM_VCS_on( ); wait_ms( DELAY_PM_VCS_TO_BL ); rv = (u8)PM_chk_LDSW( ); if( rv != 0 ) // 正常パス { // 電源起動エラーなら電源も切れてしまう。ここではケアしない vreg_ctr[VREG_C_STATUS] |= REG_BIT_LCD_POW; set_irq( VREG_C_IRQ3, REG_BIT_LCD_ON ); return ( ERR_SUCCESS ); } return ( ERR_ERR ); } // BSR // void PM_LCD_off() { // BLついてたら消す。// チェックするのは割り込みの関係 if( ( read_pmic( PM_REG_ADRS_BL ) & 0x03 ) != 0 ) { u8 tot; PM_BL_set( REG_BIT_CMD_BL_U_OFF | REG_BIT_CMD_BL_L_OFF ); vreg_ctr[VREG_C_STATUS] &= bits8(1,0,0,1, 1,1,1,1); if( (( REG_BIT_BL_U_OFF | REG_BIT_BL_L_OFF ) & ~vreg_ctr[ VREG_C_IRQ_MASK3 ] ) != 0 ) { vreg_ctr[ VREG_C_IRQ3 ] |= ( ( REG_BIT_BL_U_OFF | REG_BIT_BL_L_OFF ) & ~vreg_ctr[ VREG_C_IRQ_MASK3 ] ); IRQ0_neg; tot = 0; while( !IRQ0 && ( ++tot != 0 ) ){;} IRQ0_ast; } vreg_ctr[VREG_C_COMMAND2] &= ~( REG_BIT_CMD_BL_U_OFF | REG_BIT_CMD_BL_L_OFF ); } // 液晶電源切る // SPFL_LCD_AMOL_HV_CONT = 0; // 他のファミリでもL縛りなので弊害なし // 50msとか待つし、確認しましょうかね… if( read_pmic( PM_REG_ADRS_VDD_LCD ) != 0 ) { if( system_status.family == FAMILY_SPFL ) { wait_ms( 10 ); // アモルファス15Vを切ったときのウェイト。 } PM_TCOM_off(); wait_ms( 1 ); PM_TCOM_VCS_off( ); wait_ms( DELAY_PM_LCD_OFF ); PM_VDDLCD_off( ); // 残ってたの全部止めます。 vreg_ctr[VREG_C_STATUS] &= ~REG_BIT_LCD_POW; } set_irq( VREG_C_IRQ3, REG_BIT_LCD_OFF ); // 無条件に発生。マスク無ければ。 } /* ========================================================  バックライトの個別on/off  現状から on/off/維持 のフラグなので面倒   例えば、BL on/on の状態で、on/onにしろと言われても、on/on割り込みを入れます。 ======================================================== */ err PM_BL_set( u8 dat ) { u8 blset; u8 intset = 0; // RMWを行う // Read blset = read_pmic( PM_REG_ADRS_BL ); // Modify // ue if(( dat & REG_BIT_CMD_BL_U_ON ) != 0 ) { blset |= PM_REG_BIT_BL_U; intset |= REG_BIT_BL_U_ON; } else if(( dat & REG_BIT_CMD_BL_U_OFF ) != 0 ) { blset &= ~PM_REG_BIT_BL_U; intset |= REG_BIT_BL_U_OFF; } // shita if(( dat & REG_BIT_CMD_BL_L_ON ) != 0 ) { blset |= PM_REG_BIT_BL_L; intset |= REG_BIT_BL_L_ON; } else if(( dat & REG_BIT_CMD_BL_L_OFF ) != 0 ) { blset &= ~PM_REG_BIT_BL_L; intset |= REG_BIT_BL_L_OFF; } if( blset != 0 ) // BLを付ける場合はウェイトを挟まないとPWMが来ておらず // シャットダウンすることがある { wait_ms( 16 + 10 ); } send_cmd_pmic( PM_REG_ADRS_BL, blset ); #if 0 // SoCがPWMを出すようレジスタをセットしてから遅延が有るため、ステータスを先に // 更新してしまう。 #endif // PMICのBLのビットと、MCUのSTATUSレジスタのビット位置が逆なため入れ替え vreg_ctr[VREG_C_STATUS] = (( vreg_ctr[VREG_C_STATUS] & bits8(1,0,0,1, 1,1,1,1) ) | ( (( blset << 6 ) | ( blset << 4 )) & bits8(0,1,1,0, 0,0,0,0) )); // 割り込み /// 複数ビットまとめて行うので、いつもの関数使用不可 { u8 tot; if( ( intset & ~vreg_ctr[ VREG_C_IRQ_MASK3 ] ) != 0 ) { vreg_ctr[ VREG_C_IRQ3 ] |= ( intset & ~vreg_ctr[ VREG_C_IRQ_MASK3 ] ); IRQ0_neg; tot = 0; while( !IRQ0 && ( ++tot != 0 ) ){;} IRQ0_ast; } } return( ERR_SUCCESS ); // ここでは異常チェック不要 } /* ======================================================== 液晶の対向電圧の設定を行います。 仮想レジスタの内容を送るだけ ======================================================== */ void PM_LCD_vcom_set( ) { send_cmd_pmic( PM_REG_ADRS_POW_DAC1, vreg_ctr[VREG_C_VCOM_T] ); // がっかりなことに、PMICはバースト書き込み不可 send_cmd_pmic( PM_REG_ADRS_POW_DAC2, vreg_ctr[VREG_C_VCOM_B] ); return; } /* ======================================================== ↑で、レジスタ書き込みから呼び出される時のため  I2Cの取り合いの関係でここから呼ぶ ======================================================== */ task_status_immed tski_vcom_set( ) { PM_LCD_vcom_set( ); return ( ERR_FINISED ); } /* ======================================================== シーケンスの通り電源を立ち上げてゆきます。 返値 0 最後まで正常に完了した。 1 ショートなどで電源があがりきらなかった 以下のピンは主にここで操作・監視されます。 ・POW_CONT1,2 TEG電源のみ ======================================================== */ err PM_sys_pow_on( ) { // 電源順次立ち上げ // PM_reset_ast( ); 不要 PM_LDSW_onまかせ RESET2_ast; FCRAM_RST_ast; GYRO_DISABLE(); PM_LDSW_on( ); wait_ms( 1 + DELAY_PM_TW_PWUP ); PM_VDD_normMode(); PM_VDD_on( ); // wait_ms( DELAY_PM_TW_PWUP ); // GYROを挟むため wait_ms( 10 ); GYRO_ENABLE(); wait_ms( DELAY_PM_TW_PWUP - 10 ); PM_VDD50A_on( ); // 液晶電源ではなく、ledとかに使うものです wait_ms( DELAY_PM_TW_PWUP ); // 無事電源が起動したかチェック。 if( !PM_chk_LDSW() ) { return ( ERR_ERR ); // reset1はほっといて良い } // 電源周りIC情報 pmic_version = read_pmic( PM_REG_ADRS_VER ); read_mgic_2B( BT_GAUGE_REG_VERSION, mgic_version ); // リセット解除など。システム起動! PM_reset_neg(); FCRAM_RST_neg; RESET2_neg; codec_reg_init(); // CODEC 不定レジスタ初期化(reset2の後でないといけないので) ntr_pm_reg_shadow = 0; //  〃 こんなところで... return ( ERR_SUCCESS ); } /* ======================================================== 電源OFFシーケンス ======================================================== */ void PM_sys_pow_off( ) { // if( RESET1_n ) if( PM_chk_LDSW() ) { // 異常時は呼ばない PM_BL_set( REG_BIT_CMD_BL_U_OFF | REG_BIT_CMD_BL_L_OFF ); PM_LCD_off(); // TCOM,VCS OFF も消してきます。 wait_ms( 20 ); PM_reset_ast(); } RESET2_ast; FCRAM_RST_ast; wait_ms( 20 ); PM_off( ); PM_LDSW_off( ); return; } /*========================================================= extDC割り込み 電源OFFから起こす(充電の温度監視のため)のみ 普段はポーリング(pm) =========================================================*/ __interrupt void intp4_extdc( ) { // chg_led_override = (u8)( 1000 / INTERVAL_TSK_BATT ); // chg_led_override = 4; } /*========================================================= フタ開け閉め割り込み 普段はポーング(misc) =========================================================*/ __interrupt void intp5_shell( ) { ; } /*========================================================= 旧PMICへのコマンド書き込み =========================================================*/ __interrupt void intp6_PM_irq( ) { EI(); if( system_status.pwr_state == ON ) { renge_task_immed_add( tski_ntr_pmic_comm ); } } /* ======================================================== PMICからの割り込みを受けて、NTR PMIC互換レジスタからリード ======================================================== */ task_status_immed tski_ntr_pmic_comm( ) { u8 reg1_old; u8 irq_work = 0; reg1_old = ntr_pm_reg_shadow; ntr_pm_reg_shadow = iic_mcu_read_a_byte( IIC_SLA_CODEC, CODEC_REG_PM ); if( iic_mcu_result != ERR_SUCCESS ) { return ( ERR_FINISED ); } // DI( ); // バックライト 上 //////////////////////////////////// if( ( ( reg1_old ^ ntr_pm_reg_shadow ) & REG_BIT_TWL_REQ_BL_U ) != 0 ) { if( ( ntr_pm_reg_shadow & REG_BIT_TWL_REQ_BL_U ) == 0 ) // 消えた { irq_work = REG_BIT_TWL_BL_U_OFF; } else { irq_work = REG_BIT_TWL_BL_U_ON; } } // バックライト 下 if( ( ( reg1_old ^ ntr_pm_reg_shadow ) & REG_BIT_TWL_REQ_BL_L ) != 0 ) { if( ( ntr_pm_reg_shadow & REG_BIT_TWL_REQ_BL_L ) == 0 ) // 消えた { irq_work |= REG_BIT_TWL_BL_L_OFF; } else { irq_work |= REG_BIT_TWL_BL_L_ON; } } // EI(); vreg_ctr[ VREG_C_STATUS_1 ] = ( vreg_ctr[ VREG_C_STATUS_1 ] & ~0x0C ) | ( ntr_pm_reg_shadow & 0x0C ); // TWLバックライト情報のミラー irq_work &= ~vreg_ctr[ VREG_C_IRQ_MASK2 ]; // set_irq 相当品 if( irq_work != 0 ) { u8 tot; vreg_ctr[ VREG_C_IRQ2 ] |= irq_work; IRQ0_neg; // 一瞬上げてパルスを送り直す tot = 0; while( !IRQ0 && ( ++tot != 0 ) ){;} // O.Dなのでちゃんとあがるのを待つ & IRQ_mcu がLに縛られてると困る(基板不良) IRQ0_ast; } #if 0 // バックライト設定 // 勝手に消しておく /// 今のところさらに細かくは分けないけど… if( ( ntr_pm_reg_shadow & ( REG_BIT_TWL_REQ_BL_U | REG_BIT_TWL_REQ_BL_U ) ) == 0 ) { vreg_ctr[ VREG_C_COMMAND2 ] = ( REG_BIT_CMD_BL_U_OFF | REG_BIT_CMD_BL_U_OFF ); renge_task_immed_add( tski_PM_BL_set ); } #endif // offリクエスト ////////////////////////////////////// if( ( ntr_pm_reg_shadow & REG_BIT_TWL_REQ_OFF_REQ ) != 0 ) { set_irq( VREG_C_IRQ2, REG_BIT_TWL_OFF_REQ ); } // リセットリクエスト ///////////////////////////////// if( ( ntr_pm_reg_shadow & REG_BIT_TWL_REQ_RST_REQ ) != 0 ) { #if 0 // CODECバグ回避 // リセット単品でなかったら無視 if( ( reg1_old ^ ntr_pm_reg_shadow ) == REG_BIT_TWL_REQ_RST_REQ ) #endif { set_irq( VREG_C_IRQ2, REG_BIT_TWL_RESET_REQ ); } } // バックライトをマスクして書き戻す EI( ); if( ( ntr_pm_reg_shadow & ( REG_BIT_TWL_REQ_OFF_REQ | REG_BIT_TWL_REQ_RST_REQ )) != 0 ) { ntr_pm_reg_shadow &= ~( REG_BIT_TWL_REQ_OFF_REQ | REG_BIT_TWL_REQ_RST_REQ ); iic_mcu_write_a_byte_codec( CODEC_REG_PM, ntr_pm_reg_shadow ); } return ( ERR_FINISED ); } /********************************************************** command2 液晶系   ラッパー的な物。ERR_SUCCESSしか返さないが… **********************************************************/ task_status_immed tski_PM_LCD_on() { PM_LCD_on(); return( ERR_FINISED ); } task_status_immed tski_PM_LCD_off() { PM_LCD_off(); return( ERR_FINISED ); } task_status_immed tski_PM_BL_set() { u8 cmd_BL; // ↓volatileとか付けなくても大丈夫みたい do { cmd_BL = vreg_ctr[VREG_C_COMMAND2]; PM_BL_set( cmd_BL ); // マスク済み } while( cmd_BL != vreg_ctr[VREG_C_COMMAND2] ); // <- PM_BL_setが更新する vreg_ctr[VREG_C_COMMAND2] = 0; return( ERR_FINISED ); } /**********************************************************  reset2 で CODEC にリセットがかかり、レジスタが不定になるため **********************************************************/ void codec_reg_init() { wait_ms( 100 ); ntr_pm_bt_low_old = conv_ctr_bt_to_twl_bt(); iic_mcu_write_a_byte_codec( CODEC_REG_BT, (u8)ntr_pm_bt_low_old ); // SoC から書けず vol_reset(); // renge_task_immed_add( tski_vol_update ); ポーリングするので。 vol_polling = 3; } /* ============================================================ ヘルパーというかラッパーというか? ROM節約のため ============================================================ */ err send_cmd_mgic_2B( u8 reg, u16 dat ) // 送信バッファ { u16 temp = dat; return iic_mcu_write( IIC_SLA_BT_GAUGE, reg, 2, &temp ); // DMA転送するので送信データバッファのポインタがどうせ必要 } err read_mgic_2B( u8 reg, u8* dat ) // 送信バッファは固定 { return iic_mcu_read( IIC_SLA_BT_GAUGE, reg, 2, dat ); } err send_cmd_pmic( u8 reg, u8 dat ) { return iic_mcu_write_a_byte( IIC_SLA_PMIC, reg, dat ); } u8 read_pmic( u8 reg ) { return iic_mcu_read_a_byte( IIC_SLA_PMIC, reg ); } /* ============================================================ 電池メーカーとモデルから、使う電池パラメータの決定 ============================================================ */ void bt_param_select() { BT_TYPE bt_type_temp; // 対応が増えてきたら分岐コード書き直すつもりで if( battery_manufacturer <= BT_VENDER_3 ) { bt_type_temp = BT_PARAM_CTR_MAXELL; } else { bt_type_temp = BT_PARAM_CTR_PANA; } if( system_status.family == FAMILY_SPFL ) { bt_type_temp += BT_PARAM_SPFL_MAXELL; // オフセット 残念な実装で…。 } else if( system_status.family == FAMILY_SHRIMP ) { bt_type_temp += BT_PARAM_SHRIMP_MAXELL; } p_bt_param = &bt_param[ bt_type_temp ]; } /* ============================================================ TWLに電池残量を教えてあげる ============================================================ */ static void bt_batt_update_twl() { if (vreg_ctr[VREG_C_BT_REMAIN] > 80) { vreg_twl[REG_TWL_INT_ADRS_POWER_INFO] = 0x0F; } else if (vreg_ctr[VREG_C_BT_REMAIN] > 50) { vreg_twl[REG_TWL_INT_ADRS_POWER_INFO] = 0x0B; } else if (vreg_ctr[VREG_C_BT_REMAIN] > BATT_TH_LO) { vreg_twl[REG_TWL_INT_ADRS_POWER_INFO] = 0x07; } else if (( vreg_ctr[ VREG_C_BT_REMAIN ] > BATT_TH_EMPTY )|| !BT_CHG_Ena_n ) { // アダプタの有無で底上げ vreg_twl[REG_TWL_INT_ADRS_POWER_INFO] = 0x03; } else if (vreg_ctr[VREG_C_BT_REMAIN] > 0) { vreg_twl[REG_TWL_INT_ADRS_POWER_INFO] = 0x01; } else { vreg_twl[REG_TWL_INT_ADRS_POWER_INFO] = 0x00; } } /* ============================================================ NTRに電池残量を教えてあげる ============================================================ */ static void bt_batt_update_ntr() { static bit initialized; static bit flag; // あれ?staticでないとコンパイラに怒られる if( system_status.pwr_state == OFF_TRIG ) { initialized = false; } else { flag = conv_ctr_bt_to_twl_bt(); if(( ntr_pm_bt_low_old != flag ) || !initialized ) { initialized = true; ntr_pm_bt_low_old = flag; iic_mcu_write_a_byte_codec( CODEC_REG_BT, (u8)flag ); } } } /* ======================================================== ========================================================= */ static err read_BT_SOC( u8* dest ) { if( vreg_ctr[ VREG_C_HAL_OVW_BT_FUEL ] != 0xFF ) { *dest = vreg_ctr[ VREG_C_HAL_OVW_BT_FUEL ]; *(dest+1) = 0x00; return ERR_SUCCESS; } else { return( read_mgic_2B( BT_GAUGE_REG_SOC, dest ) ); } } /* ======================================================== ========================================================= */ static err read_BT_voltage( u8* dest ) { if( vreg_ctr[ VREG_C_HAL_OVW_BT_VOLTAGE ] != 0xFF ) { *dest = vreg_ctr[ VREG_C_HAL_OVW_BT_VOLTAGE ]; // *(dest+1) = 0x00; // 使わないよ けど2バイトリード関数しか用意してないのです return ERR_SUCCESS; } else { return( read_mgic_2B( BT_GAUGE_REG_VCELL, dest ) ); } } /* ======================================================== 電池残量をtwlにフラグにして返す ========================================================= */ static u8 conv_ctr_bt_to_twl_bt() { // ntr_pm_bt_low_old = ( vreg_ctr[ VREG_C_BT_REMAIN ] <= BATT_TH_LO )? NTR_PM_BT_EMPTY: NTR_PM_BT_ENOUGH; // 1で電池切れ if( vreg_ctr[ VREG_C_BT_REMAIN ] <= BATT_TH_LO ) { return NTR_PM_BT_EMPTY; } else { return NTR_PM_BT_ENOUGH; } }