ctr_mcu/trunk/adc.c
N2232 3da96fcad8 0.23
VolをTWLからも書けるように
 スライダとの後着優先になる
Codecの「書いたVolと違う値にセットされる(MAX?)」バグワークアラウンドのため、ポーリングするように再度変更
 TWLからも書けるのと併せ、そのつもりで作っていたかったので修正箇所が多い
スライダのレジスタの値を読み出されるのでスライダのアソビを考えてスケーリングするよう変更
 テーブル引きのテーブルをいじるのでは対応出来ない
ADCのフィルタの誤り。閾値付近でふらふらしてしまっていた。フィルタの意味なし
電池残量0時のデフォルトパターンを設定。
 ほぼすっからかんな電池をセットされたときなどでSoCから何も書かれてない状態の時、消灯で不便なため
電源LED autoでホタルにしない用にした。
 ホタル消そうか…
ファームが壊れ、バックアップからも復帰できないときに赤LEDを ぴぴっ、ぴぴっ と点滅させるように変更
 ファームバックアップ後、新ファーム書き込み中のある期間で電源を落とすとバックアップが消える?
 todo:デバッグコードが残っている
MGICにバッテリーパラメータを書くタイミングを変更(パラメータ転送~に時間が掛かるため)
 1)電池交換を検出したとき
 2)電源を入れようとしたときに万が一電池がすり替わってたとき
電圧で電池残量をキャップする
 分解能20mVではあまりよろしい結果が得られなかったのでMGICより下位バイトも取得するように変更
 比較部をリファクタリング
wait_msを違うモジュールに
 ROM上のbootブロックに置きたかったため
Vol更新コマンド ビットの自動クリアを忘れていた
バッテリ残量パラメータ更新
 ビットシフトが必要になったので対応 残念なコードに
電源LED赤とカメラLEDがひっくり返っていた
VOLテーブルを-10dbに更新


git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-05-23%20-%20ctr.7z%20+%20svn_v1.068.zip/ctr/svn/ctr_mcu@200 013db118-44a6-b54f-8bf7-843cb86687b1
2010-07-06 09:01:09 +00:00

547 lines
13 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.

