/* ======================================================== 藤田@開技 nintendo '09 Apr ======================================================== */ #include "incs.h" #include "adc.h" #include "pm.h" #include "led.h" //#define _4db_ #define _15db_ // ===================================================== // bit adc_updated; u8 adc_raw_vol; u8 adc_raw_dep; // ===================================================== // extern void nop8(); // ===================================================== // #define INTERVAL_TSK_ADC 15 /* ======================================================== ADC設定と、開始 以下のピンは主にここで操作・監視されます。 ・BT_TEMP,_P ・ADIN1 ・VOL 関係ありそうですが別のところで管理しています ・PM_BT_DET,_P BT_init ・8tics毎に呼ばれ、3チャンネル分取り込むとADCを停止します。  タスク起動時、レジスタには前回の取り込み値が入っています。 ======================================================== */ #ifdef _15db_ // max -15db const u8 slider_to_codec[64] = { 127, 127, 127, 126, 125, 124, 123, 122, 121, 120, 119, 118, 117, 116, 115, 114, 113, 112, 111, 110, 109, 108, 107, 106, 105, 104, 103, 102, 101, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66 }; #endif #ifdef _4db_ // max -4db const u8 slider_to_codec[64] = { 127, 127, 126, 125, 123, 122, 121, 119, 118, 117, 115, 114, 112, 111, 110, 108, 107, 106, 104, 103, 101, 100, 99, 97, 96, 94, 93, 92, 90, 89, 88, 86, 85, 83, 82, 81, 79, 78, 77, 75, 74, 72, 71, 70, 68, 67, 66, 64, 64, 63, 61, 60, 59, 57, 56, 54, 53, 52, 50, 49, 48, 46, 44, 44 }; #endif void tsk_adc( ) { static u8 task_interval = 0; static u8 old_tune; static u8 sndvol_codec; static u8 bt_temp_old; 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 ///////////////////////////////////////// { // 似非ヒステリシス V2 // ガリオームには適さない #define KIKAN 32 static u8 old_value; static s8 diffs; u8 temp; if( abs( adc_raw_dep - old_value ) >= 2 ) { // 大きく離れた vreg_ctr[ VREG_C_TUNE ] = adc_raw_dep; old_value = adc_raw_dep; #if 0 割り込み入れない; 割り込みを入れるようであれば、ちゃんと変化チェックする; set_irq( VREG_C_IRQ0, REG_BIT_VR_TUNE_CHANGE ); #endif diffs = 0; } else { // 近所の値でも、ある期間でいっぱい偏っていたらそっちに寄せる static u8 kikan_count = KIKAN; if( old_value < adc_raw_dep ) { diffs += 1; } else if( old_value > adc_raw_dep ) { diffs -= 1; } if( --kikan_count == 0 ) { if( diffs >= KIKAN && ( diffs < 64 )) { old_value += 1; } else if( ( diffs <= ( 256 - KIKAN )) && ( diffs > ( 128 + 64 ) )) // あらー? { old_value -= 1; } vreg_ctr[ VREG_C_TUNE ] = old_value; kikan_count = KIKAN; diffs = 0; } } } // Volume ///////////////////////////////////// { static u8 vol_old; static u8 force_update_vol; if(( vreg_ctr[ VREG_C_VOL_DIGITAL ] & 0x80 ) != 0 ) { // レジスタから強制セット adc_raw_vol = ( vreg_ctr[ VREG_C_VOL_DIGITAL ] * 4 ); } if( ( abs( adc_raw_vol - vol_old ) >= 2 ) // 生値でこれくらいずれたら更新(似非ヒステリシス) || ( --force_update_vol == 0 ) ) // ポーリング { vol_old = adc_raw_vol; // レジスタ更新 vreg_twl[ REG_TWL_INT_ADRS_VOL ] = vol_old / ( 256 / 32 ); // ←adc値でよい vreg_ctr[ VREG_C_SND_VOL ] = ( vol_old / 4 ); // 64段 // codecに伝える iic_mcu_write_a_byte( IIC_SLA_CODEC, CODEC_REG_VOL, slider_to_codec[ vol_old / 4 ] ); #ifndef _MODEL_CTR_ iic_mcu_write_a_byte( IIC_SLA_DCP, 0, slider_to_codec[ ( 255 - vol_old ) / 4 ] ); #endif // set_irq( VREG_C_IRQ0, REG_BIT_VR_SNDVOL_CHANGE ); // 割り込み廃止 force_update_vol = 10; } } } } ADCEN = 1; ADM = 0b00001011; // セレクトモード、昇圧、fCLK/6 ///ここから ↓ ADPC = 0x06; // ADCポートのセレクト ADS = ADC_SEL_TUNE; nop8(); ADCS = 1; // AD開始。 /// ここまで ↑ までに1us=8clk以上開ける ADIF = 0; ADMK = 0; } /* ========================================================  過去3つの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; // EI( ); switch ( ADS ) { /* case ( ADC_SEL_AMB_BRIT ): // 環境明るさ vreg_ctr[ VREG_C_AMBIENT_BRIGHTNESS ] = ADCRH; break; */ case ( ADC_SEL_TUNE ): hist_tune[index] = ADCRH; #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] = ADCRH; #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 if( adc_raw_vol == 0 ) { NOP(); } break; case ( ADC_SEL_BATT_TEMP ): hist_bt_temp[index] = ADCRH; raw_adc_temperature = getmean3( hist_bt_temp ); renge_task_immed_add( BT_temp_update ); break; case ( ADC_SEL_BATT_DET ): // 呼ばれない break; } // もっとまともな書き方がありそうだ // if( ADS == ADC_SEL_BATT_DET ){ if( ADS != ADC_SEL_BATT_TEMP ) { // 電池判別は電源投入の一回のみ 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以上開ける while( ADIF == 0 ){;} temp = ADCRH; ADCEN = 0; ADMK = 0; return ( temp ); }