Nut/OS  4.10.3
API Reference
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 - 1)) != 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     uint32_t 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     uint32_t     adc_chsr;
00165     register int idx;
00166     register int max = channel;
00167 
00168     outr(ADC_CHER, _BV(channel));
00169     adc_chsr = inr(ADC_CHSR);
00170 
00171     /* Search the highest numbered channel which is enabled */
00172     for (idx = 0; idx < 8; idx ++) {
00173         if (adc_chsr & _BV(idx)) max = idx;
00174     }
00175 
00176     /* Disable EOC for all channels */
00177     outr(ADC_IDR, 0x000000FF);
00178     /* Enable EOC for highest numbered channel */
00179     outr(ADC_IER, _BV(max));
00180 }
00181 
00188 void ADCDisableChannel(TADCChannel channel) 
00189 {
00190     outr(ADC_CHDR, _BV(channel));
00191     outr(ADC_IDR,  _BV(channel));
00192 }
00193 
00200 void ADCSetPrescale(uint32_t prescale)
00201 {
00202     if (prescale > 128) prescale = 128;
00203 
00204     prescale = (prescale / 2) - 1;
00205     outr(ADC_MR, ((inr(ADC_MR) & ~(ADC_PRESCAL | ADC_STARTUP | ADC_SHTIM)) | 
00206                 (prescale << ADC_PRESCAL_LSB) | ADC_STARTUP | ADC_SHTIM));     // set maximum sample & hold and startup time
00207 }
00208 
00214 void ADCStartConversion(void)
00215 {
00216     outr(ADC_CR, ADC_START);
00217 }
00218 
00219 /*
00220  * ADC interrupt handler.
00221  */
00222 
00223 static void ADCInterrupt(void *arg)
00224 {
00225     register uint32_t adcsr = inr(ADC_SR) & inr(ADC_CHSR);
00226     uint16_t ADC_Value;        
00227     uint16_t channel;
00228 
00229     for (channel = 0; channel < ADC_MAX_CHANNEL; channel ++) {
00230         if (adcsr & _BV(channel)) {
00231             ADC_Value = inr(ADC_CDR(channel));
00232             if (ADCBufWrite(channel, ADC_Value) != 0) {
00233                 // Send error message
00234             }
00235         }
00236     }
00237 }
00238 
00243 void ADCInit(void)
00244 {
00245     int channel;
00246     
00247     /* Only init once */
00248     if (ADC_Buffer) return;
00249 
00250     /* Enable clock int PMC and reset ADC */
00251     outr(PMC_PCER, _BV(ADC_ID));              // Enable ADC clock in PMC
00252     outr(ADC_CR, ADC_SWRST);                  // Reset bus
00253     outr(ADC_CR, 0x00);
00254     
00255     /* Basic configuration: Disable all channels and set mode and prescaler */
00256     outr(ADC_CHDR, ADC_CH0 | ADC_CH1 | ADC_CH2 | ADC_CH3 | ADC_CH4 | ADC_CH5 | ADC_CH6 | ADC_CH7);
00257     ADCSetMode(AT91_ADC_INITIAL_MODE);
00258     ADCSetPrescale(AT91_ADC_INITIAL_PRESCALE);
00259 
00260     /* Init adc buffers. One for every channel as we can sample all by automatic sequence */
00261     ADC_Buffer = NutHeapAlloc(sizeof(uint16_t *) * ADC_MAX_CHANNEL);
00262     for (channel = 0; channel < ADC_MAX_CHANNEL; channel ++) {
00263         ADC_Buffer[channel] = NutHeapAlloc(sizeof(uint16_t) * AT91_ADC_BUF_SIZE + 2);
00264         ADC_Buffer[channel][_adc_buf_head] = 0;
00265         ADC_Buffer[channel][_adc_buf_tail] = 0;        
00266     }
00267 
00268     if (NutRegisterIrqHandler(&sig_ADC, ADCInterrupt, NULL)) {
00269         // We do not free buffer as this would cost ROM and is not likely
00270         return;
00271     }
00272     NutIrqEnable(&sig_ADC);
00273 }
00274