2 * Copyright Droids Corporation, Microb Technology, Eirbot (2005)
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * Revision : $Id: adc.c,v 1.8.4.8 2009-02-27 21:37:49 zer0 Exp $
27 /* keep the previous config */
28 static uint16_t g_adc_previous_config = ADC_NO_CONFIG;
30 /* function pointer definition for event */
31 static void (*adc_event)(int16_t) = NULL;
35 * Initialisation of ADC internal registers
36 * Can be called for a wake up after a shutdown command
40 #if defined(PRADC) && defined(PRR)
42 #elif defined(PRADC) && defined(PRR0)
46 ADCSRA = (1<<ADEN) | (ADC_PRESCALE << ADPS0);
54 * Shut down the ADC, for power consumption
56 void adc_shutdown(void)
58 ADCSRA = 0; // erases all the register
60 #if defined(PRADC) && defined(PRR)
62 #elif defined(PRADC) && defined(PRR0)
69 * Register callback event. The parameter function is called when the
70 * conversion is finished.
72 void adc_register_event(void (*f)(int16_t))
82 * Interrupt function, other interrupts are disabled during its
87 #define ADC_vect SIG_ADC
99 /* sign extension to fill the 16 bits when negative
100 * (for the 16 bits output format, the output is
102 if ( ( g_adc_previous_config & ADC_RESULT_SIGNED)
103 && !(g_adc_previous_config & ADC_MODE_16_BITS)
104 && (result & 0x0200) )
112 * Launch a conversion : this function launches a conversion with the
113 * specified configuration. The conversion_config is casted to an
116 void adc_launch(uint16_t conversion_config)
118 /* configure multiplexer : done first, so the maximum time is
119 * left before the real conversion launch */
120 ADMUX = conversion_config & 0xFF ;
122 * This disables and reenables the ADC when a different
123 * channel is selected AND the new channel is a differential
124 * one. Using this trick, the ADC recalibrates, and the time
125 * for this allows the amplifier to settle.
128 * When switching to a differential gain channel, the first
129 * conversion result may have a poor accuracy due to the
130 * required settling time for the automatic offset
131 * cancellation circuitry. The user should preferably
132 * disregard the first conversion result.
134 if ( (conversion_config & ADC_RESULT_SIGNED) &&
135 (g_adc_previous_config != conversion_config) ) {
141 g_adc_previous_config = conversion_config;
143 /* for some devices, one additionnal MUX bit is in ADCSRB */
144 #ifdef MUX5_IN_ADCSRB
145 if (conversion_config & MUX5_MASK_IN_CONFIG)
149 #endif // MUX5_IN_ADCSRB
151 /* Enable free run or not (triggered mode) */
152 if (conversion_config & ADC_MODE_TRIGGERED)
157 /* Start conversion, with or without enabling interrupts */
158 if (conversion_config & ADC_MODE_INT) {
159 /* Clear flag from previous intr (in case of previous
160 * conversion was not using intr), and enable
162 ADCSRA |= (1 << ADSC) | (1 << ADIF) | (1 << ADIE);
165 /* clear flag from previous int, used as a 'conversion
168 ADCSRA |= (1 << ADSC) | (1 << ADIF);
173 * This function gets an ADC value. If a conversion has been
174 * previously started, with EXACTLY the same config (or specifying
175 * ADC_NO_CONFIG) then it waits for it to finish. Else it launches a
176 * new one with the given config, and polls the result.
178 * This function should not be used if you use interrupts, but only
179 * can be used with triggered (or free run mode)
181 int16_t adc_get_value(uint16_t conversion_config)
185 /* conversion has previously been launched, or no change */
186 if ((conversion_config == ADC_NO_CONFIG) ||
187 (conversion_config == g_adc_previous_config)) {
188 if (bit_is_clear(ADCSRA, ADSC) &&
189 bit_is_clear(ADCSRA, ADIF)) {
190 /* no result is available now and no
191 conversion is pending -> launch it... */
192 adc_launch(g_adc_previous_config);
195 /* The previous conversion had a different configuration : we
196 * must launch a new one */
198 /* Cancel previous triggered mode, if it was set and
199 * reset interrupt mask */
203 /* waiting for the previous conv to finish, result will
205 while (bit_is_set(ADCSRA, ADSC));
208 adc_launch(conversion_config);
211 /* waiting for the result, works even in triggered mode, then
213 while (bit_is_clear(ADCSRA, ADIF));
218 /* If we are in SIGNED_MODE + 10 bits format, and if the
219 * result is negative, set the 7 first MSB bits to 1 */
220 if( ( g_adc_previous_config & ADC_RESULT_SIGNED ) &&
221 !(g_adc_previous_config & ADC_MODE_16_BITS) &&
222 (result & 0x0200) ) {
231 * Just a int32_t version for compatibility with control_system
232 * function prototypes.
234 int32_t adc_get_value32(void *conversion_config)
236 return adc_get_value((uint16_t)conversion_config);