adc_avr.c

Go to the documentation of this file.
00001 
00042 #include "adc_avr.h"
00043 
00044 #include <cpu/irq.h> // IRQ_ASSERT_ENABLED()
00045 #include "cfg/cfg_adc.h"
00046 #include "cfg/cfg_kern.h"
00047 #include <cfg/macros.h>
00048 #include <cfg/compiler.h>
00049 
00050 #include <drv/adc.h>
00051 
00052 #include <avr/io.h>
00053 #include <avr/interrupt.h>
00054 
00055 #define ADC_AVR_AREF   0
00056 #define ADC_AVR_AVCC   1
00057 #define ADC_AVR_INT256 2
00058 
00059 #if CONFIG_KERN
00060     #include <cfg/module.h>
00061     #include <kern/proc.h>
00062     #include <kern/signal.h>
00063 
00064 
00065     #if !CONFIG_KERN_SIGNALS
00066         #error Signals must be active to use ADC with kernel
00067     #endif
00068 
00069     /* Signal adc convertion end */
00070     #define SIG_ADC_COMPLETE SIG_SINGLE
00071 
00072     /* ADC waiting process */
00073     static struct Process *adc_process;
00074 
00079     ISR(ADC_vect)
00080     {
00081         sig_signal(adc_process, SIG_ADC_COMPLETE);
00082     }
00083 #endif /* CONFIG_KERN */
00084 
00089 INLINE void adc_hw_select_ch(uint8_t ch)
00090 {
00091     /* Set to 0 all mux registers */
00092     ADMUX &= ~(BV(MUX3) | BV(MUX3) | BV(MUX2) | BV(MUX1) | BV(MUX0));
00093 
00094     /* Select channel, only first 8 channel modes are supported for now */
00095     ADMUX |= (ch & 0x07);
00096 }
00097 
00098 
00104 INLINE uint16_t adc_hw_read(void)
00105 {
00106     // Ensure another convertion is not running.
00107     ASSERT(!(ADCSRA & BV(ADSC)));
00108 
00109     // Start convertion
00110     ADCSRA |= BV(ADSC);
00111 
00112     #if CONFIG_KERN
00113         // Ensure IRQs enabled.
00114         IRQ_ASSERT_ENABLED();
00115         adc_process = proc_current();
00116         sig_wait(SIG_ADC_COMPLETE);
00117     #else
00118         //Wait in polling until is done
00119         while (ADCSRA & BV(ADSC)) ;
00120     #endif
00121 
00122     return(ADC);
00123 }
00124 
00128 INLINE void adc_hw_init(void)
00129 {
00130     /*
00131      * Select channel 0 as default,
00132      * result right adjusted.
00133      */
00134     ADMUX = 0;
00135 
00136     #if CONFIG_ADC_AVR_REF == ADC_AVR_AREF
00137         /* External voltage at AREF as analog ref source */
00138         /* None */
00139     #elif CONFIG_ADC_AVR_REF == ADC_AVR_AVCC
00140         /* AVCC as analog ref source */
00141         ADMUX |= BV(REFS0);
00142     #elif CONFIG_ADC_AVR_REF == ADC_AVR_INT256
00143         /* Internal 2.56V as ref source */
00144         ADMUX |= BV(REFS1) | BV(REFS0);
00145     #else
00146         #error Unsupported ADC ref value.
00147     #endif
00148 
00149     #if defined(ADCSRB)
00150     /* Disable Auto trigger source: ADC in Free running mode. */
00151     ADCSRB = 0;
00152     #endif
00153 
00154     /* Enable ADC, disable autotrigger mode. */
00155     ADCSRA = BV(ADEN);
00156 
00157     #if CONFIG_KERN
00158         MOD_CHECK(proc);
00159         ADCSRA |= BV(ADIE);
00160     #endif
00161 
00162     /* Set convertion frequency */
00163     #if CONFIG_ADC_AVR_DIVISOR == 2
00164         ADCSRA |= BV(ADPS0);
00165     #elif CONFIG_ADC_AVR_DIVISOR == 4
00166         ADCSRA |= BV(ADPS1);
00167     #elif CONFIG_ADC_AVR_DIVISOR == 8
00168         ADCSRA |= BV(ADPS1) | BV(ADPS0);
00169     #elif CONFIG_ADC_AVR_DIVISOR == 16
00170         ADCSRA |= BV(ADPS2);
00171     #elif CONFIG_ADC_AVR_DIVISOR == 32
00172         ADCSRA |= BV(ADPS2) | BV(ADPS0);
00173     #elif CONFIG_ADC_AVR_DIVISOR == 64
00174         ADCSRA |= BV(ADPS2) | BV(ADPS1);
00175     #elif CONFIG_ADC_AVR_DIVISOR == 128
00176         ADCSRA |= BV(ADPS2) | BV(ADPS1) | BV(ADPS0);
00177     #else
00178         #error Unsupported ADC prescaler value.
00179     #endif
00180 
00181     /* Start a convertion to init ADC hw */
00182     adc_hw_read();
00183 }