/* ======================================================== 藤田@開技 nintendo '09 Apr ======================================================== */ #include "incs.h" #include "adc.h" #include "pm.h" #include "led.h" bit adc_updated; #define INTERVAL_TSK_ADC 16 /* ======================================================== ADC設定と、開始 以下のピンは主にここで操作・監視されます。 ・BT_TEMP,_P ・ADIN1 ・VOL 関係ありそうですが別のところで管理しています ・PM_BT_DET,_P PM_init ・8tics毎に呼ばれ、3チャンネル分取り込むとADCを停止します。  タスク起動時、レジスタには前回の取り込み値が入っています。 ======================================================== */ 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 ) { if( system_status.pwr_state == ON ) { // Tune // #if 0 tune ・フ変化では割り込みを入れない // tune if( abs( old_tune - vreg_ctr[VREG_TUNE] ) >= 4 ) { old_tune = vreg_ctr[VREG_TUNE]; vreg_ctr[VREG_C_IRQ0] |= REG_BIT_VR_TUNE_CHANGE; if( ( vreg_ctr[VREG_C_IRQ_MASK0] & REG_BIT_VR_TUNE_CHANGE ) == 0 ) { IRQ0_ast; } } #endif // Volume // { static u8 vol_old; static u8 class_old; u8 class; static u8 tokidoki = 0; // todo ポーリングは不要になる予定 if( abs( vol_old - vreg_ctr[VREG_C_SND_VOL] ) > 3 ) { vol_old = vreg_ctr[VREG_C_SND_VOL]; // TWLに通知してやる vreg_twl[ REG_TWL_INT_ADRS_VOL ] = vol_old / ( 256 / 32 ); // 割り込みはHorizonを通してコマンドを発行されるのを待てばよい class = vreg_ctr[VREG_C_SND_VOL] / ( 256 / 8 ); if( class != class_old ) { class_old = class; set_irq( VREG_C_IRQ0, REG_BIT_VR_SNDVOL_CHANGE ); } } // デバイスに伝える if(( sndvol_codec != vreg_ctr[VREG_C_SND_VOL] ) || ( tokidoki == 0 )) { sndvol_codec = vreg_ctr[VREG_C_SND_VOL]; // DCPにも伝えておく iic_mcu_write_a_byte( IIC_SLA_DCP, 0, sndvol_codec / 2 + sndvol_codec / 4 ); // 簡易スケーリング todo // codecに伝える iic_mcu_write_a_byte( IIC_SLA_CODEC, CODEC_REG_VOL, 127 - ( sndvol_codec / 2 + sndvol_codec / 4 )/2 ); } tokidoki += 1; } // TUNE_LED // // ここで?仕様? { switch ( vreg_ctr[VREG_C_LED_TUNE] ) { case LED_TUNE_ILM_ON: LED_duty_TUNE = vreg_ctr[VREG_C_LED_BRIGHT]; break; case LED_TUNE_ILM_SVR: LED_duty_TUNE = vreg_ctr[VREG_C_TUNE] / 16; break; case LED_TUNE_ILM_OFF: default: LED_duty_TUNE = 0; break; } } adc_updated = 0; } } ADCEN = 1; ADM = 0b00011011; // セレクトモード、章圧、fCLK/6 ///ここから ↓ ADPC = 0x02; // ADCポートのセレクト ADS = ADC_SEL_TUNE; // NOP(); ADCS = 1; // AD開始。 /// ここまで ↑ までに1us以上開ける 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; u8 temp; 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_ vreg_ctr[ VREG_C_TUNE ] = 255 - getmean3( hist_tune ); #else vreg_ctr[ VREG_C_TUNE ] = getmean3( hist_tune ); #endif break; case ( ADC_SEL_VOL ): hist_snd_vol[index] = ADCRH; vreg_ctr[VREG_C_SND_VOL] = getmean3( hist_snd_vol ); break; case ( ADC_SEL_BATT_TEMP ): hist_bt_temp[index] = ADCRH; raw_adc_temperature = getmean3( hist_bt_temp ); renge_task_immed_add( PM_bt_temp_update ); break; case ( ADC_SEL_BATT_DET ): // vreg_ctr[ VREG_C_DBG_BATT_DET ] = ADCRH; // todo break; } // もっとまともな書き方がありそうだ // if( ADS == ADC_SEL_BATT_DET ){b if( ADS != ADC_SEL_BATT_TEMP ) { // 電池判別は電源投入の一回のみ ADS += 1; // 次のチャンネル BT_TEMP_P = 1; // 電池温度監視スタート } else { ADCEN = 0; // 止めてしまう BT_TEMP_P = 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; ADCS = 0; ADM = 0b00100011; // セレクトモード、昇圧、fCLK/6 ///ここから↓ ADPC = 0x02; // ADCポートのセレクト ADS = ch; ADCS = 1; // AD開始。 /// ここまで↑ に、1us以上開ける ADMK = 0; while( ADIF == 0 ){;} temp = ADCRH; ADCEN = 0; return ( temp ); }