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: at91_adc.c,v $
00036  * Revision 1.2  2007/12/09 22:13:08  olereinhardt
00037  * Added cvs log tag
00038  *
00039  */
00040 
00041 #include <arch/arm.h>
00042 #include <dev/irqreg.h>
00043 
00044 #include <sys/event.h>
00045 #include <sys/atom.h>
00046 #include <sys/timer.h>
00047 #include <sys/thread.h>
00048 #include <sys/heap.h>
00049 
00050 #include <dev/irqreg.h>
00051 #include <dev/at91_adc.h>
00052 
00057 
00058 #ifndef AT91_ADC_INITIAL_MODE
00059 #define AT91_ADC_INITIAL_MODE SINGLE_CONVERSION
00060 #endif
00061 
00062 #ifndef AT91_ADC_INITIAL_PRESCALE
00063 #define AT91_ADC_INITIAL_PRESCALE 55
00064 #endif
00065 
00066 #define AT91_ADC_BUF_SIZE 16 // this may only be a power of two
00067 
00068 #define _adc_buf_head AT91_ADC_BUF_SIZE
00069 #define _adc_buf_tail AT91_ADC_BUF_SIZE+1
00070 
00071 u_short **ADC_Buffer = NULL;
00072 
00081 int ADCBufRead(u_short channel, u_short * read)
00082 {
00083     u_short tail, head;
00084     tail = ADC_Buffer[channel][_adc_buf_tail];
00085     head = ADC_Buffer[channel][_adc_buf_head];
00086     if (head != tail) {
00087         *read = ADC_Buffer[channel][tail];
00088         ADC_Buffer[channel][_adc_buf_tail] = (tail + 1) & (AT91_ADC_BUF_SIZE-1);
00089         return 0;
00090     }
00091     return 1;
00092 }
00093 
00094 /* Store data in the buffer, called from interrupt */
00095 
00096 static inline int ADCBufWrite(u_short channel, u_short write)
00097 {
00098     u_short tail, head;
00099     tail = ADC_Buffer[channel][_adc_buf_tail];
00100     head = ADC_Buffer[channel][_adc_buf_head];
00101     if ((head + 1) % AT91_ADC_BUF_SIZE != tail) {
00102         ADC_Buffer[channel][head] = write;
00103         ADC_Buffer[channel][_adc_buf_head] = (head + 1) & (AT91_ADC_BUF_SIZE-1);
00104         return 0;
00105     }
00106     return 1;
00107 }
00108 
00115 void ADCSetMode(TADCMode mode) 
00116 {
00117     u_int regval;
00118     
00119     regval = inr(ADC_MR);
00120     regval &= ~ADC_SLEEP;
00121     switch (mode) {
00122         case ADC_OFF:
00123             regval &= ~ADC_TRGEN;
00124             regval |= ADC_SLEEP;
00125             break;
00126         case SINGLE_CONVERSION:
00127             regval &= ~ADC_TRGEN;
00128             break;
00129         case FREE_RUNNING_T0:
00130             regval &= ~ADC_TRGSEL;
00131             regval |= ADC_TRGEN | ADC_TRGSEL_TIOA0;
00132             break;     
00133         case FREE_RUNNING_T1:
00134             regval &= ~ADC_TRGSEL;
00135             regval |= ADC_TRGEN | ADC_TRGSEL_TIOA1;
00136             break;
00137         case FREE_RUNNING_T2:
00138             regval &= ~ADC_TRGSEL;
00139             regval |= ADC_TRGEN | ADC_TRGSEL_TIOA2;
00140         break;
00141         case FREE_RUNNING_EXT:
00142             regval &= ~ADC_TRGSEL;
00143             regval |= ADC_TRGEN | ADC_TRGSEL_EXT;
00144             break;
00145     }
00146     outr(ADC_MR, regval);
00147 }
00148 
00155 void ADCEnableChannel(TADCChannel channel) 
00156 {
00157     outr(ADC_CHER, _BV(channel));
00158     outr(ADC_IER,  _BV(channel));
00159 }
00160 
00167 void ADCDisableChannel(TADCChannel channel) 
00168 {
00169     outr(ADC_CHER, _BV(channel));
00170     outr(ADC_IDR,  _BV(channel));
00171 }
00172 
00179 void ADCSetPrescale(u_int prescale)
00180 {
00181     if (prescale > 128) prescale = 128;
00182 
00183     prescale = (prescale / 2) - 1;
00184     outr(ADC_MR, ((inr(ADC_MR) & ~(ADC_PRESCAL | ADC_STARTUP | ADC_SHTIM)) | 
00185                 (prescale << ADC_PRESCAL_LSB) | ADC_STARTUP | ADC_SHTIM));     // set maximum sample & hold and startup time
00186 }
00187 
00193 void ADCStartConversion(void)
00194 {
00195     outr(ADC_CR, ADC_START);
00196 }
00197 
00198 /*
00199  * ADC interrupt handler.
00200  */
00201 
00202 static void ADCInterrupt(void *arg)
00203 {
00204     register u_int adcsr = inr(ADC_SR);   
00205     u_short ADC_Value;        
00206     u_short channel;
00207 
00208     for (channel = 0; channel < ADC_MAX_CHANNEL; channel ++) {
00209         if (adcsr & _BV(channel)) {
00210             ADC_Value = inr(ADC_CDR(channel));
00211             if (ADCBufWrite(channel, ADC_Value) != 0) {
00212                 // Send error message
00213             }
00214         }
00215     }
00216 }
00217 
00222 void ADCInit(void)
00223 {
00224     int channel;
00225     
00226     /* Only init once */
00227     if (ADC_Buffer) return;
00228 
00229     /* Enable clock int PMC and reset ADC */
00230     outr(PMC_PCER, _BV(ADC_ID));              // Enable ADC clock in PMC
00231     outr(ADC_CR, ADC_SWRST);                  // Reset bus
00232     outr(ADC_CR, 0x00);
00233     
00234     /* Basic configuration: Disable all channels and set mode and prescaler */
00235     outr(ADC_CHDR, ADC_CH0 | ADC_CH1 | ADC_CH2 | ADC_CH3 | ADC_CH4 | ADC_CH5 | ADC_CH6 | ADC_CH7);
00236     ADCSetMode(AT91_ADC_INITIAL_MODE);
00237     ADCSetPrescale(AT91_ADC_INITIAL_PRESCALE);
00238 
00239     /* Init adc buffers. One for every channel as we can sample all by automatic sequence */
00240     ADC_Buffer = NutHeapAlloc(sizeof(u_short *) * ADC_MAX_CHANNEL);
00241     for (channel = 0; channel < ADC_MAX_CHANNEL; channel ++) {
00242         ADC_Buffer[channel] = NutHeapAlloc(sizeof(u_short) * AT91_ADC_BUF_SIZE + 2);
00243         ADC_Buffer[channel][_adc_buf_head] = 0;
00244         ADC_Buffer[channel][_adc_buf_tail] = 0;        
00245     }
00246 
00247     if (NutRegisterIrqHandler(&sig_ADC, ADCInterrupt, NULL)) {
00248         // We do not free buffer as this would cost ROM and is not likely
00249         return;
00250     }
00251     NutIrqEnable(&sig_ADC);
00252 }
00253 

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