/* ========================================================
藤田@開技
nintendo
'09 Apr
======================================================== */
#include "incs.h"
#include "adc.h"
#include "pm.h"
#include "led.h"
//#define _4db_
//#define _15db_
#define _10db_
#include "voltable.h"
// ===================================================== //
bit adc_updated;
u8 adc_raw_vol;
u8 adc_raw_dep;
u8 vol_written_ctr;
bit vol_by_twl;
typedef struct filter_work
{
u8* value_used;
s8 diffs; // KIKAN中の偏り具合
s8 kikan;
}filter_work;
filter_work work_vr_3d = {
&vreg_ctr[ VREG_C_TUNE ]
};
u8 vol_data_ctr;
u8 vol_data_ctr_tmp;
filter_work work_vr_vol = {
&vol_data_ctr_tmp
};
// ===================================================== //
extern void nop8();
static void adc_filter( u8 new_val, filter_work* work );
static u8 adc_scaling( u8 );
// ===================================================== //
#define INTERVAL_TSK_ADC 15
/* ========================================================
ADC設定と、開始
以下のピンは主にここで操作・監視されます。
・BT_TEMP,_P
・ADIN1
・VOL
関係ありそうですが別のところで管理しています
・PM_BT_DET,_P BT_init
・8tics毎に呼ばれ、チャンネル分取り込むとADCを停止します。
 タスク起動時、レジスタには前回の取り込み値が入っています。
======================================================== */
void tsk_adc( )
{
static u8 task_interval = 0;
static u8 old_tune;
static u8 sndvol_codec;
static u8 bt_temp_old;
#if 0
// debug
{
static u16 loop;
static u8 dat_old;
static bit interval;
/*
// VOL書き頻度を半分にする
interval++;
if( !interval )
{
return;
}
*/
if( system_status.pwr_state == ON )
{
loop++;
if( loop == 499 ){
// vol_written_ctr = 0;
}
else if( loop == 500 ){
vol_written_ctr = 0;
loop = 0;
}
else
{
vol_written_ctr = slider_to_codec[ vol_data_ctr ];
}
}
renge_task_immed_add( tski_vol_update );
}
//*/
#endif
renge_task_immed_add( tski_vol_update ); // T = 2ms polling
if( task_interval-- != 0 )
{
return;
}
else
{
task_interval = (u8)( INTERVAL_TSK_ADC / SYS_INTERVAL_TICK );
}
if( adc_updated )
{
adc_updated = 0;
if( system_status.pwr_state == ON )
{
// 3D /////////////////////////////////////////
adc_filter( adc_scaling( adc_raw_dep ), &work_vr_3d );
// Volume /////////////////////////////////////
{
static u8 vol_old;
adc_filter( adc_scaling( adc_raw_vol ), &work_vr_vol ); // 結果は*work_vr_volから指されるvol_data_ctr 読みにくい...
vol_data_ctr = vol_data_ctr_tmp / 4;
if(( vreg_ctr[ VREG_C_VOL_DIGITAL ] & REG_BIT_VOL_FORCE_REG ) != 0 )
{
// レジスタから強制セット
vol_data_ctr = ( vreg_ctr[ VREG_C_VOL_DIGITAL ] & ~( REG_BIT_VOL_RESET | REG_BIT_VOL_FORCE_REG ) );
}
if( vol_old != vol_data_ctr )
{
vol_old = vol_data_ctr;
vol_by_twl = 0;
vreg_ctr[ VREG_C_SND_VOL ] = vol_data_ctr; // 64段
vol_written_ctr = slider_to_codec[ vol_data_ctr ];
vreg_twl[ REG_TWL_INT_ADRS_VOL ] = vol_data_ctr / 2;
// renge_task_immed_add( tski_vol_update ); 2ms後でいいでしょう...
}
}
// バッテリ識別 ///////////////////////////
/* 呼ばれません */
}
}
ADCEN = 1;
ADM = 0b00001011; // セレクトモード、昇圧、fCLK/6 ///ここから ↓
ADPC = 0x06; // ADCポートのセレクト
ADS = ADC_SEL_TUNE;
nop8();
ADCS = 1; // AD開始。 /// ここまで  までに1us=8clk以上開ける
ADIF = 0;
ADMK = 0;
}
/* ========================================================
 Volを更新します。
 こんな時に登録されます。
  ・ユーザーがVolスライダを動かした
  ・Horizonに強制更新を指示された codecリセット時
  ・TWLアプリがVolをいじった
======================================================== */
task_status_immed tski_vol_update()
{
u8 vol_scaled;
u8 temp;
u8 i;
// SPIでかくテスト todo
// return( ERR_FINISED );
if( vol_by_twl )
{
temp = slider_to_codec[ vreg_twl[ REG_TWL_INT_ADRS_VOL ] * 2 ];
}
else
{
temp = vol_written_ctr;
}
// debug todo
iic_mcu_read_a_byte( IIC_SLA_CODEC, CODEC_REG_VOL );
// codecに伝える
iic_mcu_write_a_byte( IIC_SLA_CODEC, CODEC_REG_VOL, temp );
// debug todo
iic_mcu_read_a_byte( IIC_SLA_CODEC, CODEC_REG_VOL );
#ifndef _MODEL_CTR_
iic_mcu_write_a_byte( IIC_SLA_DCP, 0, slider_to_codec[ ( 255 - vol_data ) / 4 ] );
#endif
// set_irq( VREG_C_IRQ0, REG_BIT_VR_SNDVOL_CHANGE ); // 割り込み廃止
return( ERR_FINISED );
}
/* ========================================================
 過去つのminでもMAXでもない値を返す
 突発的なノイズを除く。
 運が悪いと振動するよ
======================================================== */
static u8 getmean3( u8 * hist )
{
if( *hist > *( hist + 1 ) )
{
if( *hist > *( hist + 2 ) )
{
return( ( *( hist + 1 ) > *( hist + 2 ) ) ? *( hist + 1 ) : *( hist + 2 ) );
}
else
{
return( *hist );
}
}else{
if( *hist > *( hist + 2 ) )
{
return( *hist );
}
else
{
return( ( *( hist + 1 ) < *( hist + 2 ) ) ? *( hist + 1 ) : *( hist + 2 ) );
}
}
}
/* ========================================================
 自前で次のチャンネル
  一通り終わったら止める
======================================================== */
__interrupt void int_adc( )
{
static u8 hist_tune[3];
static u8 hist_snd_vol[3];
static u8 hist_bt_temp[3];
static u8 index;
volatile u8 adc_data;
adc_data = ADCRH;
switch ( ADS )
{
/*
case ( ADC_SEL_AMB_BRIT ): // 環境明るさ
vreg_ctr[ VREG_C_AMBIENT_BRIGHTNESS ] = adc_data;
break;
*/
case ( ADC_SEL_TUNE ):
EI();
#ifdef _MODEL_WM0_
adc_raw_dep = 255 - adc_data;
#else
adc_raw_dep = adc_data;
#endif
break;
case ( ADC_SEL_VOL ):
EI();
#ifdef _MODEL_CTR_
if( system_status.model == MODEL_TS_BOARD )
{
adc_raw_vol = adc_data;
}
else
{
adc_raw_vol = 255 - adc_data;
}
#else
adc_raw_vol = adc_data;
#endif
break;
case ( ADC_SEL_BATT_TEMP ):
EI();
raw_adc_temperature = adc_data;
#ifdef _DEBUG_BT_TEMP_
if( vreg_ctr[ VREG_C_COMMAND3 ] == 't' )
{
raw_adc_temperature = vreg_ctr[ VREG_C_DBG01 ];
}
#endif
if( (( vreg_ctr[ VREG_C_STATUS_1 ] & REG_BIT_GASGAUGE_ERR ) == 0 ) &&
(( system_status.pwr_state == ON ) ||
( system_status.pwr_state == SLEEP )
)
)
{
renge_task_immed_add( tski_BT_temp_update );
}
break;
/* 呼ばれません
case ( ADC_SEL_BATT_DET ):
break;
*/
}
// もっとまともな書き方がありそうだ
if( ADS < ADC_SEL_BATT_DET )
{
ADS += 1; // 次のチャンネル
ADIF = 0; // ←これをしないと、いっこ前のチャンネルのデータの完了で直後に割り込む可能性がある
}
else
{
ADCEN = 0; // 止めてしまう
adc_updated = 1;
index = ( index == 2 ) ? 0 : ( index + 1 ); // ノイズ取りの配列インデックス
}
}
/* ========================================================
tsk_adcと競合することを考慮していません。
======================================================== */
u8 get_adc( u8 ch )
{
u8 temp;
ADMK = 1;
ADIF = 0;
ADCEN = 1;
ADM = 0b00001011; // セレクトモード、昇圧、fCLK/6 ///ここから↓
ADPC = 0x06; // ADCポートのセレクト
ADS = ch;
nop8();
ADCS = 1; // AD開始。 /// ここまで↑ に、1us以上開ける
ADIF = 0;
while( ADIF == 0 ){;}
temp = ADCRH;
ADCEN = 0;
ADMK = 0;
return ( temp );
}
/* ========================================================
VRの可動範囲を考えてスケーリング
======================================================== */
#define ASOBI 10
static u8 adc_scaling( u8 orig_val )
{
u16 temp;
if( orig_val > ( 255 - ASOBI ))
{
return( 255 );
}
if( orig_val <= ASOBI )
{
return( 0 );
}
orig_val -= ASOBI;
temp = (u16)( orig_val * 256 ) / ( 256 - ( 2 * ASOBI ));
return( (u8)( temp & 0xFF ) );
}
/* ========================================================
似非ヒステリシス V2
四捨五入的な動きします
======================================================== */
#define KIKAN 16
static void adc_filter( u8 new_val, filter_work *work )
{
u8 temp;
if( abs( new_val - *( work -> value_used )) > 2 )
{
// 大きく離れた
*( work -> value_used ) = new_val;
work -> diffs = 0;
work -> kikan = KIKAN;
}
else
{
// 近所の値でも、ある期間でいっぱい偏っていたらそっちに寄せる
if( *( work -> value_used ) < new_val )
{
work -> diffs += 1;
}
else if( *( work -> value_used ) > new_val )
{
work -> diffs -= 1;
}
if( --( work -> kikan ) == 0 )
{
if( ( work -> diffs ) == KIKAN )
// if( ( work -> diffs ) > (s8)( KIKAN * 0.8 ) )
{
*( work -> value_used ) = *( work -> value_used ) + 1;
}
else if( ( work -> diffs ) == ( -1 * KIKAN ) )
// else if( ( work -> diffs ) < (s8)( -1 * KIKAN * 0.8 ) )
{
*( work -> value_used ) = *( work -> value_used ) - 1;
}
work -> diffs = 0;
work -> kikan = KIKAN;
}
}
}
#if 0
// getmean使用 //
__interrupt void int_adc( )
{
static u8 hist_tune[3];
static u8 hist_snd_vol[3];
static u8 hist_bt_temp[3];
static u8 index;
volatile u8 adc_data;
adc_data = ADCRH;
switch ( ADS )
{
/*
case ( ADC_SEL_AMB_BRIT ): // 環境明るさ
vreg_ctr[ VREG_C_AMBIENT_BRIGHTNESS ] = adc_data;
break;
*/
case ( ADC_SEL_TUNE ):
hist_tune[index] = adc_data;
EI();
#ifdef _MODEL_WM0_
adc_raw_dep = 255 - getmean3( hist_tune );
#else
adc_raw_dep = getmean3( hist_tune );
#endif
break;
case ( ADC_SEL_VOL ):
hist_snd_vol[index] = adc_data;
EI();
#ifdef _MODEL_CTR_
if( system_status.model == MODEL_TS_BOARD )
{
adc_raw_vol = getmean3( hist_snd_vol );
}
else
{
adc_raw_vol = ( 255 - getmean3( hist_snd_vol ));
}
#else
adc_raw_vol = getmean3( hist_snd_vol );
#endif
break;
case ( ADC_SEL_BATT_TEMP ):
hist_bt_temp[index] = adc_data;
EI();
raw_adc_temperature = getmean3( hist_bt_temp );
if( (( vreg_ctr[ VREG_C_STATUS_1 ] & REG_BIT_GASGAUGE_ERR ) == 0 ) &&
(( system_status.pwr_state == ON ) ||
( system_status.pwr_state == SLEEP )
)
)
{
renge_task_immed_add( tski_BT_temp_update );
}
break;
/* 呼ばれません
case ( ADC_SEL_BATT_DET ):
break;
*/
}
// もっとまともな書き方がありそうだ
if( ADS < ADC_SEL_BATT_DET )
{
ADS += 1; // 次のチャンネル
ADIF = 0; // ←これをしないと、いっこ前のチャンネルのデータの完了で直後に割り込む可能性がある
}
else
{
ADCEN = 0; // 止めてしまう
adc_updated = 1;
index = ( index == 2 ) ? 0 : ( index + 1 ); // ノイズ取りの配列インデックス
}
}
#endif