adc_avr.c
Go to the documentation of this file.
00001
00043 #include "adc_avr.h"
00044
00045 #include "cfg/cfg_adc.h"
00046 #include "cfg/cfg_proc.h"
00047 #include "cfg/cfg_signal.h"
00048 #include <cfg/macros.h>
00049 #include <cfg/compiler.h>
00050
00051 #include <cpu/irq.h> // IRQ_ASSERT_ENABLED()
00052
00053 #include <drv/adc.h>
00054
00055 #include <avr/io.h>
00056 #include <avr/interrupt.h>
00057
00064 #define ADC_AVR_AREF   0
00065 #define ADC_AVR_AVCC   1
00066 #define ADC_AVR_INT256 2
00067 /* \} */
00068
00069 #if CONFIG_KERN
00070     #include <cfg/module.h>
00071     #include <kern/proc.h>
00072     #include <kern/signal.h>
00073
00074
00075     #if !CONFIG_KERN_SIGNALS
00076         #error Signals must be active to use the ADC with kernel
00077     #endif
00078 
00079     /* Signal adc convertion end */
00080     #define SIG_ADC_COMPLETE SIG_SINGLE
00081 
00082     /* ADC waiting process */
00083     static struct Process *adc_process;
00084
00089     ISR(ADC_vect)
00090     {
00091         sig_post(adc_process, SIG_ADC_COMPLETE);
00092     }
00093 #endif /* CONFIG_KERN */
00094
00099 void adc_hw_select_ch(uint8_t ch)
00100 {
00101     /* Set to 0 all mux registers */
00102     #if CPU_AVR_ATMEGA8 || CPU_AVR_ATMEGA328P || CPU_AVR_ATMEGA168
00103         ADMUX &= ~(BV(MUX3) | BV(MUX2) | BV(MUX1) | BV(MUX0));
00104     #elif CPU_AVR_ATMEGA32 || CPU_AVR_ATMEGA64 || CPU_AVR_ATMEGA128 || CPU_AVR_ATMEGA1281 \
00105         || CPU_AVR_ATMEGA1280 || CPU_AVR_ATMEGA2560 || CPU_AVR_ATMEGA324P \
00106         || CPU_AVR_ATMEGA644P
00107         ADMUX &= ~(BV(MUX4) | BV(MUX3) | BV(MUX2) | BV(MUX1) | BV(MUX0));
00108         #if CPU_AVR_ATMEGA1280 || CPU_AVR_ATMEGA2560
00109             ADCSRB &= ~(BV(MUX5));
00110         #endif
00111     #else
00112         #error Unknown CPU
00113     #endif
00114 
00115     /* Select channel, only first 8 channel modes are supported */
00116     ADMUX |= (ch & 0x07);
00117
00118     #if CPU_AVR_ATMEGA1280 || CPU_AVR_ATMEGA2560
00119         /* Select channel, all 16 channels are supported */
00120         if (ch > 0x07)
00121             ADCSRB |= BV(MUX5);
00122
00123     #endif
00124 
00125 }
00126
00127
00133 uint16_t adc_hw_read(void)
00134 {
00135     // Ensure another convertion is not running.
00136     ASSERT(!(ADCSRA & BV(ADSC)));
00137
00138     // Start convertion
00139     ADCSRA |= BV(ADSC);
00140
00141     #if CONFIG_KERN
00142         // Ensure IRQs enabled.
00143         IRQ_ASSERT_ENABLED();
00144         adc_process = proc_current();
00145         sig_wait(SIG_ADC_COMPLETE);
00146     #else
00147         //Wait in polling until is done
00148         while (ADCSRA & BV(ADSC)) ;
00149     #endif
00150 
00151     return(ADC);
00152 }
00153
00157 void adc_hw_init(void)
00158 {
00159     /*
00160      * Select channel 0 as default,
00161      * result right adjusted.
00162      */
00163     ADMUX = 0;
00164
00165     #if CONFIG_ADC_AVR_REF == ADC_AVR_AREF
00166         /* External voltage at AREF as analog ref source */
00167         /* None */
00168     #elif CONFIG_ADC_AVR_REF == ADC_AVR_AVCC
00169         /* AVCC as analog ref source */
00170         ADMUX |= BV(REFS0);
00171     #elif CONFIG_ADC_AVR_REF == ADC_AVR_INT256
00172         /* Internal 2.56V as ref source */
00173         ADMUX |= BV(REFS1) | BV(REFS0);
00174     #else
00175         #error Unsupported ADC ref value.
00176     #endif
00177 
00178     #if defined(ADCSRB)
00179     /* Disable Auto trigger source: ADC in Free running mode. */
00180     ADCSRB = 0;
00181     #endif
00182 
00183     /* Enable ADC, disable autotrigger mode. */
00184     ADCSRA = BV(ADEN);
00185
00186     #if CONFIG_KERN
00187         MOD_CHECK(proc);
00188         ADCSRA |= BV(ADIE);
00189     #endif
00190 
00191     /* Set convertion frequency */
00192     #if CONFIG_ADC_AVR_DIVISOR == 2
00193         ADCSRA |= BV(ADPS0);
00194     #elif CONFIG_ADC_AVR_DIVISOR == 4
00195         ADCSRA |= BV(ADPS1);
00196     #elif CONFIG_ADC_AVR_DIVISOR == 8
00197         ADCSRA |= BV(ADPS1) | BV(ADPS0);
00198     #elif CONFIG_ADC_AVR_DIVISOR == 16
00199         ADCSRA |= BV(ADPS2);
00200     #elif CONFIG_ADC_AVR_DIVISOR == 32
00201         ADCSRA |= BV(ADPS2) | BV(ADPS0);
00202     #elif CONFIG_ADC_AVR_DIVISOR == 64
00203         ADCSRA |= BV(ADPS2) | BV(ADPS1);
00204     #elif CONFIG_ADC_AVR_DIVISOR == 128
00205         ADCSRA |= BV(ADPS2) | BV(ADPS1) | BV(ADPS0);
00206     #else
00207         #error Unsupported ADC prescaler value.
00208     #endif
00209 
00210     /* Start a convertion to init ADC hw */
00211     adc_hw_read();
00212 }