at91_adc.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2001-2005 by EmbeddedIT, 
00003  * Ole Reinhardt <ole.reinhardt@embedded-it.de> All rights reserved.
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 EMBEDDED IT 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 EMBEDDED IT
00022  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
00023  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
00024  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
00025  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
00026  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
00027  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
00028  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  *
00030  * For additional information see http://www.ethernut.de/
00031  *
00032  */
00033 
00034 /*
00035  * $Log$
00036  * Revision 1.4  2009/01/17 11:26:37  haraldkipp
00037  * Getting rid of two remaining BSD types in favor of stdint.
00038  * Replaced 'u_int' by 'unsinged int' and 'uptr_t' by 'uintptr_t'.
00039  *
00040  * Revision 1.3  2008/08/11 06:59:03  haraldkipp
00041  * BSD types replaced by stdint types (feature request #1282721).
00042  *
00043  * Revision 1.2  2007/12/09 22:13:08  olereinhardt
00044  * Added cvs log tag
00045  *
00046  */
00047 
00048 #include <arch/arm.h>
00049 #include <dev/irqreg.h>
00050 
00051 #include <sys/event.h>
00052 #include <sys/atom.h>
00053 #include <sys/timer.h>
00054 #include <sys/thread.h>
00055 #include <sys/heap.h>
00056 
00057 #include <dev/irqreg.h>
00058 #include <dev/at91_adc.h>
00059 
00064 
00065 #ifndef AT91_ADC_INITIAL_MODE
00066 #define AT91_ADC_INITIAL_MODE SINGLE_CONVERSION
00067 #endif
00068 
00069 #ifndef AT91_ADC_INITIAL_PRESCALE
00070 #define AT91_ADC_INITIAL_PRESCALE 55
00071 #endif
00072 
00073 #define AT91_ADC_BUF_SIZE 16 // this may only be a power of two
00074 
00075 #define _adc_buf_head AT91_ADC_BUF_SIZE
00076 #define _adc_buf_tail AT91_ADC_BUF_SIZE+1
00077 
00078 uint16_t **ADC_Buffer = NULL;
00079 
00088 int ADCBufRead(uint16_t channel, uint16_t * read)
00089 {
00090     uint16_t tail, head;
00091     tail = ADC_Buffer[channel][_adc_buf_tail];
00092     head = ADC_Buffer[channel][_adc_buf_head];
00093     if (head != tail) {
00094         *read = ADC_Buffer[channel][tail];
00095         ADC_Buffer[channel][_adc_buf_tail] = (tail + 1) & (AT91_ADC_BUF_SIZE-1);
00096         return 0;
00097     }
00098     return 1;
00099 }
00100 
00101 /* Store data in the buffer, called from interrupt */
00102 
00103 static inline int ADCBufWrite(uint16_t channel, uint16_t write)
00104 {
00105     uint16_t tail, head;
00106     tail = ADC_Buffer[channel][_adc_buf_tail];
00107     head = ADC_Buffer[channel][_adc_buf_head];
00108     if ((head + 1) % AT91_ADC_BUF_SIZE != tail) {
00109         ADC_Buffer[channel][head] = write;
00110         ADC_Buffer[channel][_adc_buf_head] = (head + 1) & (AT91_ADC_BUF_SIZE-1);
00111         return 0;
00112     }
00113     return 1;
00114 }
00115 
00122 void ADCSetMode(TADCMode mode) 
00123 {
00124     unsigned int regval;
00125     
00126     regval = inr(ADC_MR);
00127     regval &= ~ADC_SLEEP;
00128     switch (mode) {
00129         case ADC_OFF:
00130             regval &= ~ADC_TRGEN;
00131             regval |= ADC_SLEEP;
00132             break;
00133         case SINGLE_CONVERSION:
00134             regval &= ~ADC_TRGEN;
00135             break;
00136         case FREE_RUNNING_T0:
00137             regval &= ~ADC_TRGSEL;
00138             regval |= ADC_TRGEN | ADC_TRGSEL_TIOA0;
00139             break;     
00140         case FREE_RUNNING_T1:
00141             regval &= ~ADC_TRGSEL;
00142             regval |= ADC_TRGEN | ADC_TRGSEL_TIOA1;
00143             break;
00144         case FREE_RUNNING_T2:
00145             regval &= ~ADC_TRGSEL;
00146             regval |= ADC_TRGEN | ADC_TRGSEL_TIOA2;
00147         break;
00148         case FREE_RUNNING_EXT:
00149             regval &= ~ADC_TRGSEL;
00150             regval |= ADC_TRGEN | ADC_TRGSEL_EXT;
00151             break;
00152     }
00153     outr(ADC_MR, regval);
00154 }
00155 
00162 void ADCEnableChannel(TADCChannel channel) 
00163 {
00164     outr(ADC_CHER, _BV(channel));
00165     outr(ADC_IER,  _BV(channel));
00166 }
00167 
00174 void ADCDisableChannel(TADCChannel channel) 
00175 {
00176     outr(ADC_CHER, _BV(channel));
00177     outr(ADC_IDR,  _BV(channel));
00178 }
00179 
00186 void ADCSetPrescale(unsigned int prescale)
00187 {
00188     if (prescale > 128) prescale = 128;
00189 
00190     prescale = (prescale / 2) - 1;
00191     outr(ADC_MR, ((inr(ADC_MR) & ~(ADC_PRESCAL | ADC_STARTUP | ADC_SHTIM)) | 
00192                 (prescale << ADC_PRESCAL_LSB) | ADC_STARTUP | ADC_SHTIM));     // set maximum sample & hold and startup time
00193 }
00194 
00200 void ADCStartConversion(void)
00201 {
00202     outr(ADC_CR, ADC_START);
00203 }
00204 
00205 /*
00206  * ADC interrupt handler.
00207  */
00208 
00209 static void ADCInterrupt(void *arg)
00210 {
00211     register unsigned int adcsr = inr(ADC_SR);   
00212     uint16_t ADC_Value;        
00213     uint16_t channel;
00214 
00215     for (channel = 0; channel < ADC_MAX_CHANNEL; channel ++) {
00216         if (adcsr & _BV(channel)) {
00217             ADC_Value = inr(ADC_CDR(channel));
00218             if (ADCBufWrite(channel, ADC_Value) != 0) {
00219                 // Send error message
00220             }
00221         }
00222     }
00223 }
00224 
00229 void ADCInit(void)
00230 {
00231     int channel;
00232     
00233     /* Only init once */
00234     if (ADC_Buffer) return;
00235 
00236     /* Enable clock int PMC and reset ADC */
00237     outr(PMC_PCER, _BV(ADC_ID));              // Enable ADC clock in PMC
00238     outr(ADC_CR, ADC_SWRST);                  // Reset bus
00239     outr(ADC_CR, 0x00);
00240     
00241     /* Basic configuration: Disable all channels and set mode and prescaler */
00242     outr(ADC_CHDR, ADC_CH0 | ADC_CH1 | ADC_CH2 | ADC_CH3 | ADC_CH4 | ADC_CH5 | ADC_CH6 | ADC_CH7);
00243     ADCSetMode(AT91_ADC_INITIAL_MODE);
00244     ADCSetPrescale(AT91_ADC_INITIAL_PRESCALE);
00245 
00246     /* Init adc buffers. One for every channel as we can sample all by automatic sequence */
00247     ADC_Buffer = NutHeapAlloc(sizeof(uint16_t *) * ADC_MAX_CHANNEL);
00248     for (channel = 0; channel < ADC_MAX_CHANNEL; channel ++) {
00249         ADC_Buffer[channel] = NutHeapAlloc(sizeof(uint16_t) * AT91_ADC_BUF_SIZE + 2);
00250         ADC_Buffer[channel][_adc_buf_head] = 0;
00251         ADC_Buffer[channel][_adc_buf_tail] = 0;        
00252     }
00253 
00254     if (NutRegisterIrqHandler(&sig_ADC, ADCInterrupt, NULL)) {
00255         // We do not free buffer as this would cost ROM and is not likely
00256         return;
00257     }
00258     NutIrqEnable(&sig_ADC);
00259 }
00260 

© 2000-2007 by egnite Software GmbH - visit http://www.ethernut.de/