| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 |
- /*
- * Copyright (C) 2001-2005 by EmbeddedIT,
- * Ole Reinhardt <ole.reinhardt@embedded-it.de> All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY EMBEDDED IT AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EMBEDDED IT
- * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * For additional information see http://www.ethernut.de/
- *
- */
- /*
- * $Log$
- * Revision 1.4 2009/01/17 11:26:37 haraldkipp
- * Getting rid of two remaining BSD types in favor of stdint.
- * Replaced 'u_int' by 'unsinged int' and 'uptr_t' by 'uintptr_t'.
- *
- * Revision 1.3 2008/08/11 06:59:03 haraldkipp
- * BSD types replaced by stdint types (feature request #1282721).
- *
- * Revision 1.2 2007/12/09 22:13:08 olereinhardt
- * Added cvs log tag
- *
- */
- #include <arch/arm.h>
- #include <dev/irqreg.h>
- #include <sys/event.h>
- #include <sys/atom.h>
- #include <sys/timer.h>
- #include <sys/thread.h>
- #include <sys/heap.h>
- #include <dev/irqreg.h>
- #include <dev/at91_adc.h>
- /*!
- * \addtogroup xgNutArchArmAt91Adc
- */
- /*@{*/
- #ifndef AT91_ADC_INITIAL_MODE
- #define AT91_ADC_INITIAL_MODE SINGLE_CONVERSION
- #endif
- #ifndef AT91_ADC_INITIAL_PRESCALE
- #define AT91_ADC_INITIAL_PRESCALE 55
- #endif
- #define AT91_ADC_BUF_SIZE 16 // this may only be a power of two
- #define _adc_buf_head AT91_ADC_BUF_SIZE
- #define _adc_buf_tail AT91_ADC_BUF_SIZE+1
- uint16_t **ADC_Buffer = NULL;
- /*!
- * \brief Reads data from the adc buffer
- *
- * \param channel Specifies the channel to read data from
- * \param read Variable to store the data in
- * \return 0: data read succesfully, 1: no data available
- */
- int ADCBufRead(uint16_t channel, uint16_t * read)
- {
- uint16_t tail, head;
- tail = ADC_Buffer[channel][_adc_buf_tail];
- head = ADC_Buffer[channel][_adc_buf_head];
- if (head != tail) {
- *read = ADC_Buffer[channel][tail];
- ADC_Buffer[channel][_adc_buf_tail] = (tail + 1) & (AT91_ADC_BUF_SIZE - 1);
- return 0;
- }
- return 1;
- }
- /* Store data in the buffer, called from interrupt */
- static inline int ADCBufWrite(uint16_t channel, uint16_t write)
- {
- uint16_t tail, head;
- tail = ADC_Buffer[channel][_adc_buf_tail];
- head = ADC_Buffer[channel][_adc_buf_head];
- if (((head + 1) & (AT91_ADC_BUF_SIZE - 1)) != tail) {
- ADC_Buffer[channel][head] = write;
- ADC_Buffer[channel][_adc_buf_head] = (head + 1) & (AT91_ADC_BUF_SIZE - 1);
- return 0;
- }
- return 1;
- }
- /*!
- * \brief Sets the data aquisition mode for the adc
- *
- * \param mode Mode to set
- */
- void ADCSetMode(TADCMode mode)
- {
- uint32_t regval;
- regval = inr(ADC_MR);
- regval &= ~ADC_SLEEP;
- switch (mode) {
- case ADC_OFF:
- regval &= ~ADC_TRGEN;
- regval |= ADC_SLEEP;
- break;
- case SINGLE_CONVERSION:
- regval &= ~ADC_TRGEN;
- break;
- case FREE_RUNNING_T0:
- regval &= ~ADC_TRGSEL;
- regval |= ADC_TRGEN | ADC_TRGSEL_TIOA0;
- break;
- case FREE_RUNNING_T1:
- regval &= ~ADC_TRGSEL;
- regval |= ADC_TRGEN | ADC_TRGSEL_TIOA1;
- break;
- case FREE_RUNNING_T2:
- regval &= ~ADC_TRGSEL;
- regval |= ADC_TRGEN | ADC_TRGSEL_TIOA2;
- break;
- case FREE_RUNNING_EXT:
- regval &= ~ADC_TRGSEL;
- regval |= ADC_TRGEN | ADC_TRGSEL_EXT;
- break;
- }
- outr(ADC_MR, regval);
- }
- /*!
- * \brief Enable a channel used to sample when conversion started
- *
- * \param channel Specifies the channel to enable
- */
- void ADCEnableChannel(TADCChannel channel)
- {
- uint32_t adc_chsr;
- register int idx;
- register int max = channel;
- outr(ADC_CHER, _BV(channel));
- adc_chsr = inr(ADC_CHSR);
- /* Search the highest numbered channel which is enabled */
- for (idx = 0; idx < 8; idx ++) {
- if (adc_chsr & _BV(idx)) max = idx;
- }
- /* Disable EOC for all channels */
- outr(ADC_IDR, 0x000000FF);
- /* Enable EOC for highest numbered channel */
- outr(ADC_IER, _BV(max));
- }
- /*!
- * \brief Disable a channel.
- *
- * \param channel Specifies the channel to disable
- */
- void ADCDisableChannel(TADCChannel channel)
- {
- outr(ADC_CHDR, _BV(channel));
- outr(ADC_IDR, _BV(channel));
- }
- /*!
- * \brief Set the prescaler for the adc
- *
- * \param prescale Prescaler value 0-128
- */
- void ADCSetPrescale(uint32_t prescale)
- {
- if (prescale > 128) prescale = 128;
- prescale = (prescale / 2) - 1;
- outr(ADC_MR, ((inr(ADC_MR) & ~(ADC_PRESCAL | ADC_STARTUP | ADC_SHTIM)) |
- (prescale << ADC_PRESCAL_LSB) | ADC_STARTUP | ADC_SHTIM)); // set maximum sample & hold and startup time
- }
- /*!
- * \brief Start conversion
- */
- void ADCStartConversion(void)
- {
- outr(ADC_CR, ADC_START);
- }
- /*
- * ADC interrupt handler.
- */
- static void ADCInterrupt(void *arg)
- {
- register uint32_t adcsr = inr(ADC_SR) & inr(ADC_CHSR);
- uint16_t ADC_Value;
- uint16_t channel;
- for (channel = 0; channel < ADC_MAX_CHANNEL; channel ++) {
- if (adcsr & _BV(channel)) {
- ADC_Value = inr(ADC_CDR(channel));
- if (ADCBufWrite(channel, ADC_Value) != 0) {
- // Send error message
- }
- }
- }
- }
- /*!
- * \brief Initialize the adc to the configured default values and enable interrupt
- */
- void ADCInit(void)
- {
- int channel;
- /* Only init once */
- if (ADC_Buffer) return;
- /* Enable clock int PMC and reset ADC */
- outr(PMC_PCER, _BV(ADC_ID)); // Enable ADC clock in PMC
- outr(ADC_CR, ADC_SWRST); // Reset bus
- outr(ADC_CR, 0x00);
- /* Basic configuration: Disable all channels and set mode and prescaler */
- outr(ADC_CHDR, ADC_CH0 | ADC_CH1 | ADC_CH2 | ADC_CH3 | ADC_CH4 | ADC_CH5 | ADC_CH6 | ADC_CH7);
- ADCSetMode(AT91_ADC_INITIAL_MODE);
- ADCSetPrescale(AT91_ADC_INITIAL_PRESCALE);
- /* Init adc buffers. One for every channel as we can sample all by automatic sequence */
- ADC_Buffer = NutHeapAlloc(sizeof(uint16_t *) * ADC_MAX_CHANNEL);
- for (channel = 0; channel < ADC_MAX_CHANNEL; channel ++) {
- ADC_Buffer[channel] = NutHeapAlloc(sizeof(uint16_t) * AT91_ADC_BUF_SIZE + 2);
- ADC_Buffer[channel][_adc_buf_head] = 0;
- ADC_Buffer[channel][_adc_buf_tail] = 0;
- }
- if (NutRegisterIrqHandler(&sig_ADC, ADCInterrupt, NULL)) {
- // We do not free buffer as this would cost ROM and is not likely
- return;
- }
- NutIrqEnable(&sig_ADC);
- }
- /*@}*/
|