Nut/OS  4.10.3
API Reference
adc.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004 by Ole Reinhardt <ole.reinhardt@kernelconcepts.de>,
00003  *                       Kernelconcepts http://www.kernelconcepts.de
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  * 3. Neither the name of the copyright holders nor the names of
00015  *    contributors may be used to endorse or promote products derived
00016  *    from this software without specific prior written permission.
00017  *
00018  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00019  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00020  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00021  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00022  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00023  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00024  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00025  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00026  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00027  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00028  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00029  * SUCH DAMAGE.
00030  *
00031  * For additional information see http://www.ethernut.de/
00032  *
00033  */
00034 
00041 /*
00042  * $Log$
00043  * Revision 1.8  2008/08/11 06:59:14  haraldkipp
00044  * BSD types replaced by stdint types (feature request #1282721).
00045  *
00046  * Revision 1.7  2006/01/25 12:51:40  freckle
00047  * added explicit off mode
00048  *
00049  * Revision 1.6  2006/01/11 16:34:44  freckle
00050  * ADCInit can be called multiple times (makes life easier)
00051  *
00052  * Revision 1.5  2005/10/24 17:59:55  haraldkipp
00053  * Fixes for ATmega103
00054  *
00055  * Revision 1.4  2005/08/25 16:23:42  olereinhardt
00056  * Removed compute intensive % and replaced by an &
00057  *
00058  * Revision 1.3  2005/08/19 21:52:43  freckle
00059  * use 8-bit buffer pointers, removed critical section from ADCRead
00060  *
00061  * Revision 1.2  2005/08/02 17:46:45  haraldkipp
00062  * Major API documentation update.
00063  *
00064  * Revision 1.1  2005/07/26 18:02:27  haraldkipp
00065  * Moved from dev.
00066  *
00067  * Revision 1.3  2005/06/13 12:00:09  olereinhardt
00068  * Removed unnecessary NutExitCritical
00069  *
00070  * Revision 1.2  2005/03/04 11:42:05  olereinhardt
00071  * Added function void ADCStartLowNoiseConversion(void)
00072  * This function enters sleep mode!!! Be shure to read the AVR datasheet before using this function
00073  *
00074  * Revision 1.1  2004/08/02 10:05:25  olereinhardt
00075  * First checkin. ADC driver for ATMega128 / GCC
00076  *
00077  */
00078 
00079 
00085 
00086 /* Not ported. */
00087 #ifdef __GNUC__
00088 
00089 #include <string.h>
00090 #include <avr/sleep.h>
00091 #include <sys/heap.h>
00092 #include <sys/atom.h>
00093 #include <sys/nutconfig.h>
00094 
00095 #include <dev/irqreg.h>
00096 #include <dev/adc.h>
00097 
00098 #ifndef ADC_INITIAL_CHANNEL
00099 #define ADC_INITIAL_CHANNEL ADC0
00100 #endif
00101 
00102 #ifndef ADC_INITIAL_REF
00103 #define ADC_INITIAL_REF AVCC
00104 #endif
00105 
00106 #ifndef ADC_INITIAL_MODE
00107 #define ADC_INITIAL_MODE SINGLE_CONVERSION
00108 #endif
00109 
00110 #ifndef ADC_INITIAL_PRESCALE
00111 #define ADC_INITIAL_PRESCALE ADC_PRESCALE_DIV64
00112 #endif
00113 
00114 #define ADC_BUF_SIZE 16 // this may only be a power of two
00115 
00116 #if defined(__GNUC__) && defined(__AVR_ENHANCED__)
00117 uint8_t adc_sleep_mode = SLEEP_MODE_ADC;
00118 
00119 /* AT90CAN128 uses a different register to enter sleep mode */
00120 #if defined(SMCR)
00121 #define AVR_SLEEP_CTRL_REG    SMCR
00122 #else
00123 #define AVR_SLEEP_CTRL_REG    MCUCR
00124 #endif
00125 #endif
00126 
00127 
00128 
00129 /********** DRIVER GLOBALS **********/
00130 adc_mode_t current_mode = ADC_OFF;
00131 
00132 // The buffers are FIFO buffers implemented as char
00133 // arrays with head and tail pointers.
00134 
00135 // All read and write functions return a 0 for
00136 // success and a 1 for fail, if a successfull read,
00137 // the character is placed into *read.
00138 
00139 // buffer: [data1 data2 ... datalast head tail]
00140 
00141 #define _adc_buf_head ADC_BUF_SIZE
00142 #define _adc_buf_tail (ADC_BUF_SIZE+1)
00143 
00144 uint16_t *ADC_buffer = NULL;
00145 
00146 inline int ADCBufRead(uint16_t * buf, uint16_t * read)
00147 {
00148     uint8_t tail, head;
00149     tail = buf[_adc_buf_tail];
00150     head = buf[_adc_buf_head];
00151     if (head != tail) {
00152         *read = buf[tail];
00153         buf[_adc_buf_tail] = (tail + 1) & (ADC_BUF_SIZE-1);
00154         return 0;
00155     }
00156     return 1;
00157 }
00158 
00159 inline int ADCBufWrite(uint16_t * buf, uint16_t * write)
00160 {
00161     uint8_t tail, head;
00162     tail = buf[_adc_buf_tail];
00163     head = buf[_adc_buf_head];
00164     if ((head + 1) % ADC_BUF_SIZE != tail) {
00165         buf[head] = *write;
00166         buf[_adc_buf_head] = (head + 1) & (ADC_BUF_SIZE-1);
00167         return 0;
00168     }
00169     return 1;
00170 }
00171 
00172 void ADCBufInit(uint16_t * buf)
00173 {
00174     buf[_adc_buf_head] = 0;
00175     buf[_adc_buf_tail] = 0;
00176 }
00177 
00178 static void ADCInterrupt(void *arg)
00179 {
00180     uint16_t ADC_value;
00181 
00182     ADC_value = inw(ADCW);
00183 
00184     if (ADCBufWrite(ADC_buffer, &ADC_value) != 0) {
00185         // Send error message
00186     }
00187 
00188 }
00189 
00190 void ADCInit()
00191 {
00192     if (ADC_buffer) return;
00193 
00194     ADCSetChannel(ADC_INITIAL_CHANNEL);
00195     ADCSetRef(ADC_INITIAL_REF);
00196     ADCSetMode(ADC_INITIAL_MODE);
00197     ADCSetPrescale(ADC_INITIAL_PRESCALE);
00198 
00199     ADC_buffer = NutHeapAlloc(sizeof(uint16_t) * (ADC_BUF_SIZE + 2));
00200     ADCBufInit(ADC_buffer);
00201 
00202     if (NutRegisterIrqHandler(&sig_ADC, ADCInterrupt, NULL)) {
00203         // MR 2006-01-11: we do not free buffer as this would cost ROM and is not likely
00204         return;
00205     }
00206     // Enable ADC
00207     sbi(ADCSR, ADEN);
00208 
00209     // Enable ADC interrupt
00210     sbi(ADCSR, ADIE);
00211 }
00212 
00213 void ADCSetRef(adc_ref_t reference)
00214 {
00215     ADCStopConversion();
00216 
00217 #ifdef __AVR_ENHANCED__
00218     switch (reference) {
00219     case AVCC:
00220         cbi(ADMUX, REFS1);
00221         sbi(ADMUX, REFS0);
00222         break;
00223     case AREF:
00224         cbi(ADMUX, REFS1);
00225         cbi(ADMUX, REFS0);
00226         break;
00227     case INTERNAL_256:
00228         sbi(ADMUX, REFS1);
00229         sbi(ADMUX, REFS0);
00230         break;
00231     }
00232 #endif /* __AVR_ENHANCED__ */
00233 
00234 }
00235 
00236 void ADCSetMode(adc_mode_t mode)
00237 {
00238     ADCStopConversion();
00239 
00240     switch (mode) {
00241     case FREE_RUNNING:
00242         sbi(ADCSR, ADFR);
00243         break;
00244     case SINGLE_CONVERSION:
00245         cbi(ADCSR, ADFR);
00246         break;
00247     case ADC_OFF:
00248                 break;
00249     }
00250         current_mode = mode;
00251 }
00252 
00253 uint8_t ADCSetPrescale(uint8_t prescalar)
00254 {
00255 
00256     ADCStopConversion();
00257 
00258     if (prescalar > 128) {
00259         prescalar = 128;
00260     }
00261 
00262     switch (prescalar) {
00263     case ADC_PRESCALE_DIV2:
00264         cbi(ADCSR, ADPS2);
00265         cbi(ADCSR, ADPS1);
00266         cbi(ADCSR, ADPS0);
00267         break;
00268     case ADC_PRESCALE_DIV4:
00269         cbi(ADCSR, ADPS2);
00270         sbi(ADCSR, ADPS1);
00271         cbi(ADCSR, ADPS0);
00272         break;
00273     case ADC_PRESCALE_DIV8:
00274         cbi(ADCSR, ADPS2);
00275         sbi(ADCSR, ADPS1);
00276         sbi(ADCSR, ADPS0);
00277         break;
00278     case ADC_PRESCALE_DIV16:
00279         sbi(ADCSR, ADPS2);
00280         cbi(ADCSR, ADPS1);
00281         cbi(ADCSR, ADPS0);
00282         break;
00283     case ADC_PRESCALE_DIV32:
00284         sbi(ADCSR, ADPS2);
00285         cbi(ADCSR, ADPS1);
00286         sbi(ADCSR, ADPS0);
00287         break;
00288     case ADC_PRESCALE_DIV64:
00289         sbi(ADCSR, ADPS2);
00290         sbi(ADCSR, ADPS1);
00291         cbi(ADCSR, ADPS0);
00292         break;
00293     case ADC_PRESCALE_DIV128:
00294         sbi(ADCSR, ADPS2);
00295         sbi(ADCSR, ADPS1);
00296         sbi(ADCSR, ADPS0);
00297         break;
00298 
00299     default:
00300         return 1;
00301         break;
00302     }
00303 
00304     return 0;
00305 }
00306 
00307 void ADCSetChannel(adc_channel_t adc_channel)
00308 {
00309     uint8_t current_admux;
00310 
00311     current_admux = inb(ADMUX) & 0xF8;
00312 
00313     outb(ADMUX, (current_admux | adc_channel));
00314 }
00315 
00316 void ADCBufferFlush(void)
00317 {
00318     ADCBufInit(ADC_buffer);
00319 }
00320 
00321 void ADCStartConversion()
00322 {
00323     sbi(ADCSR, ADSC);
00324 }
00325 
00326 void ADCStartLowNoiseConversion()
00327 {
00328     ADCSetMode(SINGLE_CONVERSION);
00329 
00330 #if defined(__GNUC__) && defined(__AVR_ENHANCED__)
00331     {
00332         uint8_t sleep_mode = AVR_SLEEP_CTRL_REG & _SLEEP_MODE_MASK;
00333         set_sleep_mode(adc_sleep_mode);
00334         /* Note:  avr-libc has a sleep_mode() function, but it's broken for
00335         AT90CAN128 with avr-libc version earlier than 1.2 */
00336         AVR_SLEEP_CTRL_REG |= _BV(SE);
00337         __asm__ __volatile__ ("sleep" "\n\t" :: );
00338         AVR_SLEEP_CTRL_REG &= ~_BV(SE);
00339         set_sleep_mode(sleep_mode);
00340     }
00341 #else
00342     sbi(ADCSR, ADSC);
00343 #endif    
00344 }
00345 
00346 void ADCStopConversion()
00347 {
00348     if (current_mode != FREE_RUNNING) {
00349         // Send warning message
00350         return;
00351     }
00352 // Terminate and restart the ADC 
00353 // When restarted, start_conversion needs to be
00354 // called again
00355     cbi(ADCSR, ADEN);
00356     cbi(ADCSR, ADSC);
00357     sbi(ADCSR, ADEN);
00358 }
00359 
00360 uint8_t ADCRead(uint16_t * value)
00361 {
00362     return ADCBufRead(ADC_buffer, value);
00363 }
00364 
00365 inline adc_mode_t ADCGetMode(void)
00366 {
00367     return (current_mode);
00368 }
00369 #endif
00370