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         ADMUX &= ~(BV(MUX4) | BV(MUX3) | BV(MUX2) | BV(MUX1) | BV(MUX0));
00106     #else
00107         #error Unknown CPU
00108     #endif
00109 
00110     /* Select channel, only first 8 channel modes are supported for now */
00111     ADMUX |= (ch & 0x07);
00112 }
00113 
00114 
00120 uint16_t adc_hw_read(void)
00121 {
00122     // Ensure another convertion is not running.
00123     ASSERT(!(ADCSRA & BV(ADSC)));
00124 
00125     // Start convertion
00126     ADCSRA |= BV(ADSC);
00127 
00128     #if CONFIG_KERN
00129         // Ensure IRQs enabled.
00130         IRQ_ASSERT_ENABLED();
00131         adc_process = proc_current();
00132         sig_wait(SIG_ADC_COMPLETE);
00133     #else
00134         //Wait in polling until is done
00135         while (ADCSRA & BV(ADSC)) ;
00136     #endif
00137 
00138     return(ADC);
00139 }
00140 
00144 void adc_hw_init(void)
00145 {
00146     /*
00147      * Select channel 0 as default,
00148      * result right adjusted.
00149      */
00150     ADMUX = 0;
00151 
00152     #if CONFIG_ADC_AVR_REF == ADC_AVR_AREF
00153         /* External voltage at AREF as analog ref source */
00154         /* None */
00155     #elif CONFIG_ADC_AVR_REF == ADC_AVR_AVCC
00156         /* AVCC as analog ref source */
00157         ADMUX |= BV(REFS0);
00158     #elif CONFIG_ADC_AVR_REF == ADC_AVR_INT256
00159         /* Internal 2.56V as ref source */
00160         ADMUX |= BV(REFS1) | BV(REFS0);
00161     #else
00162         #error Unsupported ADC ref value.
00163     #endif
00164 
00165     #if defined(ADCSRB)
00166     /* Disable Auto trigger source: ADC in Free running mode. */
00167     ADCSRB = 0;
00168     #endif
00169 
00170     /* Enable ADC, disable autotrigger mode. */
00171     ADCSRA = BV(ADEN);
00172 
00173     #if CONFIG_KERN
00174         MOD_CHECK(proc);
00175         ADCSRA |= BV(ADIE);
00176     #endif
00177 
00178     /* Set convertion frequency */
00179     #if CONFIG_ADC_AVR_DIVISOR == 2
00180         ADCSRA |= BV(ADPS0);
00181     #elif CONFIG_ADC_AVR_DIVISOR == 4
00182         ADCSRA |= BV(ADPS1);
00183     #elif CONFIG_ADC_AVR_DIVISOR == 8
00184         ADCSRA |= BV(ADPS1) | BV(ADPS0);
00185     #elif CONFIG_ADC_AVR_DIVISOR == 16
00186         ADCSRA |= BV(ADPS2);
00187     #elif CONFIG_ADC_AVR_DIVISOR == 32
00188         ADCSRA |= BV(ADPS2) | BV(ADPS0);
00189     #elif CONFIG_ADC_AVR_DIVISOR == 64
00190         ADCSRA |= BV(ADPS2) | BV(ADPS1);
00191     #elif CONFIG_ADC_AVR_DIVISOR == 128
00192         ADCSRA |= BV(ADPS2) | BV(ADPS1) | BV(ADPS0);
00193     #else
00194         #error Unsupported ADC prescaler value.
00195     #endif
00196 
00197     /* Start a convertion to init ADC hw */
00198     adc_hw_read();
00199 }