twl_mcu/ADC.c
2024-12-17 04:24:29 -05:00

464 lines
14 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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.13.5Vでみても、567640なので、512引いて、55128でまだまだ余裕
// それ以上だったら取得失敗扱い(無視)
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:213ClkSys
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
}