/** * \file * * * \brief ADC hardware-specific definition * * \author Francesco Sacchi * * This module is automatically included so no need to include * in test list. * notest: avr * * $WIZ$ */ #include "adc_avr.h" #include "cfg/cfg_adc.h" #include "cfg/cfg_proc.h" #include "cfg/cfg_signal.h" #include #include #include // IRQ_ASSERT_ENABLED() #include #include #include /** * ADC voltage referencese. * * $WIZ$ avr_adc_refs = "ADC_AVR_AREF", "ADC_AVR_AVCC", "ADC_AVR_INT256" * \{ */ #define ADC_AVR_AREF 0 #define ADC_AVR_AVCC 1 #define ADC_AVR_INT256 2 /* \} */ #if CONFIG_KERN #include #include #include #if !CONFIG_KERN_SIGNALS #error Signals must be active to use the ADC with kernel #endif /* Signal adc convertion end */ #define SIG_ADC_COMPLETE SIG_SINGLE /* ADC waiting process */ static struct Process *adc_process; /** * ADC ISR. * Simply signal the adc process that convertion is complete. */ ISR(ADC_vect) { sig_post(adc_process, SIG_ADC_COMPLETE); } #endif /* CONFIG_KERN */ /** * Select mux channel \a ch. * \todo only first 8 channels are selectable! */ void adc_hw_select_ch(uint8_t ch) { /* Set to 0 all mux registers */ #if CPU_AVR_ATMEGA8 || CPU_AVR_ATMEGA328P || CPU_AVR_ATMEGA168 ADMUX &= ~(BV(MUX3) | BV(MUX2) | BV(MUX1) | BV(MUX0)); #elif CPU_AVR_ATMEGA32 || CPU_AVR_ATMEGA64 || CPU_AVR_ATMEGA128 || CPU_AVR_ATMEGA1281 \ || CPU_AVR_ATMEGA1280 || CPU_AVR_ATMEGA2560 ADMUX &= ~(BV(MUX4) | BV(MUX3) | BV(MUX2) | BV(MUX1) | BV(MUX0)); #if CPU_AVR_ATMEGA1280 || CPU_AVR_ATMEGA2560 ADCSRB &= ~(BV(MUX5)); #endif #else #error Unknown CPU #endif /* Select channel, only first 8 channel modes are supported */ ADMUX |= (ch & 0x07); #if CPU_AVR_ATMEGA1280 || CPU_AVR_ATMEGA2560 /* Select channel, all 16 channels are supported */ if (ch > 0x07) ADCSRB |= BV(MUX5); #endif } /** * Start an ADC convertion. * If a kernel is present, preempt until convertion is complete, otherwise * a busy wait on ADCS bit is done. */ uint16_t adc_hw_read(void) { // Ensure another convertion is not running. ASSERT(!(ADCSRA & BV(ADSC))); // Start convertion ADCSRA |= BV(ADSC); #if CONFIG_KERN // Ensure IRQs enabled. IRQ_ASSERT_ENABLED(); adc_process = proc_current(); sig_wait(SIG_ADC_COMPLETE); #else //Wait in polling until is done while (ADCSRA & BV(ADSC)) ; #endif return(ADC); } /** * Init ADC hardware. */ void adc_hw_init(void) { /* * Select channel 0 as default, * result right adjusted. */ ADMUX = 0; #if CONFIG_ADC_AVR_REF == ADC_AVR_AREF /* External voltage at AREF as analog ref source */ /* None */ #elif CONFIG_ADC_AVR_REF == ADC_AVR_AVCC /* AVCC as analog ref source */ ADMUX |= BV(REFS0); #elif CONFIG_ADC_AVR_REF == ADC_AVR_INT256 /* Internal 2.56V as ref source */ ADMUX |= BV(REFS1) | BV(REFS0); #else #error Unsupported ADC ref value. #endif #if defined(ADCSRB) /* Disable Auto trigger source: ADC in Free running mode. */ ADCSRB = 0; #endif /* Enable ADC, disable autotrigger mode. */ ADCSRA = BV(ADEN); #if CONFIG_KERN MOD_CHECK(proc); ADCSRA |= BV(ADIE); #endif /* Set convertion frequency */ #if CONFIG_ADC_AVR_DIVISOR == 2 ADCSRA |= BV(ADPS0); #elif CONFIG_ADC_AVR_DIVISOR == 4 ADCSRA |= BV(ADPS1); #elif CONFIG_ADC_AVR_DIVISOR == 8 ADCSRA |= BV(ADPS1) | BV(ADPS0); #elif CONFIG_ADC_AVR_DIVISOR == 16 ADCSRA |= BV(ADPS2); #elif CONFIG_ADC_AVR_DIVISOR == 32 ADCSRA |= BV(ADPS2) | BV(ADPS0); #elif CONFIG_ADC_AVR_DIVISOR == 64 ADCSRA |= BV(ADPS2) | BV(ADPS1); #elif CONFIG_ADC_AVR_DIVISOR == 128 ADCSRA |= BV(ADPS2) | BV(ADPS1) | BV(ADPS0); #else #error Unsupported ADC prescaler value. #endif /* Start a convertion to init ADC hw */ adc_hw_read(); }