/* ======================================================== 対PMIC 藤田@開技 nintendo '08 Dec ======================================================== */ #pragma nop #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; st_bt_comp bt_comp; // バッテリパラメータ構造体 u8 reg_shadow; // NTR PMIC レジスタミラー bit bt_chg_ready; // バッテリパラメータ送信済。充電開始許可 u8 chg_led_override; // アダプタ差したとき、充電するしないに関わらずしばらく点灯させる // ======================================================== #ifdef _PMIC_TWL_ u8 blset; #endif /* ======================================================== 液晶系の電源制御  ステータスフラグはすぐに立ててしまう。  不感応時間があるし、 起動失敗であれば電源が落ちる 別のタスクで電源落ちは監視していて、ステータスもクリアする ======================================================== */ // BSR // err PM_LCD_on( ) { u8 rv; PM_VDDLCD_on( ); 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 = PM_chk_LDSW( ); if( rv != 0 ) { // 電源起動エラーなら電源も切れてしまう。ここではケアしない vreg_ctr[VREG_C_STATUS] |= REG_BIT_LCD_POW; set_irq( VREG_C_IRQ3, REG_BIT_LCD_ON ); SND_DEPOP_SND_ENABLE; return ( ERR_ERR ); } #ifdef _PMIC_TWL_ PM_TEG_LCD_dis( 0 ); blset = ( PM_REG_BIT_BL_U | PM_REG_BIT_BL_L ); #endif return ( ERR_SUCCESS ); } // BSR // void PM_LCD_off() { SND_DEPOP_SND_MUTE; // BLついてたら消す #ifdef _PMIC_TWL_ if( blset != 0 ) #else if( ( iic_mcu_read_a_byte( IIC_SLA_PMIC, PM_REG_ADRS_BL ) & 0x03 ) != 0 ) #endif { u8 tot; PM_BL_set( REG_BIT_CMD_BL_U_OFF | REG_BIT_CMD_BL_L_OFF ); vreg_ctr[VREG_C_STATUS] &= 0b10011111; 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 ); } #ifdef _PMIC_TWL_ PM_TEG_LCD_dis( 1 ); blset = 0; #endif if( iic_mcu_read_a_byte( IIC_SLA_PMIC, PM_REG_ADRS_VDD_LCD ) != 0 ) { 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 ) { #ifndef _PMIC_TWL_ u8 blset; #endif u8 intset = 0; // RMWを行う #ifndef _PMIC_TWL_ // Read blset = iic_mcu_read_a_byte( IIC_SLA_PMIC, PM_REG_ADRS_BL ) ; #endif // 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 ); // wait_ms( 84 ); ミツミの1stバグ回避 } iic_mcu_write_a_byte( IIC_SLA_PMIC, PM_REG_ADRS_BL, blset ); #if 0 // SoCがPWMを出すようレジスタをセットしてから遅延が有るため、ステータスを先に // 更新してしまう。 #endif vreg_ctr[VREG_C_STATUS] = (( vreg_ctr[VREG_C_STATUS] & 0b10011111 ) | ( (( blset << 6 ) | ( blset << 4 )) & 0b01100000 )); // PMICのBLのビットと、MCUのSTATUSレジスタのビット位置が逆なため入れ替え { 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 ); // ここでは異常チェック不要 } /* ======================================================== 液晶の対向電圧の設定を行います。 仮想レジスタの内容を送るだけ ======================================================== */ err PM_LCD_vcom_set( ) { u8 rv; rv = iic_mcu_write_a_byte( IIC_SLA_PMIC, PM_REG_ADRS_POW_DAC1, vreg_ctr[VREG_C_VCOM_T] ); // がっかりなことに、PMICはバースト書き込み不可 rv |= iic_mcu_write_a_byte( IIC_SLA_PMIC, PM_REG_ADRS_POW_DAC2, vreg_ctr[VREG_C_VCOM_B] ); return ( rv ); } /* ======================================================== ↑で、レジスタ書き込みから呼び出される時のため  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( ) { // 電源順次立ち上げ #ifdef _PMIC_CTR_ // PM_reset_ast( ); 不要 PM_LDSW_onまかせ RESET2_ast; FCRAM_RST_ast; GYRO_DISABLE(); PM_LDSW_on( ); wait_ms( 1 ); wait_ms( 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 ); // 無事電源が起動したかチェック。 # ifdef _PMIC_CTR_ if( !PM_chk_LDSW() ) { return ( ERR_ERR ); // reset1はほっといて良い } PM_reset_neg(); # else RESET1_neg; if( !RESET1_n ) { RESET1_ast; return ( ERR_ERR ); // reset1はほっといて良い } # endif FCRAM_RST_neg; RESET2_neg; wait_ms( 100 ); #else // TWL PMIC // u8 temp; // 電源投入 PM_reset_ast(); RESET2_ast; FCRAM_RST_ast; PM_TEG_PWSW = 1; wait_ms( 160 ); PM_TEG_PWSW = 0; // 残量確認 temp = 99; if( temp < 5 ) { return ( ERR_ERR ); } vreg_ctr[VREG_C_BT_REMAIN] = temp; FCRAM_RST_neg; PM_reset_neg(); RESET2_neg; wait_ms( 100 ); if( !RESET1_n ) { // 起動失敗 PM_reset_ast(); RESET2_ast; FCRAM_RST_ast; return ( ERR_ERR ); } #endif { // CODEC 不定レジスタ初期化 u8 codec_reg_init[3] = { 0,0,0 }; iic_mcu_write( IIC_SLA_CODEC, CODEC_REG_PM, 3, codec_reg_init ); reg_shadow = 0; // こんなところで... } return ( ERR_SUCCESS ); } /* ======================================================== 電源OFFシーケンス ======================================================== */ err PM_sys_pow_off( ) { #ifdef _PMIC_CTR_ // 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( 50 + 10 ); PM_reset_ast( ); } RESET2_ast; FCRAM_RST_ast; // PM_off( ); ↓まとめて落としてしまえ PM_LDSW_off( ); #else if( RESET1_n ) { PM_reset_ast(); RESET2_ast; FCRAM_RST_ast; PM_TEG_PWSW = 1; wait_ms( 250 ); wait_ms( 250 ); wait_ms( 250 ); PM_TEG_PWSW = 0; } PM_reset_ast(); RESET2_ast; FCRAM_RST_ast; #endif return ( ERR_SUCCESS ); } /*========================================================= extDC割り込み 電源OFFから起こす(充電の温度監視のため)のみ 普段はポーリング(pm) =========================================================*/ __interrupt void intp4_extdc( ) { // chg_led_override = (u8)( 1000 / INTERVAL_TSK_BATT / SYS_INTERVAL_TICK ); 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( ntr_pmic_comm ); } } #define _type1_ /* ======================================================== PMICからの割り込みを受けて、NTR PMIC互換レジスタからリード ======================================================== */ task_status_immed ntr_pmic_comm( ) { u8 reg1_old; u8 irq_work = 0; reg1_old = reg_shadow; reg_shadow = iic_mcu_read_a_byte( IIC_SLA_CODEC, CODEC_REG_PM ); if( iic_mcu_bus_status != ERR_SUCCESS ) { return ( ERR_FINISED ); } DI( ); // バックライト 上 //////////////////////////////////// if( ( ( reg1_old ^ reg_shadow ) & REG_BIT_TWL_REQ_BL_U ) != 0 ) { if( ( reg_shadow & REG_BIT_TWL_REQ_BL_U ) == 0 ) // 消えた { #ifdef _type1_ irq_work = REG_BIT_TWL_BL_U_OFF; #else set_irq( VREG_C_IRQ2, REG_BIT_TWL_BL_U_OFF ); #endif } else { #ifdef _type1_ irq_work = REG_BIT_TWL_BL_U_ON; #else set_irq( VREG_C_IRQ2, REG_BIT_TWL_BL_U_ON ); #endif } } // バックライト 下 if( ( ( reg1_old ^ reg_shadow ) & REG_BIT_TWL_REQ_BL_L ) != 0 ) { if( ( reg_shadow & REG_BIT_TWL_REQ_BL_L ) == 0 ) // 消えた { #ifdef _type1_ irq_work |= REG_BIT_TWL_BL_L_OFF; #else set_irq( VREG_C_IRQ2, REG_BIT_TWL_BL_L_OFF ); #endif } else { #ifdef _type1_ irq_work |= REG_BIT_TWL_BL_L_ON; #else set_irq( VREG_C_IRQ2, REG_BIT_TWL_BL_L_ON ); #endif } } EI(); vreg_ctr[ VREG_C_STATUS_1 ] = ( vreg_ctr[ VREG_C_STATUS_1 ] & ~0x0C ) | ( reg_shadow & 0x0C ); // TWLバックライト情報のミラー #ifdef _type1_ irq_work &= ~vreg_ctr[ VREG_C_IRQ_MASK2 ]; // set_irq 相当品 if( irq_work != 0 ) { u8 tot; DI(); vreg_ctr[ VREG_C_IRQ2 ] |= irq_work; EI(); IRQ0_neg; // 一瞬上げてパルスを送り直す tot = 0; while( !IRQ0 && ( ++tot != 0 ) ){;} // O.Dなのでちゃんとあがるのを待つ & IRQ_mcu がLに縛られてると困る(基板不良) IRQ0_ast; } #endif #if 0 // バックライト設定 // 勝手に消しておく /// 今のところさらに細かくは分けないけど… if( ( 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( ( reg_shadow & REG_BIT_TWL_REQ_OFF_REQ ) != 0 ) { set_irq( VREG_C_IRQ2, REG_BIT_TWL_OFF_REQ ); } // リセットリクエスト ///////////////////////////////// if( ( reg_shadow & REG_BIT_TWL_REQ_RST_REQ ) != 0 ) { #if 0 // CODECバグ回避 // リセット単品でなかったら無視 if( ( reg1_old ^ reg_shadow ) == REG_BIT_TWL_REQ_RST_REQ ) #endif { set_irq( VREG_C_IRQ2, REG_BIT_TWL_RESET_REQ ); } } // バックライトをマスクして書き戻す EI( ); if( ( reg_shadow & ( REG_BIT_TWL_REQ_OFF_REQ | REG_BIT_TWL_REQ_RST_REQ )) != 0 ) { reg_shadow &= ~( REG_BIT_TWL_REQ_OFF_REQ | REG_BIT_TWL_REQ_RST_REQ ); iic_mcu_write_a_byte( IIC_SLA_CODEC, CODEC_REG_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 ); } /* ======================================================== 電池の管理 以下のピンは主にここで操作・監視されます。 ・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 250 void tsk_batt( ) { static u8 task_interval = 0; static bit temp_zone_charge_enable; // 温度で充電停止する時にヒステリシスを付けるため static bit pm_extdc_old; if( task_interval-- != 0 ) { return; } else { task_interval = (u8)( INTERVAL_TSK_BATT / SYS_INTERVAL_TICK ); } // アダプタステータス更新 ///////// if( pm_extdc_old != !PM_EXTDC_n ) { pm_extdc_old = !PM_EXTDC_n; if( pm_extdc_old ) { 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)( 1000 / INTERVAL_TSK_BATT / SYS_INTERVAL_TICK ); } else { 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; } } // 充電 /////////////////////////// // 温度付きヒステリシス if(( 75 <= raw_adc_temperature ) && ( raw_adc_temperature <= 184 )) { temp_zone_charge_enable = 1; // 充電許可 } else if(( raw_adc_temperature <= 61 ) || ( 189 <= raw_adc_temperature )) { temp_zone_charge_enable = 0; // 充電禁止 } else { // temp_zone_charge_enable そのまま } #ifndef _MODEL_WM0_ // WM0ではCHG_ENABLEピンは /WL_RST に配線されており、充電制御しない if( temp_zone_charge_enable && bt_chg_ready ) { BT_CHG_ENABLE(); // 温度範囲OKで充電再開 } else { BT_CHG_DISABLE(); // 温度危険! 充電停止 } #endif // 充電 // // →割り込み。miscの中でよろしくやってくれている。 if( !BT_CHG_n ) { set_bit( 1, vreg_ctr[VREG_C_STATUS], REG_BIT_BATT_CHARGE ); LED_CHARGE = 1; } else { set_bit( 0, vreg_ctr[VREG_C_STATUS], REG_BIT_BATT_CHARGE ); LED_CHARGE = 0; } if( chg_led_override != 0 ){ // 気がつく人いるかな…? chg_led_override -= 1; LED_CHARGE = 1; } // 電池残量 // if( system_status.pwr_state == ON ) { BT_get_left(); } } /******************************************************** 電池関係の初期化    ゲージ  | 有り     | 無し   ーーーーーーーーーーーーーーーーーーーーーーー    電池 有り| 実機     | ?   ーーーーーーーーーーーーーーーーーーーーーーー       無し| 白箱     | TS         | 実機電池無し |   ーーーーーーーーーーーーーーーーーーーーーーー   ゲージ有り、電池無し の白箱/実機判別は、  電池温度で判定する ***********************************************************/ #define swap_endian_16( x ) (unsigned int)(( x << 8 ) | ( x >> 8 )) void BT_chk( ) { u8 temp; union{ u16 _u16; // endian 注意 struct{ u8 lsb; u8 msb; }chars; }dat_16; BT_DET_P = 1; BT_TEMP_P = 1; wait_ms(1); // チャージに時間が掛かる { BT_VENDER battery_manufacturer_old = battery_manufacturer; // 電池メーカーの識別 temp = get_adc( ADC_SEL_BATT_DET ); BT_DET_P = 0; if( temp > 233 ) battery_manufacturer = BT_VENDER_OPEN; else if( temp > 197 ) battery_manufacturer = BT_VENDER_6; else if( temp > 158 ) battery_manufacturer = BT_VENDER_PANA; else if( temp > 123 ) battery_manufacturer = BT_VENDER_4; else if( temp > 79 ) battery_manufacturer = BT_VENDER_3; else if( temp > 33 ) battery_manufacturer = BT_VENDER_2; else if( temp > 5 ) battery_manufacturer = BT_VENDER_1; else battery_manufacturer = BT_VENDER_MAXELL; if( battery_manufacturer != battery_manufacturer_old ) { if( battery_manufacturer < BT_VENDER_OPEN ) { // バッテリが変わった // bt_comp = BT_COMP[ battery_manufacturer ]; // バッテリパラメータ変更 wait_ms( 10 ); // 0. バッテリ残量IC クイックスタート dat_16._u16 = swap_endian_16( 0x4000 ); // quick start iic_mcu_write( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_MODE, 2, &dat_16 ); bt_chg_ready = 1; } else { // 電池が外された bt_chg_ready = 0; } } } // 電池温度監視スタート renge_task_immed_add( BT_temp_update ); } void BT_init( ) { u8 temp; u8 origParam[4]; union{ u16 _u16; // endian 注意 struct{ u8 lsb; u8 msb; }chars; }dat_16; // PMIC バージョン読み出し // temp = iic_mcu_read_a_byte( IIC_SLA_PMIC, PM_REG_ADRS_VER ); // vreg_ctr[ VREG_C_PM_INFO ] = temp; /// デバッグ用は別にまとめた /* // -1. リセットをかけてみる dat_16._u16 = swap_endian_16( 0x5400 ); // reset iic_mcu_write( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_COMMAND, 2, &dat_16 ); // こいつはNACKを返す */ // 電池温度測定(TS,白箱判定も兼ねる) // raw_adc_temperature = get_adc( ADC_SEL_BATT_TEMP ); // 1. ロック解除 dat_16._u16 = swap_endian_16( 0x4A57 ); // unlock key if( iic_mcu_write( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_LOCK, 2, &dat_16 ) == ERR_SUCCESS ) { vreg_ctr[ VREG_C_STATUS_1 ] &= ~REG_BIT_GASGAUGE_ERR; // 残量IC有り // if( battery_manufacturer < BT_VENDER_OPEN ) { // 電池何かしらあり // system_status.model = MODEL_JIKKI; } else { // 電池無し // if( raw_adc_temperature < 4 ) { // 白箱 // system_status.model = MODEL_SHIROBAKO; } else { // 実機、バッテリ無し system_status.model = MODEL_UNKNOWN; } } } else { vreg_ctr[ VREG_C_STATUS_1 ] |= REG_BIT_GASGAUGE_ERR; // 残量IC NACK if( raw_adc_temperature > 0xF0 ) { // TS // system_status.model = MODEL_TS_BOARD; } else { // 実機、残量IC NACK( バッテリ無しまたは残量IC故障 ) #ifdef _ALLOW_NOBATT_ system_status.model = MODEL_JIKKI; #else system_status.model = MODEL_JIKKI_NOBATT; // 起動させない #endif } } if( system_status.model == MODEL_JIKKI ) { // wait_ms( 5 + 1 ); I2C_mの初期化時にウェイト入れてるので不要 // 2. 初期パラメータを一時保存 iic_mcu_read( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_RCOMP, 4, origParam ); // 3. 一時的にOCVを変更 dat_16._u16 = swap_endian_16( 0xDA20 ); // マジックナンバー的なもの。メーカー指定 iic_mcu_write( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_OCV, 2, &dat_16 ); // 4. 一時的にRCOMPを変更 dat_16._u16 = swap_endian_16( 0xFF00 ); iic_mcu_write( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_RCOMP, 2, &dat_16 ); // 5.メーカー別パラメータのロード { iic_mcu_set_wo_dma( ); iic_mcu_write( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_BT_PARAM, 64, &BT_PARAM[ battery_manufacturer ] ); } // 6. 150ms以上待つ wait_ms( 150 + 15 ); // 7. OCVに「とある値」を書く dat_16._u16 = swap_endian_16( 0xDA20 ); iic_mcu_write( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_OCV, 2, &dat_16 ); // 8. 150〜600ms待つ。600msは厳守 wait_ms( 150 + 15 ); // 9. SOCを読む。ベリファイのため。 temp = iic_mcu_read_a_byte( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_SOC ); if(( temp >= 0x74 ) && ( temp <= 0x75 )) { // カスタムモデル書き込みOK! }else{ // 失敗だったらリトライするのか? } // 10.元のRCOMPとOCVを書き戻す iic_mcu_write( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_RCOMP, 4, origParam ); // 11. ロック dat_16._u16 = swap_endian_16( 0x0000 ); // lock key iic_mcu_write( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_LOCK, 2, &dat_16 ); // おしまい // BT_temp_update( ); // 温度のtemp。 残量ICに行きます } } extern u16 _dbg_rcomp; /* ======================================================== raw_adc_temperatureに入っている値を℃に変換するとともに、 ・レジスタにセット ・残量ICにセット ======================================================== */ task_status_immed BT_temp_update( ) { static u8 rawdat_old; static s8 temperature; s16 newrcomp; /* サーミスタ - 10kΩ分圧点の時、 常用温度では分圧比のカーブがほぼリニアで、 村田 T[℃] = 81.48 - 111.97 x ratio TDK T = 81.406 - 111.81 x ratio */ if( rawdat_old != raw_adc_temperature ) { rawdat_old = raw_adc_temperature; // temperature = 81.45 - 111.9 * raw_adc_temperature/256.0; // それぞれ256倍してある temperature = ( 20851 - 112 * raw_adc_temperature + (256/2) ) /256; vreg_ctr[VREG_C_BT_TEMP] = (u8)temperature; newrcomp = 0; if( temperature > 20 ) { newrcomp = ( ( temperature - 20 ) * bt_comp.temp_co_up )/256; } else { newrcomp = ( ( temperature - 20 ) * bt_comp.temp_co_dn )/256; } newrcomp = bt_comp.rcomp + newrcomp; newrcomp = newrcomp; _dbg_rcomp = newrcomp; if( iic_mcu_write( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_RCOMP, 2, &newrcomp ) == ERR_SUCCESS ) { rawdat_old = raw_adc_temperature; } else { vreg_ctr[ VREG_C_STATUS_1 ] |= REG_BIT_GASGAUGE_ERR; } } return ( ERR_FINISED ); } /********************************************************** 電池残量ICから残量を取得し、レジスタに書き込む。  電池残量ICが無い・故障などの時はとりあえず残量99%とする。         ↑は status_1で確認可能。電源投入時にチェックしています。  BT_init()が実行されている必要があります。 **********************************************************/ void BT_get_left(){ u8 temp[2]; // 電池残量更新 // #ifdef _debug_bt_irq_ if( vreg_ctr[ VREG_C_COMMAND3 ] == 'd' ) { vreg_ctr[ VREG_C_BT_REMAIN ] = vreg_ctr[ VREG_C_DBG01 ]; } else #endif { if( system_status.model == MODEL_TS_BOARD ) { vreg_ctr[ VREG_C_BT_REMAIN ] = 99; } else { if(( vreg_ctr[ VREG_C_STATUS_1 ] & REG_BIT_GASGAUGE_ERR ) == 0 ) { temp[0] = iic_mcu_read_a_byte( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_VCELL ); if( iic_mcu_bus_status != ERR_SUCCESS ) { // バッテリ残量が取れなくなった vreg_ctr[ VREG_C_STATUS_1 ] |= REG_BIT_GASGAUGE_ERR; bt_chg_ready = 0; vreg_ctr[ VREG_C_BT_REMAIN ] = 0; system_status.cnt_force_off = 1; // 強制電源断フラグ } else { vreg_ctr[ VREG_C_BT_VOLTAGE ] = temp[0]; iic_mcu_read( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_SOC, 2, temp ); vreg_ctr[ VREG_C_BT_REMAIN ] = temp[0]; vreg_ctr[ VREG_C_BT_REMAIN_FINE ] = temp[1]; // モデルゲージと実際との乖離が大きい/電圧がPMICの限界を超えそう if( vreg_ctr[ VREG_C_BT_VOLTAGE ] < V_TH_ZERO ) { // 電圧が規定値になってしまったので強制off vreg_ctr[ VREG_C_BT_REMAIN ] = 0; } else if(( vreg_ctr[ VREG_C_BT_VOLTAGE ] < V_TH_EMPTY ) && ( vreg_ctr[ VREG_C_BT_REMAIN ] > BATT_TH_EMPTY )) { vreg_ctr[ VREG_C_BT_REMAIN ] = BATT_TH_EMPTY; } else if(( vreg_ctr[ VREG_C_BT_VOLTAGE ] < V_TH_LO ) && ( vreg_ctr[ VREG_C_BT_REMAIN ] > BATT_TH_LO )) { vreg_ctr[ VREG_C_BT_REMAIN ] = BATT_TH_LO; } } } // もう特に何もすること無いと思う... } } // 残量で割り込み。急激に減ると飛ぶことがある // { static u8 bt_remain_old; if( (( vreg_ctr[ VREG_C_BT_REMAIN ] <= BATT_TH_LO ) && ( BATT_TH_LO < bt_remain_old ))|| (( vreg_ctr[ VREG_C_BT_REMAIN ] <= BATT_TH_EMPTY ) && ( BATT_TH_EMPTY < bt_remain_old ))|| (( vreg_ctr[ VREG_C_BT_REMAIN ] == 0 ) && ( bt_remain_old != 0 )) ) { set_irq( VREG_C_IRQ1, REG_BIT_BT_REMAIN ); } if(( vreg_ctr[ VREG_C_BT_REMAIN ] == 0 ) && ( bt_remain_old != 0 )) { // system_status.cnt_force_off = 1; // 強制電源断フラグ } bt_remain_old = vreg_ctr[ VREG_C_BT_REMAIN ]; if( system_status.pwr_state == OFF_TRIG ) { bt_remain_old = 100; } } // PMIC-NTRに電池残量を教えてあげる iic_mcu_write_a_byte( IIC_SLA_CODEC, CODEC_REG_BT, ( vreg_ctr[ VREG_C_BT_REMAIN ] <= BATT_TH_LO )? 1 : 0 ); // 1で電池切れ } static unsigned long bt_relax_timer; #define BT_RELAX_TIME_MIN (unsigned long)30 /**********************************************************  電池がリラックスするのを待つ ・PM_sys_power_offの時 ・充電中にアダプタが抜かれたとき **********************************************************/ void BT_set_relax_timer() { // RTCを使うと楽かと思ったがとんでもなかった bt_relax_timer = (unsigned long)( BT_RELAX_TIME_MIN * 60 * 1000 / SYS_INTERVAL_TICK ); } u8 BT_is_relaxed() { if( bt_relax_timer != 0 ) { bt_relax_timer -= 1; return( 0 ); } else { return( 1 ); } }