/* ======================================================== 対PMIC 藤田@開技 nintendo '08 Dec ======================================================== */ #pragma nop #include "incs.h" #include "adc.h" #include "led.h" #include "pm.h" // ======================================================== // -1.45 ,-3.9} // ======================================================== static const u8 BT_BT_PARAM_PANA[64] = { 0xAD, 0x30, 0xAE, 0x70, 0xB0, 0x00, 0xB3, 0x00, 0xB4, 0x70, 0xB5, 0xA0, 0xB7, 0x80, 0xBA, 0x00, 0xBB, 0x90, 0xBD, 0x00, 0xBE, 0x00, 0xBF, 0xF0, 0xC3, 0x00, 0xC5, 0xC0, 0xC8, 0x00, 0xCA, 0xC0, 0x04, 0x00, 0x12, 0x00, 0x0C, 0x10, 0x24, 0x00, 0x10, 0xD0, 0x1B, 0xF0, 0x0A, 0xF0, 0x08, 0xE0, 0x0C, 0xF0, 0x08, 0xC0, 0x08, 0xB0, 0x07, 0xF0, 0x0B, 0x00, 0x05, 0xD0, 0x02, 0x00, 0x09, 0x00 }; static const unsigned char BT_PANA_RCOMP = 135; static const float BT_PANA_TEMPCOUP = 0.3; static const float BT_PANA_TEMPCODN = 0.5; // ======================================================== u8 raw_adc_temperature; u8 rcomp; float temp_co_up; float temp_co_dn; #define _TEG_ /* ======================================================== バッテリの認証を行います。 引数 無し 返値 (ERR)ERR_SUCCESS 成功 それ以外 失敗 ======================================================== */ err PM_bt_auth( ) { /* todo マキシムなら Dallas-1wire 通信 SHA-1計算 */ return ( ERR_SUCCESS ); } /******************************************************//** PMIC達の初期化 \n 電池メーカー識別 \n 電池残量ICのセット \n バージョン情報の取得 \n \n 以下のピンは主にここで操作・監視されます。 \n ・PM_BT_DET,_P *********************************************************/ #define swap_endian_16( x ) (unsigned int)( x << 8 | x >> 8 ) void PM_init( ) { u8 temp; u8 origParam[4]; union{ u16 _u16; // ↓でわかるように、little endian です。注意。 struct{ u8 lsb; u8 msb; }chars; }dat_16; #if 1 wait_ms( 200 ); // -1. なんかおかしい… リセットをかけてみる dat_16._u16 = swap_endian_16( 0x5400 ); // reset iic_mcu_write( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_COMMAND, 2, &dat_16.chars.lsb ); #endif wait_ms( 200 ); // 0. バッテリ残量IC クイックスタート dat_16._u16 = swap_endian_16( 0x4000 ); // quick start if( iic_mcu_write( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_MODE, 2, &dat_16.chars.lsb ) != ERR_SUCCESS ) { vreg_ctr[ VREG_C_STATUS_X ] |= 0x01; } else { // 1. ロック解除 dat_16._u16 = swap_endian_16( 0x4057 ); // unlock key iic_mcu_write( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_LOCK, 2, &dat_16.chars.lsb ); // 2. 初期パラメータを一時保存 iic_mcu_read( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_RCOMP, 4, origParam ); // 3. 一時的にOCVを変更 dat_16._u16 = swap_endian_16( 0xD4C0 ); // マジックナンバー的なもの。メーカー指定 iic_mcu_write( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_OCV, 2, &dat_16.chars.lsb ); // 4. 一時的にRCOMPを変更 dat_16._u16 = swap_endian_16( 0xFF00 ); iic_mcu_write( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_RCOMP, 2, &dat_16.chars.lsb ); // 電池メーカーの識別 BT_DET_P = 1; temp = ( u8 ) ( get_adc( ADC_SEL_BATT_DET ) >> 6 ); BT_DET_P = 0; iic_mcu_set_wo_dma( ); // 5.メーカー別パラメータのロード switch ( temp ) { // case( BT_VENDER_PANA ): default: iic_mcu_write( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_BT_PARAM, 64, BT_BT_PARAM_PANA ); /* iic_mcu_write( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_BT_PARAM, 16, BT_BT_PARAM_PANA ); iic_mcu_set_wo_dma( ); iic_mcu_write( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_BT_PARAM+16, 16, &BT_BT_PARAM_PANA[16] ); iic_mcu_set_wo_dma( ); iic_mcu_write( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_BT_PARAM+16*2, 16, &BT_BT_PARAM_PANA[32] ); iic_mcu_set_wo_dma( ); iic_mcu_write( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_BT_PARAM+16*3, 16, &BT_BT_PARAM_PANA[48] ); */ rcomp = BT_PANA_RCOMP; temp_co_up = BT_PANA_TEMPCOUP; temp_co_dn = BT_PANA_TEMPCODN; break; } // 6. 150ms以上待つ wait_ms( 200 ); // 7. OCVに「とある値」を書く dat_16._u16 = swap_endian_16( 0xD4C0 ); iic_mcu_write( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_OCV, 2, &dat_16.chars.lsb ); // 8. 150〜600ms待つ。600msは厳守 wait_ms( 200 ); // 9. SOCを読む。ベリファイのため。 temp = iic_mcu_read_a_byte( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_SOC ); if( 0x6D == temp || temp == 0x6E || temp == 0x6F ){ // カスタムモデル書き込み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.chars.lsb ); // おしまい // } // 電池温度測定 BT_TEMP_P = 1; // 電池温度監視スタート raw_adc_temperature = get_adc( ADC_SEL_BATT_TEMP ); // 温度のtemp。 renge_task_immed_add( PM_bt_temp_update ); // PMIC バージョン読み出し // temp = iic_mcu_read_a_byte( IIC_SLA_PMIC, PM_REG_ADRS_VER ); // vreg_ctr[ VREG_C_PM_INFO ] = temp; } /* ======================================================== raw_adc_temperatureに入っている値を℃に変換するとともに、 ・レジスタにセット ・残量ICにセット ======================================================== */ task_status_immed PM_bt_temp_update( ) { u16 newrcomp; static u8 temp_old = 0; static u8 count = 0; // たまにしか書きに行かない volatile static u8 skip = 1; if( skip != 0 ){ return ( ERR_SUCCESS ); } /* サーミスタ - 10kΩ分圧点の時、 常用温度では分圧比のカーブがほぼリニアで、 村田 T[℃] = 81.48 - 111.97 x ratio TDK T = 81.406 - 111.81 x ratio */ vreg_ctr[VREG_C_BT_TEMP] = ( u8 ) ( ( s16 ) ( ( 163 - ( 224 * raw_adc_temperature ) ) / 2 ) >> 8 ); // 時々/大きく変化があったら書きにゆく if( ( abs( vreg_ctr[VREG_C_BT_TEMP] - temp_old ) > 3 ) || ( count == 0 ) ) { if( ( s8 ) vreg_ctr[VREG_C_BT_TEMP] > 20 ) { newrcomp = -( ( ( s16 ) vreg_ctr[VREG_C_BT_TEMP] - 20 ) * temp_co_up ); } else { newrcomp = -( ( ( s16 ) vreg_ctr[VREG_C_BT_TEMP] - 20 ) * temp_co_dn ); } newrcomp += rcomp; /* If Temperature > 20 Then NewRCOMP = StartingRCOMP + ((Temperature - 20) * TempCoUp) ElseIf Temp < 20 Then NewRCOMP = StartingRCOMP + ((Temperature - 20) * TempCoDown) Else NewRCOMP = StartingRCOMP End If */ if( iic_mcu_write ( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_RCOMP, 2, &newrcomp ) == ERR_SUCCESS ) { temp_old = vreg_ctr[VREG_C_BT_TEMP]; } count += 1; } return ( ERR_SUCCESS ); } /* ======================================================== バックライト周り ======================================================== */ #ifdef _PMIC_TWL_ err PM_LCD_on( ) { // PM_TEG_LCD_dis( 0 ); // 何もしない wait_ms( DELAY_PM_TSS_50B ); wait_ms( DELAY_PM_TSS_50B ); vreg_ctr[VREG_C_STATUS] |= REG_BIT_LCD_POW; return ( PM_chk_LDSW( ) ); } err PM_LCD_off( ) { // PM_TEG_LCD_dis( 1 ); wait_ms( 1 + 50 ); PM_VDDLCD_off( ); // 残ってたの全部止めます。 vreg_ctr[VREG_C_STATUS] &= ~REG_BIT_LCD_POW; return ( ERR_SUCCESS ); } err PM_BL_on( ) { wait_ms( 10 ); vreg_ctr[VREG_C_STATUS] |= REG_BIT_BL; return ( PM_chk_LDSW( ) ); } err PM_BL_off( ) { vreg_ctr[VREG_C_STATUS] &= ~REG_BIT_BL; return ( ERR_SUCCESS ); } err PM_LCD_vcom_set( ) { return ( ERR_SUCCESS ); } task_status_immed tski_vcom_set( ) { PM_LCD_vcom_set( ); return ( ERR_FINISED ); } #else /* ======================================================== ↑で、レジスタ書き込みから呼び出される時のため  I2Cの取り合いの関係でここから呼ぶ ======================================================== */ task_status_immed tski_vcom_set( ) { PM_LCD_vcom_set( ); return ( ERR_FINISED ); } /* ======================================================== 液晶系の電源制御  ステータスフラグはすぐに立ててしまう。  不感応時間があるし、 起動失敗であれば電源が落ちる 別のタスクで電源落ちは監視していて、ステータスもクリアする ======================================================== */ err PM_LCD_on( ) { PM_VDDLCD_on( ); wait_ms( DELAY_PM_TSS_50B ); wait_ms( DELAY_PM_5V_TO_VCOM ); PM_TCOM_VCS_on( ); wait_ms( DELAY_PM_TSS_50B ); iic_mcu_write_a_byte( IIC_SLA_PMIC, 0x22, 0x4A ); // バグ持ちPMIC対策 vreg_ctr[VREG_C_STATUS] |= REG_BIT_LCD_POW; SND_DEPOP = 0; // 1でミュート return ( PM_chk_LDSW( ) ); } err PM_LCD_off( ) { PM_TCOM_VCS_off( ); wait_ms( 1 + 50 ); // PM_VDDLCD_off(); // 残ってたの全部止めます。 vreg_ctr[VREG_C_STATUS] &= ~REG_BIT_LCD_POW; SND_DEPOP = 1; return ( ERR_SUCCESS ); } err PM_BL_on( ) { PM_set_BL( 0x03 ); wait_ms( 10 ); vreg_ctr[VREG_C_STATUS] |= REG_BIT_BL; return ( PM_chk_LDSW( ) ); } err PM_BL_off( ) { PM_set_BL( 0x00 ); vreg_ctr[VREG_C_STATUS] &= ~REG_BIT_BL; 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 ); } #endif /* ======================================================== ↑の、I2Cコマンドでの実行の場合の為の、ラッパー的な物 実仕様上は大丈夫だろうけど、同じ関数がキューに2つ以上 乗らないようにしてあるし、ばらばらにしておく。 ======================================================== */ task_status_immed tski_PM_LCD_on( ) { PM_LCD_on( ); return ( ERR_FINISED ); } task_status_immed tski_PM_BL_on( ) { PM_BL_on( ); return ( ERR_FINISED ); } task_status_immed tski_PM_BL_off( ) { PM_BL_off( ); return ( ERR_FINISED ); } task_status_immed tski_PM_LCD_off( ) { PM_LCD_off( ); return ( ERR_FINISED ); } /* ======================================================== シーケンスの通り電源を立ち上げてゆきます。 返値 0 最後まで正常に完了した。 1 ショートなどで電源があがりきらなかった 以下のピンは主にここで操作・監視されます。 ・POW_CONT1,2 TEG電源のみ ======================================================== */ err PM_sys_pow_on( ) { #ifndef _PMIC_TWL_ u8 temp; // 電池温度測定 while( ADCEN != 0 ) {; } BT_TEMP_P = 1; vreg_ctr[VREG_C_BT_TEMP] = get_adc( ADC_SEL_BATT_TEMP ); BT_TEMP_P = 0; PM_bt_temp_update( ); // 温度のtemp。 残量ICに行きます // 残量チェック vreg_ctr[VREG_C_BT_REMAIN] = PM_get_batt_left( ); vreg_ctr[VREG_C_BT_REMAIN] = 200; if( vreg_ctr[VREG_C_BT_REMAIN] < 0 ) { return ( 1 ); } // 電源順次立ち上げ RESET2_ast; FCRAM_RST_ast; PM_LDSW_on( ); wait_ms( 1 ); iic_mcu_write_a_byte( IIC_SLA_PMIC, 0x22, 0xCA ); // バグ持ちPMIC対策 OVP解除 wait_ms( DELAY_PM_TW_PWUP ); PM_VDD_on( ); wait_ms( DELAY_PM_TW_PWUP ); PM_VDD50A_on( ); wait_ms( DELAY_PM_TW_PWUP ); iic_mcu_write_a_byte( IIC_SLA_PMIC, PM_REG_ADRS_POW_SAVE, 0x03 ); // バグ持ちPMIC対策 強制PWM if( PM_chk_LDSW( ) == 0 ) { return ( ERR_ERR ); } PM_reset_neg( ); RESET2_neg; FCRAM_RST_neg; return ( ERR_SUCCESS ); #else // KE3-L で開発 u8 temp; // 電源投入 RESETs_ast; FCRAM_RST_ast; PM_TEG_PWSW = 1; wait_ms( 160 ); PM_TEG_PWSW = 0; // 残量確認 temp = PM_get_batt_left( ); temp = 200; if( temp < ( 255 * 0.03 ) ) { return ( ERR_ERR ); } vreg_ctr[VREG_C_BT_REMAIN] = temp; PM_reset_neg( ); RESET2_neg; FCRAM_RST_neg; wait_ms( 100 ); if( !RESET1_n ) { // 起動失敗 RESETs_ast; FCRAM_RST_ast; return ( ERR_ERR ); } return ( ERR_SUCCESS ); #endif } /* ======================================================== 電源OFFシーケンス todo: 電源異常断の場合 ======================================================== */ err PM_sys_pow_off( ) { #ifdef _PMIC_CTR_ PM_BL_off( ); PM_LCD_off( ); // TCOM,VCS OFF も消してきます。 PM_reset_ast( ); RESET2_ast; FCRAM_RST_ast; PM_off( ); PM_LDSW_off( ); #else if( RESET1_n ) { RESETs_ast; FCRAM_RST_ast; PM_TEG_PWSW = 1; wait_ms( 250 ); wait_ms( 250 ); wait_ms( 250 ); PM_TEG_PWSW = 0; } RESETs_ast; FCRAM_RST_ast; #endif return ( ERR_SUCCESS ); } /* ======================================================== スリープシーケンス ======================================================== */ err to_sleep( ) { PM_LCD_off( ); return 0; } /* ======================================================== 電池の管理 以下のピンは主にここで操作・監視されます。 ・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 100 void tsk_batt( ) { static u8 task_interval = 0; static u8 charge_hys = 0; // ヒステリシスで上限下限を拡張するとき1 if( task_interval != 0 ) { task_interval -= 1; return; } else { task_interval = ( INTERVAL_TSK_BATT / SYS_INTERVAL_TICK ); } // 電源周りのステータスが変化? /// set_bit( PM_EXTDC, vreg_ctr[VREG_C_STATUS], REG_BIT_POW_SUPPLY ); set_bit( !BT_CHG_n, vreg_ctr[VREG_C_STATUS], REG_BIT_BATT_CHARGE ); // →割り込み。miscの中でよろしくやってくれている。 // 充電 /////////////////////////// // 温度付きヒステリシス if( ( ( 345 / 4 ) < vreg_ctr[VREG_C_BT_TEMP] ) && ( vreg_ctr[VREG_C_BT_TEMP] < ( 739 / 4 ) ) ) { charge_hys = 1; } if( ( ( ( 345 - 65 ) / 4 ) < vreg_ctr[VREG_C_BT_TEMP] ) && ( vreg_ctr[VREG_C_BT_TEMP] < ( ( 739 + 18 ) / 4 ) ) ) { charge_hys = 0; } if( ( ( charge_hys == 1 ) && ( ( ( 345 - 65 ) / 4 ) < vreg_ctr[VREG_C_BT_TEMP] ) && ( vreg_ctr[VREG_C_BT_TEMP] < ( ( 739 + 18 ) / 4 ) ) ) || ( ( charge_hys == 0 ) && ( ( 345 / 4 ) < vreg_ctr[VREG_C_BT_TEMP] ) && ( vreg_ctr[VREG_C_BT_TEMP] < ( 739 / 4 ) ) ) ) { BT_CHG_EN = 1; } else { BT_CHG_EN = 0; } // 充電LED LED_duty_CHARGE = !BT_CHG_n ? vreg_ctr[VREG_C_LED_BRIGHT] : 0; if(( vreg_ctr[ VREG_C_STATUS_X ] & 0x01 ) == 0 ) { // 電池残量の取得 { u8 temp; temp = PM_get_batt_left(); vreg_ctr[ VREG_C_BT_REMAIN ] = temp; // todo 閾値を超えたら割り込み } } else { vreg_ctr[ VREG_C_BT_REMAIN ] = 0xFF; } vreg_ctr[ VREG_C_FREE0 ] = vreg_ctr[ VREG_C_BT_REMAIN ]; vreg_ctr[ VREG_C_FREE1 ] = iic_mcu_read_a_byte( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_VCELL ); return; } /*========================================================= extDC割り込み 電源OFFから起こす(充電の温度監視のため)のみ 普段はポーリング(pm) =========================================================*/ __interrupt void intp4_extdc( ) { ; } /*========================================================= フタ開け閉め割り込み 電源OFFから起こす(充電の温度監視のため)のみ 普段はポーング(misc) =========================================================*/ __interrupt void intp5_shell( ) { ; } /*========================================================= 旧PMICへのコマンド書き込み =========================================================*/ __interrupt void intp6_PM_irq( ) { renge_task_immed_add( ntr_pmic_comm ); } /* ======================================================== PMICからの割り込みを受けて、NTRPMIC互換レジスタからリード ======================================================== */ task_status_immed ntr_pmic_comm( ) { #ifdef _CODEC_CTR_ static u8 reg_shadow; u8 reg_old; reg_old = reg_shadow; // BL関係 reg_shadow = iic_mcu_read_a_byte( IIC_SLA_CODEC, CODEC_REG_PMCOMP ); DI( ); // offリクエスト if( ( reg_shadow & REG_BIT_TWL_REQ_OFF_REQ ) != 0 ) { set_irq( VREG_C_IRQ3, REG_BIT_TWL_OFF_REQ ); vreg_ctr[VREG_C_IRQ3] |= REG_BIT_TWL_OFF_REQ; if( ( vreg_ctr[VREG_C_IRQ_MASK3] & REG_BIT_TWL_OFF_REQ ) == 0 ) { IRQ0_ast; } } // リセットリクエスト if( ( reg_shadow & REG_BIT_TWL_REQ_RST_REQ ) != 0 ) { vreg_ctr[VREG_C_IRQ3] |= REG_BIT_TWL_RESET_REQ; if( ( vreg_ctr[VREG_C_IRQ_MASK3] & REG_BIT_TWL_RESET_REQ ) == 0 ) { IRQ0_ast; } } // バックライトが... if( ( ( reg_old ^ reg_shadow ) & ~( REG_BIT_TWL_REQ_BL ) ) != 0 ) { if( ( reg_shadow & ( REG_BIT_TWL_REQ_BL ) ) == 0x00 ) { // 両方消された vreg_ctr[VREG_C_IRQ3] |= REG_BIT_TWL_BL_OFF; if( ( vreg_ctr[VREG_C_IRQ_MASK3] & REG_BIT_TWL_BL_OFF ) == 0 ) { IRQ0_ast; } } else if( ( reg_shadow & ( REG_BIT_TWL_REQ_BL ) ) == ( REG_BIT_TWL_REQ_BL ) ) { // 両方ついた vreg_ctr[VREG_C_IRQ3] |= REG_BIT_TWL_BL_ON; if( ( vreg_ctr[VREG_C_IRQ_MASK3] & REG_BIT_TWL_BL_ON ) == 0 ) { IRQ0_ast; } } } EI( ); reg_shadow &= ~( REG_BIT_TWL_REQ_BL ); // BLだけマスクして、クリアの準備 iic_mcu_write_a_byte( IIC_SLA_CODEC, CODEC_REG_PMCOMP, reg_shadow ); #endif return ( ERR_FINISED ); }