e57b04bf675de37d64e72a3ba2d10e63eadc0250
[bertos.git] / bertos / cpu / avr / drv / adc_avr.c
1 /*!
2  * \file
3  * <!--
4  * Copyright 2007 Develer S.r.l. (http://www.develer.com/)
5  * -->
6  *
7  * \version $Id$
8  *
9  * \brief ADC hardware-specific definition
10  *
11  * \version $Id$
12  * \author Francesco Sacchi <batt@develer.com>
13  */
14
15 #include "adc_avr.h"
16
17 #include <drv/adc.h>
18 #include <appconfig.h>
19
20 #include <cfg/macros.h>
21 #include <cfg/compiler.h>
22
23 #include <avr/io.h>
24 #include <avr/interrupt.h>
25
26 #define ADC_AVR_AREF   0
27 #define ADC_AVR_AVCC   1
28 #define ADC_AVR_INT256 2
29
30 #if CONFIG_KERNEL
31         #include <cfg/module.h>
32         #include <config_kern.h>
33         #include <kern/proc.h>
34         #include <kern/signal.h>
35
36
37         #if !CONFIG_KERN_SIGNALS
38                 #error Signals must be active to use ADC with kernel
39         #endif
40
41         /* Signal adc convertion end */
42         #define SIG_ADC_COMPLETE SIG_SINGLE
43
44         /* ADC waiting process */
45         static struct Process *adc_process;
46
47         /**
48          * ADC ISR.
49          * Simply signal the adc process that convertion is complete.
50          */
51         ISR(ADC_vect)
52         {
53                 sig_signal(adc_process, SIG_ADC_COMPLETE);
54         }
55 #endif /* CONFIG_KERNEL */
56
57 /**
58  * Select mux channel \a ch.
59  * \todo only first 8 channels are selectable!
60  */
61 INLINE void adc_hw_select_ch(uint8_t ch)
62 {
63         /* Set to 0 all mux registers */
64         ADMUX &= ~(BV(MUX3) | BV(MUX3) | BV(MUX2) | BV(MUX1) | BV(MUX0));
65
66         /* Select channel, only first 8 channel modes are supported for now */
67         ADMUX |= (ch & 0x07);
68 }
69
70
71 /**
72  * Start an ADC convertion.
73  * If a kernel is present, preempt until convertion is complete, otherwise
74  * a busy wait on ADCS bit is done.
75  */
76 INLINE uint16_t adc_hw_read(void)
77 {
78         // Ensure another convertion is not running.
79         ASSERT(!(ADCSRA & BV(ADSC)));
80
81         // Start convertion
82         ADCSRA |= BV(ADSC);
83
84         #if CONFIG_KERNEL
85                 // Ensure IRQs enabled.
86                 ASSERT(IRQ_ENABLED());
87                 adc_process = proc_current();
88                 sig_wait(SIG_ADC_COMPLETE);
89         #else
90                 //Wait in polling until is done
91                 while (ADCSRA & BV(ADSC)) ;
92         #endif
93
94         return(ADC);
95 }
96
97 /**
98  * Init ADC hardware.
99  */
100 INLINE void adc_hw_init(void)
101 {
102         /*
103          * Select channel 0 as default,
104          * result right adjusted.
105          */
106         ADMUX = 0;
107
108         #if CONFIG_ADC_AVR_REF == ADC_AVR_AREF
109                 /* External voltage at AREF as analog ref source */
110                 /* None */
111         #elif CONFIG_ADC_AVR_REF == ADC_AVR_AVCC
112                 /* AVCC as analog ref source */
113                 ADMUX |= BV(REFS0);
114         #elif CONFIG_ADC_AVR_REF == ADC_AVR_INT256
115                 /* Internal 2.56V as ref source */
116                 ADMUX |= BV(REFS1) | BV(REFS0);
117         #else
118                 #error Unsupported ADC ref value.
119         #endif
120
121         /* Disable Auto trigger source: ADC in Free running mode. */
122         ADCSRB = 0;
123         
124         /* Enable ADC, disable autotrigger mode. */
125         ADCSRA = BV(ADEN);
126
127         #if CONFIG_KERNEL
128                 MOD_CHECK(proc);
129                 ADCSRA |= BV(ADIE);
130         #endif
131
132         /* Set convertion frequency */
133         #if CONFIG_ADC_AVR_DIVISOR == 2
134                 ADCSRA |= BV(ADPS0);
135         #elif CONFIG_ADC_AVR_DIVISOR == 4
136                 ADCSRA |= BV(ADPS1);
137         #elif CONFIG_ADC_AVR_DIVISOR == 8
138                 ADCSRA |= BV(ADPS1) | BV(ADPS0);
139         #elif CONFIG_ADC_AVR_DIVISOR == 16
140                 ADCSRA |= BV(ADPS2);
141         #elif CONFIG_ADC_AVR_DIVISOR == 32
142                 ADCSRA |= BV(ADPS2) | BV(ADPS0);
143         #elif CONFIG_ADC_AVR_DIVISOR == 64
144                 ADCSRA |= BV(ADPS2) | BV(ADPS1);
145         #elif CONFIG_ADC_AVR_DIVISOR == 128
146                 ADCSRA |= BV(ADPS2) | BV(ADPS1) | BV(ADPS0);
147         #else
148                 #error Unsupported ADC prescaler value.
149         #endif
150
151         /* Start a convertion to init ADC hw */
152         adc_hw_read();
153 }