mirror of
https://github.com/rvtr/ctr_mcu.git
synced 2025-06-18 16:45:33 -04:00
476 lines
11 KiB
C
476 lines
11 KiB
C
/* ========================================================
|
||
adc.c
|
||
|
||
藤田@開技
|
||
nintendo
|
||
'09 Apr
|
||
$Id$
|
||
======================================================== */
|
||
#include "incs.h"
|
||
#include "adc.h"
|
||
#include "pm.h"
|
||
|
||
#include "led.h"
|
||
|
||
#include "vreg_twl.h"
|
||
#include "i2c_mcu.h"
|
||
|
||
|
||
// ===================================================== //
|
||
static bit adc_updated;
|
||
static bit vol_changed_by_ctr;
|
||
bit vol_changed_by_twl;
|
||
static u8 vol_old;
|
||
|
||
static u8 adc_raw_vol;
|
||
static u8 adc_raw_dep;
|
||
|
||
u8 vol_polling;
|
||
u8 vol_level_twl;
|
||
|
||
extern const u8 slider_to_codec[];
|
||
|
||
|
||
|
||
// ===================================================== //
|
||
typedef struct filter_work
|
||
{
|
||
u8* value_used;
|
||
s8 diffs; // KIKAN中の偏り具合
|
||
s8 kikan;
|
||
u8 large_diff_count;
|
||
}filter_work;
|
||
|
||
|
||
static filter_work work_vr_3d = {
|
||
&vreg_ctr[ VREG_C_3D ]
|
||
// のこりは不定値でよし。constにしちゃダメ
|
||
};
|
||
|
||
|
||
static u8 vol_data_ctr;
|
||
static u8 vol_data_ctr_tmp;
|
||
static filter_work work_vr_vol = {
|
||
&vol_data_ctr_tmp
|
||
// のこりは不定値でよし。constにしちゃダメ
|
||
};
|
||
|
||
|
||
// twl の8段階volのリニア値からの境界
|
||
/*
|
||
twl内の32 -> 8 テーブル
|
||
0~1,~4,~8,~13,~18,~23,~28,31
|
||
*/
|
||
static const u8 TWL_VOL_BOUNDARY[] = {
|
||
1, 4, 8, 13, 18, 23, 28, 31
|
||
};
|
||
|
||
// ===================================================== //
|
||
extern void nop8();
|
||
static void adc_filter( u8 new_val, filter_work* work );
|
||
static u8 adc_scaling( u8 );
|
||
static void update_twl_vol( u8 sent_index );
|
||
|
||
|
||
|
||
// ===================================================== //
|
||
#define INTERVAL_TSK_ADC 15
|
||
|
||
|
||
|
||
/********************************************//**
|
||
ADC設定と、開始
|
||
|
||
以下のピンは主にここで操作・監視されます。
|
||
- BT_TEMP,_P
|
||
- ADIN1
|
||
- VOL
|
||
|
||
***********************************************/
|
||
void tsk_adc( )
|
||
{
|
||
if( adc_updated )
|
||
{
|
||
adc_updated = false;
|
||
|
||
// 3D /////////////////////////////////////////
|
||
vreg_ctr[ VREG_C_3D ] = adc_raw_dep; // 生値
|
||
|
||
// Volume /////////////////////////////////////
|
||
{
|
||
vreg_ctr[ VREG_C_VOL_ADC_RAW ] = adc_raw_vol;
|
||
|
||
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( vol_old != vol_data_ctr )
|
||
{
|
||
vol_changed_by_ctr = true;
|
||
vol_old = vol_data_ctr;
|
||
vol_polling = 3;
|
||
// renge_task_immed_add( tski_vol_update ); ↓で登録
|
||
}
|
||
}
|
||
|
||
// バッテリ識別 ///////////////////////////
|
||
/* 呼ばれません */
|
||
}
|
||
|
||
// 書き忘れがあるといやなのでポーリング orz
|
||
if( vol_polling < 5 )
|
||
{
|
||
renge_task_immed_add( tski_vol_update );
|
||
vol_polling = (u8)(200 / SYS_INTERVAL_TICK) + 5; // 5回/sec
|
||
}
|
||
vol_polling --;
|
||
|
||
|
||
ADCEN = 1;
|
||
ADM = bits8(0,0,0,0, 1,0,1,1); // セレクトモード、昇圧、fCLK/6 // ここから ↓
|
||
|
||
ADPC = 0x06; // ADCポートのセレクト
|
||
ADS = ADC_SEL_3D;
|
||
nop8();
|
||
ADCS = 1; // AD開始。 // ここまで ↑ までに1us=8clk以上開ける
|
||
|
||
ADIF = 0;
|
||
ADMK = 0;
|
||
}
|
||
|
||
|
||
|
||
/********************************************//**
|
||
volを現在のスライダの位置に強制更新
|
||
***********************************************/
|
||
void vol_reset()
|
||
{
|
||
vol_old = vol_data_ctr;
|
||
vreg_ctr[ VREG_C_SND_VOL ] = vol_data_ctr; // 64段
|
||
}
|
||
|
||
|
||
/********************************************//**
|
||
Volを更新します。
|
||
|
||
こんな時に登録されます。
|
||
|
||
- ユーザーがVolスライダを動かした
|
||
- Horizonに強制更新を指示された (codecリセット時)
|
||
- TWLアプリがVolをいじった
|
||
***********************************************/
|
||
task_status_immed tski_vol_update()
|
||
{
|
||
static u8 sent_index, sent_index_twl;
|
||
static bit last_modifyer_is_twl; // false = ctr
|
||
|
||
if( !( system_status.pwr_state == ON ) ||
|
||
( system_status.pwr_state == SLEEP )){
|
||
return( TSKI_FINISHED );
|
||
}
|
||
|
||
// どの音量にするの? //
|
||
if( vol_changed_by_ctr )
|
||
{
|
||
// スライダ
|
||
vol_changed_by_ctr = false;
|
||
last_modifyer_is_twl = false;
|
||
sent_index = vol_data_ctr;
|
||
}
|
||
else if( vol_changed_by_twl )
|
||
{
|
||
// TWLアプリ
|
||
vol_changed_by_twl = false;
|
||
last_modifyer_is_twl = true;
|
||
if( vreg_twl[ REG_TWL_INT_ADRS_VOL ] == 0 )
|
||
{
|
||
sent_index_twl = 0;
|
||
}
|
||
else
|
||
{
|
||
sent_index_twl = vreg_twl[ REG_TWL_INT_ADRS_VOL ] *2 +1;
|
||
}
|
||
sent_index = sent_index_twl;
|
||
}
|
||
else
|
||
{
|
||
// force_sliderを0にしたとき & 書きまくるとき
|
||
// スライダかTWLの最後にセットした方をセット
|
||
if( last_modifyer_is_twl )
|
||
{
|
||
sent_index = sent_index_twl;
|
||
}
|
||
else
|
||
{
|
||
sent_index = vol_data_ctr;
|
||
}
|
||
}
|
||
|
||
// レジスタの更新 //
|
||
vreg_ctr[ VREG_C_SND_VOL ] = sent_index;
|
||
|
||
// twl側更新
|
||
update_twl_vol( sent_index );
|
||
|
||
// codecに伝える
|
||
/// 同値でも書く
|
||
iic_mcu_write_a_byte_codec( CODEC_REG_VOL, slider_to_codec[ sent_index ] );
|
||
|
||
// set_irq( VREG_C_IRQ0, REG_BIT_VR_SNDVOL_CHANGE ); // 割り込み廃止
|
||
return( TSKI_FINISHED );
|
||
}
|
||
|
||
|
||
/********************************************//**
|
||
TWL へ音量を通知する。
|
||
|
||
段階数が違うので、そこのケアも行う
|
||
***********************************************/
|
||
static void update_twl_vol( u8 sent_index )
|
||
{
|
||
// スケーリング
|
||
if( sent_index == 0 )
|
||
{
|
||
vreg_twl[ REG_TWL_INT_ADRS_VOL ] = 0;
|
||
}
|
||
else if( sent_index <= 4 )
|
||
{
|
||
vreg_twl[ REG_TWL_INT_ADRS_VOL ] = 2; // 1はミッシングで正解
|
||
}
|
||
else
|
||
{
|
||
vreg_twl[ REG_TWL_INT_ADRS_VOL ] = sent_index/2 ;
|
||
}
|
||
|
||
// 8段階のレベル化。 割り込みを入れるのに必要
|
||
{
|
||
static u8 vol_twl_old;
|
||
|
||
if( vol_twl_old != vreg_twl[ REG_TWL_INT_ADRS_VOL ] )
|
||
{
|
||
// 8段レベルに変換
|
||
u8 new_level = 31;
|
||
u8 i;
|
||
|
||
vol_twl_old = vreg_twl[ REG_TWL_INT_ADRS_VOL ];
|
||
|
||
for( i=0; i<=7; i++ )
|
||
{
|
||
if( vreg_twl[ REG_TWL_INT_ADRS_VOL ] <= TWL_VOL_BOUNDARY[ i ] )
|
||
{
|
||
new_level = i;
|
||
break;
|
||
}
|
||
}
|
||
vol_level_twl = new_level;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
/********************************************//**
|
||
ADC isr
|
||
|
||
マルチプレクサの状態をチェックしてしかるべき所へ転送、
|
||
|
||
自前で次のチャンネルを起動する
|
||
|
||
一通り終わったら止める
|
||
***********************************************/
|
||
__interrupt void int_adc( )
|
||
{
|
||
volatile u8 adc_data = ADCRH;
|
||
|
||
switch ( ADS )
|
||
{
|
||
/*
|
||
case ( ADC_SEL_AMB_BRIT ):
|
||
// 環境明るさ //
|
||
vreg_ctr[ VREG_C_AMBIENT_BRIGHTNESS ] = adc_data;
|
||
break;
|
||
*/
|
||
|
||
case ( ADC_SEL_3D ):
|
||
// 3Dボリューム //
|
||
EI();
|
||
adc_raw_dep = adc_data;
|
||
break;
|
||
|
||
case ( ADC_SEL_VOL ):
|
||
// 音量スライダ //
|
||
EI();
|
||
if( system_status.model == MODEL_TS_BOARD )
|
||
{
|
||
adc_raw_vol = adc_data;
|
||
}
|
||
else
|
||
{
|
||
adc_raw_vol = 255 - adc_data;
|
||
}
|
||
|
||
break;
|
||
|
||
case ( ADC_SEL_BATT_TEMP ):
|
||
// バッテリ温度 //
|
||
EI();
|
||
#ifdef _ENABLE_HAL_
|
||
if( vreg_ctr[ VREG_C_HAL_OVW_TEMPERATURE ] == 0xFF ) // HAL無効
|
||
#else
|
||
if( 1 )
|
||
#endif
|
||
{
|
||
raw_adc_temperature = adc_data;
|
||
}
|
||
else
|
||
{
|
||
raw_adc_temperature = vreg_ctr[ VREG_C_HAL_OVW_TEMPERATURE ];
|
||
}
|
||
|
||
if(// (( vreg_ctr[ VREG_C_STATUS_1 ] & REG_BIT_MGIC_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; // 次のチャンネル
|
||
}
|
||
else
|
||
{
|
||
ADCEN = 0; // 止めてしまう
|
||
adc_updated = true;
|
||
}
|
||
ADIF = 0; // ←これをしないと、いっこ前のチャンネルのデータの完了で直後に割り込む可能性がある
|
||
}
|
||
|
||
|
||
|
||
/********************************************//**
|
||
adcレジスタから読み出し、そのまま返値にする。
|
||
|
||
tsk_adcと競合することを考慮していません。
|
||
***********************************************/
|
||
u8 get_adc( u8 ch )
|
||
{
|
||
u8 temp;
|
||
|
||
ADMK = 1;
|
||
ADIF = 0;
|
||
|
||
ADCEN = 1;
|
||
ADM = bits8(0,0,0,0, 1,0,1,1); // セレクトモード、昇圧、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の可動範囲を考えてスケーリング
|
||
|
||
音量Vol専用 使い回すならそのときどうにかする
|
||
***********************************************/
|
||
static u8 adc_scaling( u8 orig_val )
|
||
{
|
||
u16 temp;
|
||
|
||
if( orig_val <= vreg_ctr[ VREG_C_VOL_CAL_MIN ] )
|
||
{
|
||
return( 0 );
|
||
}
|
||
if( orig_val >= vreg_ctr[ VREG_C_VOL_CAL_MAX ] )
|
||
{
|
||
return( 255 );
|
||
}
|
||
|
||
temp = (u16)(( orig_val - vreg_ctr[ VREG_C_VOL_CAL_MIN ] ) * 256 ) / ( vreg_ctr[ VREG_C_VOL_CAL_MAX ] - vreg_ctr[ VREG_C_VOL_CAL_MIN ] );
|
||
if( temp > 255 )
|
||
{
|
||
temp = 255;
|
||
}
|
||
|
||
return( (u8)( temp & 0xFF ) );
|
||
}
|
||
|
||
|
||
|
||
|
||
/********************************************//**
|
||
似非ヒステリシス V2
|
||
|
||
四捨五入的な動きします
|
||
***********************************************/
|
||
#define KIKAN 16
|
||
static void adc_filter( u8 new_val, filter_work *work )
|
||
{
|
||
if( abs( new_val - *( work -> value_used )) > 2 )
|
||
{
|
||
// 大きく離れた
|
||
work -> large_diff_count ++;
|
||
if( work -> large_diff_count > 16 )
|
||
{
|
||
*( work -> value_used ) = new_val;
|
||
work -> diffs = 0;
|
||
work -> kikan = KIKAN;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
work -> large_diff_count = 0;
|
||
// 近所の値でも、ある期間でいっぱい偏っていたらそっちに寄せる
|
||
if( *( work -> value_used ) < new_val )
|
||
{
|
||
work -> diffs ++;
|
||
}
|
||
else if( *( work -> value_used ) > new_val )
|
||
{
|
||
work -> diffs --;
|
||
}
|
||
|
||
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;
|
||
}
|
||
}
|
||
}
|
||
|