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