adc.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. /*
  2. * File : adc.c
  3. * This file is part of RT-Thread RTOS
  4. * COPYRIGHT (C) 2006 - 2017, RT-Thread Development Team
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License along
  17. * with this program; if not, write to the Free Software Foundation, Inc.,
  18. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  19. *
  20. * Change Logs:
  21. * Date Author Notes
  22. * 2017-09-18 Haley the first version
  23. */
  24. #include <rtthread.h>
  25. #include <rtdevice.h>
  26. #include "am_mcu_apollo.h"
  27. #ifdef RT_USING_ADC
  28. /* messagequeue define */
  29. struct rt_messagequeue adcbat_mq;
  30. #define BATTERY_GPIO 35 /* Battery */
  31. #define BATTERY_ADC_PIN AM_HAL_PIN_35_ADCSE7
  32. #define BATTERY_ADC_CHANNEL AM_HAL_ADC_SLOT_CHSEL_SE7 /* BATTERY ADC采集通道 */
  33. #define BATTERY_ADC_CHANNELNUM 7 /* BATTERY ADC采集通道号 */
  34. #define ADC_CTIMER_NUM 3 /* ADC使用定时器 */
  35. #define ADC_CTIMER_COUNT (2048/512 - 1)
  36. #define ADC_CHANNEL_NUM 1 /* ADC采集通道个数 */
  37. #define ADC_SAMPLE_NUM 8 /* ADC采样个数 */
  38. rt_uint8_t bat_adc_cnt = 0;
  39. static rt_uint8_t am_adcbat_buffer_pool[256];
  40. static rt_int16_t am_adcbat_buffertemp[32];
  41. rt_uint8_t am_adc_data_get(rt_uint8_t channel, rt_int16_t *buff, rt_uint16_t size)
  42. {
  43. rt_uint8_t adc_bufftemp[32];
  44. if (channel == BATTERY_ADC_CHANNELNUM)
  45. {
  46. /* wait adc message forever */
  47. rt_mq_recv(&adcbat_mq, adc_bufftemp, 32, RT_WAITING_FOREVER);
  48. }
  49. /* copy the data */
  50. rt_memcpy(buff, adc_bufftemp, size*sizeof(rt_int16_t));
  51. return 0;
  52. }
  53. void am_adc_start(rt_uint8_t channel)
  54. {
  55. /* messagequeue init */
  56. rt_mq_init(&adcbat_mq, "mq_adcbat",
  57. &am_adcbat_buffer_pool[0],
  58. 32 - sizeof(void*),
  59. sizeof(am_adcbat_buffer_pool),
  60. RT_IPC_FLAG_FIFO);
  61. /* Start the ctimer */
  62. am_hal_ctimer_start(ADC_CTIMER_NUM, AM_HAL_CTIMER_TIMERA);
  63. /* Trigger the ADC once */
  64. am_hal_adc_trigger();
  65. }
  66. void am_adc_stop(rt_uint8_t channel)
  67. {
  68. /* Stop the ctimer */
  69. am_hal_ctimer_stop(ADC_CTIMER_NUM, AM_HAL_CTIMER_TIMERA);
  70. /* messagequeue delete */
  71. rt_mq_delete(&adceeg_mq);
  72. /* messagequeue delete */
  73. rt_mq_delete(&adcbat_mq);
  74. }
  75. /**
  76. * @brief Interrupt handler for the ADC
  77. *
  78. * This function is Interrupt handler for the ADC
  79. *
  80. * @return None.
  81. */
  82. void am_adc_isr(void)
  83. {
  84. uint32_t ui32Status, ui32FifoData;
  85. /* enter interrupt */
  86. rt_interrupt_enter();
  87. /* Read the interrupt status */
  88. ui32Status = am_hal_adc_int_status_get(true);
  89. /* Clear the ADC interrupt */
  90. am_hal_adc_int_clear(ui32Status);
  91. /* If we got a FIFO 75% full (which should be our only ADC interrupt), go ahead and read the data */
  92. if (ui32Status & AM_HAL_ADC_INT_FIFOOVR1)
  93. {
  94. do
  95. {
  96. /* Read the value from the FIFO into the circular buffer */
  97. ui32FifoData = am_hal_adc_fifo_pop();
  98. if (AM_HAL_ADC_FIFO_SLOT(ui32FifoData) == BATTERY_ADC_CHANNELNUM)
  99. {
  100. am_adcbat_buffertemp[bat_adc_cnt++] = AM_HAL_ADC_FIFO_SAMPLE(ui32FifoData);
  101. }
  102. if ((bat_adc_cnt > ADC_SAMPLE_NUM + 2 - 1))
  103. {
  104. bat_adc_cnt = 0;
  105. /* send the message */
  106. rt_mq_send(&adcbat_mq, am_adcbat_buffertemp, ADC_SAMPLE_NUM*sizeof(rt_int16_t));
  107. }
  108. } while (AM_HAL_ADC_FIFO_COUNT(ui32FifoData) > 0);
  109. }
  110. /* leave interrupt */
  111. rt_interrupt_leave();
  112. }
  113. static void timerA3_for_adc_init(void)
  114. {
  115. /* Start a timer to trigger the ADC periodically (1 second) */
  116. am_hal_ctimer_config_single(ADC_CTIMER_NUM, AM_HAL_CTIMER_TIMERA,
  117. AM_HAL_CTIMER_XT_2_048KHZ |
  118. AM_HAL_CTIMER_FN_REPEAT |
  119. AM_HAL_CTIMER_INT_ENABLE |
  120. AM_HAL_CTIMER_PIN_ENABLE);
  121. am_hal_ctimer_int_enable(AM_HAL_CTIMER_INT_TIMERA3);
  122. /* Set 512 sample rate */
  123. am_hal_ctimer_period_set(ADC_CTIMER_NUM, AM_HAL_CTIMER_TIMERA, ADC_CTIMER_COUNT, 1);
  124. /* Enable the timer A3 to trigger the ADC directly */
  125. am_hal_ctimer_adc_trigger_enable();
  126. /* Start the timer */
  127. //am_hal_ctimer_start(ADC_CTIMER_NUM, AM_HAL_CTIMER_TIMERA);
  128. }
  129. /**
  130. * @brief Initialize the ADC
  131. *
  132. * This function initialize the ADC
  133. *
  134. * @return None.
  135. */
  136. int rt_hw_adc_init(void)
  137. {
  138. am_hal_adc_config_t sADCConfig;
  139. /* timer for adc init*/
  140. timerA3_for_adc_init();
  141. /* Set a pin to act as our ADC input */
  142. am_hal_gpio_pin_config(BATTERY_GPIO, BATTERY_ADC_PIN);
  143. /* Enable interrupts */
  144. am_hal_interrupt_enable(AM_HAL_INTERRUPT_ADC);
  145. /* Enable the ADC power domain */
  146. am_hal_pwrctrl_periph_enable(AM_HAL_PWRCTRL_ADC);
  147. /* Set up the ADC configuration parameters. These settings are reasonable
  148. for accurate measurements at a low sample rate */
  149. sADCConfig.ui32Clock = AM_HAL_ADC_CLOCK_HFRC;
  150. sADCConfig.ui32TriggerConfig = AM_HAL_ADC_TRIGGER_SOFT;
  151. sADCConfig.ui32Reference = AM_HAL_ADC_REF_INT_2P0;
  152. sADCConfig.ui32ClockMode = AM_HAL_ADC_CK_LOW_POWER;
  153. sADCConfig.ui32PowerMode = AM_HAL_ADC_LPMODE_0;
  154. sADCConfig.ui32Repeat = AM_HAL_ADC_REPEAT;
  155. am_hal_adc_config(&sADCConfig);
  156. /* For this example, the samples will be coming in slowly. This means we
  157. can afford to wake up for every conversion */
  158. am_hal_adc_int_enable(AM_HAL_ADC_INT_FIFOOVR1);
  159. /* Set up an ADC slot */
  160. am_hal_adc_slot_config(BATTERY_ADC_CHANNELNUM, AM_HAL_ADC_SLOT_AVG_1 |
  161. AM_HAL_ADC_SLOT_14BIT |
  162. BATTERY_ADC_CHANNEL |
  163. AM_HAL_ADC_SLOT_ENABLE);
  164. /* Enable the ADC */
  165. am_hal_adc_enable();
  166. /* Trigger the ADC once */
  167. //am_hal_adc_trigger();
  168. //rt_kprintf("adc_init!\n");
  169. return 0;
  170. }
  171. #ifdef RT_USING_COMPONENTS_INIT
  172. INIT_BOARD_EXPORT(rt_hw_adc_init);
  173. #endif
  174. #endif
  175. /*@}*/