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

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