at91_adc.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. /*
  2. * Copyright (C) 2001-2005 by EmbeddedIT,
  3. * Ole Reinhardt <ole.reinhardt@embedded-it.de> All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. *
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * 3. Neither the name of the copyright holders nor the names of
  15. * contributors may be used to endorse or promote products derived
  16. * from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY EMBEDDED IT AND CONTRIBUTORS
  19. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  21. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EMBEDDED IT
  22. * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  23. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  24. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  25. * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  26. * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  27. * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  28. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. *
  30. * For additional information see http://www.ethernut.de/
  31. *
  32. */
  33. /*
  34. * $Log$
  35. * Revision 1.4 2009/01/17 11:26:37 haraldkipp
  36. * Getting rid of two remaining BSD types in favor of stdint.
  37. * Replaced 'u_int' by 'unsinged int' and 'uptr_t' by 'uintptr_t'.
  38. *
  39. * Revision 1.3 2008/08/11 06:59:03 haraldkipp
  40. * BSD types replaced by stdint types (feature request #1282721).
  41. *
  42. * Revision 1.2 2007/12/09 22:13:08 olereinhardt
  43. * Added cvs log tag
  44. *
  45. */
  46. #include <arch/arm.h>
  47. #include <dev/irqreg.h>
  48. #include <sys/event.h>
  49. #include <sys/atom.h>
  50. #include <sys/timer.h>
  51. #include <sys/thread.h>
  52. #include <sys/heap.h>
  53. #include <dev/irqreg.h>
  54. #include <dev/at91_adc.h>
  55. /*!
  56. * \addtogroup xgNutArchArmAt91Adc
  57. */
  58. /*@{*/
  59. #ifndef AT91_ADC_INITIAL_MODE
  60. #define AT91_ADC_INITIAL_MODE SINGLE_CONVERSION
  61. #endif
  62. #ifndef AT91_ADC_INITIAL_PRESCALE
  63. #define AT91_ADC_INITIAL_PRESCALE 55
  64. #endif
  65. #define AT91_ADC_BUF_SIZE 16 // this may only be a power of two
  66. #define _adc_buf_head AT91_ADC_BUF_SIZE
  67. #define _adc_buf_tail AT91_ADC_BUF_SIZE+1
  68. uint16_t **ADC_Buffer = NULL;
  69. /*!
  70. * \brief Reads data from the adc buffer
  71. *
  72. * \param channel Specifies the channel to read data from
  73. * \param read Variable to store the data in
  74. * \return 0: data read succesfully, 1: no data available
  75. */
  76. int ADCBufRead(uint16_t channel, uint16_t * read)
  77. {
  78. uint16_t tail, head;
  79. tail = ADC_Buffer[channel][_adc_buf_tail];
  80. head = ADC_Buffer[channel][_adc_buf_head];
  81. if (head != tail) {
  82. *read = ADC_Buffer[channel][tail];
  83. ADC_Buffer[channel][_adc_buf_tail] = (tail + 1) & (AT91_ADC_BUF_SIZE - 1);
  84. return 0;
  85. }
  86. return 1;
  87. }
  88. /* Store data in the buffer, called from interrupt */
  89. static inline int ADCBufWrite(uint16_t channel, uint16_t write)
  90. {
  91. uint16_t tail, head;
  92. tail = ADC_Buffer[channel][_adc_buf_tail];
  93. head = ADC_Buffer[channel][_adc_buf_head];
  94. if (((head + 1) & (AT91_ADC_BUF_SIZE - 1)) != tail) {
  95. ADC_Buffer[channel][head] = write;
  96. ADC_Buffer[channel][_adc_buf_head] = (head + 1) & (AT91_ADC_BUF_SIZE - 1);
  97. return 0;
  98. }
  99. return 1;
  100. }
  101. /*!
  102. * \brief Sets the data aquisition mode for the adc
  103. *
  104. * \param mode Mode to set
  105. */
  106. void ADCSetMode(TADCMode mode)
  107. {
  108. uint32_t regval;
  109. regval = inr(ADC_MR);
  110. regval &= ~ADC_SLEEP;
  111. switch (mode) {
  112. case ADC_OFF:
  113. regval &= ~ADC_TRGEN;
  114. regval |= ADC_SLEEP;
  115. break;
  116. case SINGLE_CONVERSION:
  117. regval &= ~ADC_TRGEN;
  118. break;
  119. case FREE_RUNNING_T0:
  120. regval &= ~ADC_TRGSEL;
  121. regval |= ADC_TRGEN | ADC_TRGSEL_TIOA0;
  122. break;
  123. case FREE_RUNNING_T1:
  124. regval &= ~ADC_TRGSEL;
  125. regval |= ADC_TRGEN | ADC_TRGSEL_TIOA1;
  126. break;
  127. case FREE_RUNNING_T2:
  128. regval &= ~ADC_TRGSEL;
  129. regval |= ADC_TRGEN | ADC_TRGSEL_TIOA2;
  130. break;
  131. case FREE_RUNNING_EXT:
  132. regval &= ~ADC_TRGSEL;
  133. regval |= ADC_TRGEN | ADC_TRGSEL_EXT;
  134. break;
  135. }
  136. outr(ADC_MR, regval);
  137. }
  138. /*!
  139. * \brief Enable a channel used to sample when conversion started
  140. *
  141. * \param channel Specifies the channel to enable
  142. */
  143. void ADCEnableChannel(TADCChannel channel)
  144. {
  145. uint32_t adc_chsr;
  146. register int idx;
  147. register int max = channel;
  148. outr(ADC_CHER, _BV(channel));
  149. adc_chsr = inr(ADC_CHSR);
  150. /* Search the highest numbered channel which is enabled */
  151. for (idx = 0; idx < 8; idx ++) {
  152. if (adc_chsr & _BV(idx)) max = idx;
  153. }
  154. /* Disable EOC for all channels */
  155. outr(ADC_IDR, 0x000000FF);
  156. /* Enable EOC for highest numbered channel */
  157. outr(ADC_IER, _BV(max));
  158. }
  159. /*!
  160. * \brief Disable a channel.
  161. *
  162. * \param channel Specifies the channel to disable
  163. */
  164. void ADCDisableChannel(TADCChannel channel)
  165. {
  166. outr(ADC_CHDR, _BV(channel));
  167. outr(ADC_IDR, _BV(channel));
  168. }
  169. /*!
  170. * \brief Set the prescaler for the adc
  171. *
  172. * \param prescale Prescaler value 0-128
  173. */
  174. void ADCSetPrescale(uint32_t prescale)
  175. {
  176. if (prescale > 128) prescale = 128;
  177. prescale = (prescale / 2) - 1;
  178. outr(ADC_MR, ((inr(ADC_MR) & ~(ADC_PRESCAL | ADC_STARTUP | ADC_SHTIM)) |
  179. (prescale << ADC_PRESCAL_LSB) | ADC_STARTUP | ADC_SHTIM)); // set maximum sample & hold and startup time
  180. }
  181. /*!
  182. * \brief Start conversion
  183. */
  184. void ADCStartConversion(void)
  185. {
  186. outr(ADC_CR, ADC_START);
  187. }
  188. /*
  189. * ADC interrupt handler.
  190. */
  191. static void ADCInterrupt(void *arg)
  192. {
  193. register uint32_t adcsr = inr(ADC_SR) & inr(ADC_CHSR);
  194. uint16_t ADC_Value;
  195. uint16_t channel;
  196. for (channel = 0; channel < ADC_MAX_CHANNEL; channel ++) {
  197. if (adcsr & _BV(channel)) {
  198. ADC_Value = inr(ADC_CDR(channel));
  199. if (ADCBufWrite(channel, ADC_Value) != 0) {
  200. // Send error message
  201. }
  202. }
  203. }
  204. }
  205. /*!
  206. * \brief Initialize the adc to the configured default values and enable interrupt
  207. */
  208. void ADCInit(void)
  209. {
  210. int channel;
  211. /* Only init once */
  212. if (ADC_Buffer) return;
  213. /* Enable clock int PMC and reset ADC */
  214. outr(PMC_PCER, _BV(ADC_ID)); // Enable ADC clock in PMC
  215. outr(ADC_CR, ADC_SWRST); // Reset bus
  216. outr(ADC_CR, 0x00);
  217. /* Basic configuration: Disable all channels and set mode and prescaler */
  218. outr(ADC_CHDR, ADC_CH0 | ADC_CH1 | ADC_CH2 | ADC_CH3 | ADC_CH4 | ADC_CH5 | ADC_CH6 | ADC_CH7);
  219. ADCSetMode(AT91_ADC_INITIAL_MODE);
  220. ADCSetPrescale(AT91_ADC_INITIAL_PRESCALE);
  221. /* Init adc buffers. One for every channel as we can sample all by automatic sequence */
  222. ADC_Buffer = NutHeapAlloc(sizeof(uint16_t *) * ADC_MAX_CHANNEL);
  223. for (channel = 0; channel < ADC_MAX_CHANNEL; channel ++) {
  224. ADC_Buffer[channel] = NutHeapAlloc(sizeof(uint16_t) * AT91_ADC_BUF_SIZE + 2);
  225. ADC_Buffer[channel][_adc_buf_head] = 0;
  226. ADC_Buffer[channel][_adc_buf_tail] = 0;
  227. }
  228. if (NutRegisterIrqHandler(&sig_ADC, ADCInterrupt, NULL)) {
  229. // We do not free buffer as this would cost ROM and is not likely
  230. return;
  231. }
  232. NutIrqEnable(&sig_ADC);
  233. }
  234. /*@}*/