mirror of
https://github.com/rvtr/twl_mcu.git
synced 2025-06-18 06:35:40 -04:00
464 lines
14 KiB
C
464 lines
14 KiB
C
#pragma interrupt INTAD callbk_int_ad
|
||
|
||
/******************************************************************************
|
||
1Ch ADCリード
|
||
de JHL 藤田@開技
|
||
'07 Dec
|
||
*******************************************************************************/
|
||
#include "incs.h"
|
||
|
||
extern bit adc_calib_mode;
|
||
extern u8 vregs[];
|
||
|
||
extern bit pwon_wt_sel;
|
||
|
||
|
||
// Vref = 2.8V
|
||
// F B 7 3 1 0
|
||
u8 const threshold_Co[] = { 99, 82, 67, 31, 0 }; // batt == 0
|
||
u8 const threshold_Co_NAND[] = { 99, 82, 68, 46, 27 };
|
||
u8 const threshold_PSS[] = { 77, 52, 33, 11, 0 }; // batt == 5
|
||
u8 const threshold_PSS_NAND[] = { 82, 55, 42, 30, 27 };
|
||
u8 const threshold_IS[] = { 78, 62, 48, 32, 0 }; // batt == 3, vref = 3.3v、オフセットあり(1.8V)
|
||
u8 const threshold_IS_NAND[] = { 78, 62, 48, 32, 16 };
|
||
// 非 NAND アプリは 0 になりません。
|
||
/*
|
||
>> (AVref=3.3Vとした,AOUTの電圧)
|
||
>> 100% 1.95 ~ 5 F
|
||
>> 75% 1.9 ~ 1.95V 4 B
|
||
>> 50% 1.85 ~ 1.9V 3 7
|
||
>> 25% 1.8 ~ 1.85V 2 3
|
||
>> 5% 1.75 ~ 1.8V 1 1
|
||
>> 2% 1.7 ~ 1.75V 0 0
|
||
*/
|
||
|
||
u16 vBatt_raw; // 補正値加算前
|
||
u16 vBatt; // 移動平均をとった物
|
||
|
||
u8 adc_comp_val; // 補正値。閾値テーブルを作るときに加算
|
||
|
||
u16 Vbatt_threshold[5];
|
||
|
||
u8 battLvl;
|
||
u8 battLvl_old; // 割り込みをかけるため。使い回してます
|
||
|
||
|
||
/******************************************************************************
|
||
電池電圧→電池残量換算
|
||
電池劣化とか、負荷による電池電圧の降下は気にしません。
|
||
BOOTモードのときは来ません
|
||
25Hz( = 40ms間隔 )で呼ばれます
|
||
******************************************************************************/
|
||
void tsk_adc(){
|
||
static u16 vBatt_vals[ 9 ];
|
||
static u8 trigger_counter;
|
||
static u16 geta;
|
||
static u16 vBatt_last_wake;
|
||
|
||
static u8 battLvl_hist;
|
||
static u8 battLvl_count;
|
||
u8 battLvl_now;
|
||
|
||
static u8 vBatt_th_hys[ 5 ];
|
||
|
||
static u8 on_start = 0;
|
||
|
||
#ifdef debug_codes
|
||
if( !pwon_wt_sel ){
|
||
#endif
|
||
battLvl_old = battLvl;
|
||
|
||
// パルス性のノイズを取り、データの取り込み
|
||
vBatt_vals[ 8 ] = vBatt_vals[ 7 ];
|
||
vBatt_vals[ 7 ] = vBatt_vals[ 6 ];
|
||
vBatt_vals[ 6 ] = vBatt_vals[ 5 ];
|
||
vBatt_vals[ 5 ] = vBatt_vals[ 4 ];
|
||
vBatt_vals[ 4 ] = vBatt_vals[ 3 ];
|
||
vBatt_vals[ 3 ] = vBatt_vals[ 2 ];
|
||
vBatt_vals[ 2 ] = vBatt_vals[ 1 ];
|
||
if( ( ( vBatt_vals[ 0 ] << 1 ) < ( vBatt_vals[ 1 ] + vBatt_raw + 5 ) )
|
||
&& ( ( vBatt_vals[ 0 ] << 1 ) > ( vBatt_vals[ 1 ] + vBatt_raw - 5 ) ) ){
|
||
vBatt_vals[ 1 ] = vBatt_vals[ 0 ];
|
||
}else{
|
||
vBatt_vals[ 1 ] = ( ( vBatt_vals[ 0 ] + vBatt_raw ) >> 1 );
|
||
}
|
||
vBatt_vals[ 0 ] = vBatt_raw;
|
||
vBatt = ( ( vBatt_vals[ 8 ] + vBatt_vals[ 7 ] + vBatt_vals[ 6 ] + vBatt_vals[ 5 ]
|
||
+ vBatt_vals[ 4 ] + vBatt_vals[ 3 ] + vBatt_vals[ 2 ] + vBatt_vals[ 1 ] ) >> 3 );
|
||
|
||
// スリープ時の、ゲタ見積もり
|
||
if( PM_SLP == 0 ){
|
||
trigger_counter = 0;
|
||
geta = 0;
|
||
}else{
|
||
trigger_counter++;
|
||
if( trigger_counter == 1 ){
|
||
; // カウンタの帳尻合わせです
|
||
}else if( trigger_counter == 2 ){
|
||
vBatt_last_wake = vBatt_vals[ 8 ];
|
||
if( vBatt_last_wake > vBatt_vals[ 7 ] ) vBatt_last_wake = vBatt_vals[ 7 ];
|
||
if( vBatt_last_wake > vBatt_vals[ 6 ] ) vBatt_last_wake = vBatt_vals[ 6 ];
|
||
if( vBatt_last_wake > vBatt_vals[ 5 ] ) vBatt_last_wake = vBatt_vals[ 5 ];
|
||
if( vBatt_last_wake > vBatt_vals[ 4 ] ) vBatt_last_wake = vBatt_vals[ 4 ];
|
||
if( vBatt_last_wake > vBatt_vals[ 3 ] ) vBatt_last_wake = vBatt_vals[ 3 ];
|
||
if( vBatt_last_wake > vBatt_vals[ 2 ] ) vBatt_last_wake = vBatt_vals[ 2 ];
|
||
if( vBatt_last_wake > vBatt_vals[ 1 ] ) vBatt_last_wake = vBatt_vals[ 1 ];
|
||
}else if( trigger_counter < 127 ){
|
||
geta = vBatt - vBatt_last_wake;
|
||
if( geta > 0x8000 ){
|
||
geta = 0;
|
||
}
|
||
}else{
|
||
trigger_counter--;
|
||
}
|
||
}
|
||
|
||
if( ( vBatt - geta ) > Vbatt_threshold[ 0 ] ){ battLvl_now = 0x05;
|
||
}else if( ( vBatt - geta ) > Vbatt_threshold[ 1 ] ){ battLvl_now = 0x04;
|
||
}else if( ( vBatt - geta ) > Vbatt_threshold[ 2 ] ){ battLvl_now = 0x03;
|
||
}else if( ( vBatt - geta ) > Vbatt_threshold[ 3 ] ){ battLvl_now = 0x02;
|
||
}else if( ( vBatt - geta ) > Vbatt_threshold[ 4 ] ){ battLvl_now = 0x01;
|
||
}else{ battLvl_now = 0x00;
|
||
}
|
||
|
||
DBG_IIC_REG_TMP3( (u8)vBatt );
|
||
DBG_IIC_REG_TMP2( battLvl_now );
|
||
|
||
if( battLvl_hist != battLvl_now ){
|
||
battLvl_count = 0;
|
||
battLvl_hist = battLvl_now;
|
||
}else{
|
||
++battLvl_count;
|
||
if( on_start < 30 ){
|
||
// 起動直後は電池電圧早く出す
|
||
on_start++;
|
||
if( battLvl_count > 10 ){ // 何回か同じ値を連続でとったら、更新
|
||
battLvl_count = 0;
|
||
battLvl = battLvl_now;
|
||
}
|
||
}else{
|
||
// 通常運転
|
||
if( battLvl_count > 25 ){ // 何回か同じ値を連続でとったら、更新
|
||
battLvl_count = 0;
|
||
if( n_ac_supp == 0 ){ // アダプタの有無で一方通行
|
||
// アダプタの有り
|
||
if( battLvl_now > battLvl ){
|
||
battLvl++;
|
||
}
|
||
if( ( battLvl_now != battLvl )
|
||
&& ( battLvl_now == 0x00 ) ) { // タイミングが悪く、アダプタありにも関わらずbatt-empty
|
||
battLvl = 0;
|
||
}
|
||
}else{
|
||
// アダプタなし
|
||
if( battLvl_now < battLvl ){
|
||
battLvl--;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
#ifdef debug_codes
|
||
}
|
||
#endif
|
||
switch( battLvl ){ // マイコン遅い
|
||
case( 2 ): vregs[ REG_INT_ADRS_POWER_INFO ] = 0x03; break;
|
||
case( 3 ): vregs[ REG_INT_ADRS_POWER_INFO ] = 0x07; break;
|
||
case( 4 ): vregs[ REG_INT_ADRS_POWER_INFO ] = 0x0B; break;
|
||
case( 5 ): vregs[ REG_INT_ADRS_POWER_INFO ] = 0x0F; break;
|
||
case( 0 ): vregs[ REG_INT_ADRS_POWER_INFO ] = 0x00; break;
|
||
default: vregs[ REG_INT_ADRS_POWER_INFO ] = 0x01; break;
|
||
}
|
||
|
||
#ifdef debug_saito_special
|
||
GPIO_dir = 0;
|
||
GPIO_dat = (bit)( battLvl & 0x01 );
|
||
#endif
|
||
|
||
chk_obs_pmic_batt_low(); // NTR向け、電池残量減少通知
|
||
#ifdef debug_codes
|
||
if( !pwon_wt_sel ){
|
||
chk_irq0_batt(); // 電池残量減少割り込み
|
||
}
|
||
#else
|
||
chk_irq0_batt();
|
||
#endif
|
||
ADC_Start();
|
||
}
|
||
|
||
|
||
|
||
/******************************************************************************
|
||
NTRの一部のソフトが、PMIC側の battery_low ビットを見ているのでセットしてやる
|
||
******************************************************************************/
|
||
void chk_obs_pmic_batt_low(){
|
||
// 減ってきたので通知
|
||
if( ( 0x02 < battLvl_old )
|
||
&& ( battLvl <= 0x02 ) ){
|
||
iic2m_write_data( IIC_SLV_ADDR_PMIC, 0x02, 0x10 ); // LEDを赤相当に
|
||
}
|
||
// 増えてきたので復帰
|
||
if( ( battLvl_old <= 0x03 )
|
||
&& ( 0x03 < battLvl ) ){
|
||
iic2m_write_data( IIC_SLV_ADDR_PMIC, 0x02, 0x00 ); // LEDを緑相当に
|
||
}
|
||
}
|
||
|
||
|
||
|
||
/******************************************************************************
|
||
電池減ってきた割り込みをかける
|
||
******************************************************************************/
|
||
void chk_irq0_batt(){
|
||
static u8 irq_hist = 0;
|
||
|
||
// low割り込み
|
||
if( ( battLvl == 0x01 )
|
||
&& ( irq_hist == 0 ) ){
|
||
irq_hist = 0x02;
|
||
vregs[ REG_INT_ADRS_IRQ ] |= 0x20;
|
||
if( is_TWL ){
|
||
// DI();
|
||
n_irq_ast;
|
||
n_irq_ngt;
|
||
// EI();
|
||
}
|
||
}
|
||
|
||
if( with_NAND ){
|
||
// empty割り込み
|
||
// 電圧検出の所の仕様により、残量1を飛び越して0になることはない...はず。
|
||
if( battLvl == 0x00 ){
|
||
if( irq_hist == 0x00 ){ // 突然 emptyになった?
|
||
irq_hist = 0x03;
|
||
vregs[ REG_INT_ADRS_IRQ ] |= 0x30; // そうなら、両方立てる
|
||
if( is_TWL ){
|
||
// DI();
|
||
n_irq_ast;
|
||
n_irq_ngt;
|
||
// EI();
|
||
}
|
||
}else if( irq_hist == 0x02 ){ // 以前にLow割り込みをかけた
|
||
irq_hist = 0x03;
|
||
vregs[ REG_INT_ADRS_IRQ ] |= 0x10; // 割り込みを掛けまくらないように
|
||
if( is_TWL ){
|
||
// DI();
|
||
n_irq_ast;
|
||
n_irq_ngt;
|
||
// EI();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 電池あがってきたらフラグ消してしまう
|
||
if( battLvl >= 0x01 ){ // low以上なら
|
||
// DI();
|
||
vregs[ REG_INT_ADRS_IRQ ] &= ~0x10; // emptyなかったことに
|
||
// EI();
|
||
irq_hist &= ~0x01;
|
||
}
|
||
|
||
if( battLvl >= 0x02 ){ // lowより上なら
|
||
// DI();
|
||
vregs[ REG_INT_ADRS_IRQ ] &= ~0x30; // lowもemptyもなかったことに
|
||
// EI();
|
||
irq_hist &= ~0x03;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
/******************************************************************************
|
||
電池が判明/モード切替で閾値セット
|
||
******************************************************************************/
|
||
void set_batt_th(){
|
||
u8 *p_tbl;
|
||
u8 tmp;
|
||
|
||
if( with_NAND ){
|
||
if( vregs[ REG_INT_ADRS_BATT_INFO ] == BATT_CO ){ // Co (0b000)
|
||
p_tbl = &threshold_Co_NAND[0];
|
||
}else if( vregs[ REG_INT_ADRS_BATT_INFO ] == BATT_IS ){ // IS (0b011)
|
||
p_tbl = &threshold_IS_NAND[0];
|
||
}else{ // PSS (0b111)
|
||
p_tbl = &threshold_PSS_NAND[0];
|
||
}
|
||
}else{ // NAND 保護なし
|
||
if( vregs[ REG_INT_ADRS_BATT_INFO ] == BATT_CO ){
|
||
p_tbl = &threshold_Co[0];
|
||
}else if( vregs[ REG_INT_ADRS_BATT_INFO ] == BATT_IS ){
|
||
p_tbl = &threshold_IS[0];
|
||
IS_led_cam = 0; // 赤箱対応
|
||
IS_led_cam_mode = 0; // 赤箱対応
|
||
}else{
|
||
p_tbl = &threshold_PSS[0];
|
||
}
|
||
}
|
||
for( tmp = 0; tmp != 5; tmp++ ){
|
||
Vbatt_threshold[ tmp ] = 512 + adc_comp_val + *p_tbl;
|
||
p_tbl++;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
/******************************************************************************
|
||
VoffLの測定
|
||
|
||
4ms間隔で取り込み、必要なところの8この平均取ります。
|
||
____________________________
|
||
/RESET ______
|
||
---------_________|←30ms →|
|
||
VDET+ →+-----____
|
||
| \____
|
||
ADCサンプリング ***||||||||****
|
||
この辺 8個の平均とる
|
||
******************************************************************************/
|
||
void tsk_adc_calib(){
|
||
u8 adc_avg;
|
||
static u8 count_for_IS = 0;
|
||
static u8 state = 0;
|
||
static u8 adc_raw_data_B[8], adc_raw_data_A[4]; // 平均対象のB,対象外のA
|
||
static u16 adc_sum8 = 0;
|
||
static u8 adc_rec_val = 0;
|
||
static u8 count = 0;
|
||
|
||
switch( state ){
|
||
case( 0 ):
|
||
// 下準備
|
||
IIC0_Stop();
|
||
TMH0_Stop(); // pow_R
|
||
TMH1_Stop(); // pow_B
|
||
TM50_Stop(); // wifi
|
||
P1.7 = 1; // Y
|
||
P1.5 = 1; // R
|
||
P1.6 = 1; // B
|
||
CR51 = 125 - 1 ; // T = 4ms
|
||
iic2m_write_data( IIC_SLV_ADDR_PMIC, 0x02, (u8*)0x00 );
|
||
state = 1;
|
||
break;
|
||
case( 1 ):
|
||
// スリープ待ち。赤箱なら待たない
|
||
// if( vregs[ REG_INT_ADRS_BATT_INFO ] == BATT_IS ){
|
||
// state = 2;
|
||
// }else{
|
||
{
|
||
if( PM_SLP == 1 ){
|
||
P1.7 = 0; // Y
|
||
vregs[ REG_INT_ADRS_POWER_SAVE ] = 0x07;
|
||
PM_set_VRSET();
|
||
state = 2;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case( 2 ):
|
||
// vBatt_raw は補正されてない 素 の値です
|
||
// 値域がだいたい決まっているので、下8ビットしかみない。
|
||
// 余裕をみて 3.1~3.5Vでみても、567~640なので、512引いて、55~128でまだまだ余裕
|
||
// それ以上だったら取得失敗扱い(無視)
|
||
if( ( vBatt_raw > ( 512 + 0x60 ) ) || ( vBatt_raw < ( 512 + 0x40 ) ) ){
|
||
break;
|
||
}
|
||
// まず、計算対象のバッファ8個を埋める
|
||
adc_raw_data_B[ count ] = (u8)( vBatt_raw & 0x00FF ); // マスクしない。信じてる。
|
||
adc_sum8 += ( vBatt_raw & 0x00FF );
|
||
if( count == 7 ){ // 8回ためる
|
||
count = 0;
|
||
state = 3;
|
||
}else{
|
||
count++;
|
||
}
|
||
break;
|
||
|
||
case( 3 ):
|
||
// 次に、ディレイ用のバッファ4個を埋める
|
||
adc_raw_data_A[ count ] = (u8)( vBatt_raw & 0x00FF );
|
||
if( count == 3 ){ // 4回ためる
|
||
P1.6 = 0; // B
|
||
count = 0;
|
||
state = 4;
|
||
}else{
|
||
count++;
|
||
}
|
||
break;
|
||
|
||
default:
|
||
if( n_sys_reset != 0 ){ // リセットを見るのはどちらかというと誤書き込み防止
|
||
// 微妙タイミングなら、放電の方が早くてたぶん書き込み完了しない
|
||
|
||
adc_avg = (u8)( adc_sum8 / 8 );
|
||
// なんと、半端なシフトは割り算になる(25clk)シフト&調整より早いと言うことか。
|
||
// IS対応
|
||
if( vregs[ REG_INT_ADRS_BATT_INFO ] == BATT_IS ){
|
||
adc_avg -= ( 9 + 16 ); // キャリブレーションが1.8V @ ref = 3.3 を1.65Vに換算
|
||
if( flash_write( DAT_ADC_COMP, &adc_avg ) == 0 ){ // 目立たないけど、ここで書き込み
|
||
mcu_reset;
|
||
}
|
||
}
|
||
// 必要なら記録
|
||
if( adc_rec_val != adc_avg ){
|
||
if( flash_write( DAT_ADC_COMP, &adc_avg ) == 0 ){
|
||
P1.5 = 0; // R
|
||
P1.6 = 1; // B
|
||
adc_rec_val = adc_avg;
|
||
P1.6 = 0; // B
|
||
P1.5 = 1; // R
|
||
}
|
||
}
|
||
|
||
// リングバッファ等更新
|
||
if( ( vBatt_raw & 0x00FF ) < 128 ){
|
||
adc_sum8 -= adc_raw_data_B[ count ]; // 合計から古いのを引く
|
||
adc_raw_data_B[ count ] = adc_raw_data_A[ ( count & 0x03 ) ]; // プリバッファから補充
|
||
adc_sum8 += adc_raw_data_B[ count ]; // 合計に 新しいのを足す
|
||
adc_raw_data_A[ ( count & 0x03 ) ] = (u8)( vBatt_raw & 0x00FF ); // プリバッファを更新
|
||
// あんまりうれしくないかも..
|
||
count = ( count < 7 )? count + 1: 0; // 上手な書き方募集
|
||
}
|
||
}
|
||
}
|
||
ADC_Start();
|
||
}
|
||
|
||
|
||
|
||
//****************************************************************************
|
||
__interrupt void callbk_int_ad(){
|
||
EI();
|
||
vBatt_raw = ( ADCR >> 6 ); // 右につめておきます...なんで。
|
||
ADC_Stop();
|
||
}
|
||
|
||
|
||
|
||
//****************************************************************************
|
||
void ADC_Init(){
|
||
ADPC = PORT_ADPC_3DIO; // /IRQ_0 は親のほうがプルアップしてる
|
||
ADM = 0x90; // fAD = fPRS/6, wait:2~13ClkSys
|
||
ADS = 0x03;
|
||
}
|
||
|
||
|
||
|
||
void ADC_Start(){
|
||
ADM.0 = 1; // ADCE
|
||
NOP(); // 1usあけなきゃいけないっす
|
||
NOP(); // nop : 2clkです。
|
||
NOP();
|
||
NOP();
|
||
ADM.7 = 1; // ADCS
|
||
MK1L.0 = 0; // ADC割り込みマスク
|
||
}
|
||
|
||
|
||
|
||
void ADC_Stop(){
|
||
MK1L.0 = 1; // ADMK = 1;
|
||
ADM.7 = 0; // ADCS
|
||
ADM.0 = 0; // ADCE
|
||
}
|
||
|