drv_adc.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. /**************************************************************************//**
  2. * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2020-12-12 Wayne First version
  9. *
  10. ******************************************************************************/
  11. #include <rtconfig.h>
  12. #if defined(BSP_USING_ADC)
  13. #include <rtdevice.h>
  14. #include "NuMicro.h"
  15. #include <drv_sys.h>
  16. /* Private define ---------------------------------------------------------------*/
  17. /* Private Typedef --------------------------------------------------------------*/
  18. struct nu_adc
  19. {
  20. struct rt_adc_device dev;
  21. char *name;
  22. uint32_t OpFreqKHz;
  23. IRQn_Type irqn;
  24. E_SYS_IPRST rstidx;
  25. E_SYS_IPCLK clkidx;
  26. int chn_num;
  27. uint32_t chn_mask;
  28. rt_sem_t m_psSem;
  29. };
  30. typedef struct nu_adc *nu_adc_t;
  31. /* Private functions ------------------------------------------------------------*/
  32. static rt_err_t nu_adc_enabled(struct rt_adc_device *device, rt_uint32_t channel, rt_bool_t enabled);
  33. static rt_err_t nu_adc_convert(struct rt_adc_device *device, rt_uint32_t channel, rt_uint32_t *value);
  34. /* Public functions ------------------------------------------------------------*/
  35. int rt_hw_adc_init(void);
  36. /* Private variables ------------------------------------------------------------*/
  37. static struct nu_adc g_sNuADC =
  38. {
  39. .name = "adc",
  40. .OpFreqKHz = 4000, /* 1000 <= OpFreqKHz <= 4000 */
  41. .chn_num = 8,
  42. .irqn = IRQ_ADC,
  43. .rstidx = ADCRST,
  44. .clkidx = ADCCKEN,
  45. .chn_mask = 0
  46. };
  47. static void nu_adc_isr(int vector, void *param)
  48. {
  49. uint32_t isr, conf;
  50. nu_adc_t psNuAdc = (nu_adc_t)param;
  51. conf = inpw(REG_ADC_CONF);
  52. isr = inpw(REG_ADC_ISR);
  53. if ((isr & ADC_ISR_NACF) && (conf & ADC_CONF_NACEN))
  54. {
  55. outpw(REG_ADC_ISR, ADC_ISR_NACF);
  56. }
  57. if (isr & ADC_ISR_MF)
  58. {
  59. rt_err_t result;
  60. outpw(REG_ADC_ISR, ADC_ISR_MF);
  61. result = rt_sem_release(psNuAdc->m_psSem);
  62. RT_ASSERT(result == RT_EOK);
  63. }
  64. }
  65. static rt_err_t _nu_adc_init(rt_device_t dev)
  66. {
  67. uint32_t div;
  68. nu_adc_t psNuAdc = (nu_adc_t)dev;
  69. /* ADC Engine Clock is set to freq Khz */
  70. if (psNuAdc->OpFreqKHz > 4000) psNuAdc->OpFreqKHz = 4000;
  71. if (psNuAdc->OpFreqKHz < 1000) psNuAdc->OpFreqKHz = 1000;
  72. div = 12000 / psNuAdc->OpFreqKHz;
  73. outpw(REG_CLK_DIVCTL7, inpw(REG_CLK_DIVCTL7) & ~((0x3 << 19) | (0x7 << 16) | (0xFFul << 24)));
  74. outpw(REG_CLK_DIVCTL7, (0 << 19) | (0 << 16) | ((div - 1) << 24));
  75. /* Install interrupt service routine */
  76. rt_hw_interrupt_install(psNuAdc->irqn, nu_adc_isr, (void *)psNuAdc, psNuAdc->name);
  77. return RT_EOK;
  78. }
  79. static rt_err_t _nu_adc_control(rt_device_t dev, int cmd, void *args)
  80. {
  81. rt_err_t ret = RT_EINVAL ;
  82. nu_adc_t psNuAdc = (nu_adc_t)dev;
  83. switch (cmd)
  84. {
  85. case START_MST: /* Menu Start Conversion */
  86. {
  87. /* Enable interrupt */
  88. outpw(REG_ADC_IER, inpw(REG_ADC_IER) | ADC_IER_MIEN);
  89. /* Start conversion */
  90. outpw(REG_ADC_CTL, inpw(REG_ADC_CTL) | ADC_CTL_MST);
  91. /* Wait it done */
  92. ret = rt_sem_take(psNuAdc->m_psSem, RT_WAITING_FOREVER);
  93. RT_ASSERT(ret == RT_EOK);
  94. /* Get data: valid data is 12-bit */
  95. *((uint32_t *)args) = inpw(REG_ADC_DATA) & 0x00000FFF;
  96. }
  97. break;
  98. case VBPOWER_ON: /* Enable ADC Internal Bandgap Power */
  99. {
  100. outpw(REG_ADC_CTL, inpw(REG_ADC_CTL) | ADC_CTL_VBGEN);
  101. }
  102. break;
  103. case VBPOWER_OFF: /* Disable ADC Internal Bandgap Power */
  104. {
  105. outpw(REG_ADC_CTL, inpw(REG_ADC_CTL) & ~ADC_CTL_VBGEN);
  106. }
  107. break;
  108. case NAC_ON: /* Enable Normal AD Conversion */
  109. {
  110. outpw(REG_ADC_CONF, inpw(REG_ADC_CONF) | ADC_CONF_NACEN | ADC_CONF_REFSEL_AVDD33);
  111. }
  112. break;
  113. case NAC_OFF: /* Disable Normal AD Conversion */
  114. {
  115. outpw(REG_ADC_CONF, inpw(REG_ADC_CONF) & ~ADC_CONF_NACEN);
  116. }
  117. break;
  118. case SWITCH_CH:
  119. {
  120. int chn = (int)args;
  121. if (chn >= psNuAdc->chn_num)
  122. {
  123. return -ret;
  124. }
  125. outpw(REG_ADC_CONF, (inpw(REG_ADC_CONF) & ~ADC_CONF_CHSEL_Msk) | (chn << ADC_CONF_CHSEL_Pos));
  126. }
  127. break;
  128. default:
  129. return -(ret);
  130. }
  131. return RT_EOK;
  132. }
  133. static rt_err_t _nu_adc_open(rt_device_t dev, rt_uint16_t oflag)
  134. {
  135. nu_adc_t psNuAdc = (nu_adc_t)dev;
  136. /* Enable ADC engine clock */
  137. nu_sys_ipclk_enable(psNuAdc->clkidx);
  138. /* Reset the ADC IP */
  139. nu_sys_ip_reset(psNuAdc->rstidx);
  140. /* Enable ADC Power */
  141. outpw(REG_ADC_CTL, inpw(REG_ADC_CTL) | ADC_CTL_ADEN);
  142. /* Enable ADC to high speed mode */
  143. outpw(REG_ADC_CONF, inpw(REG_ADC_CONF) | ADC_CONF_HSPEED);
  144. /* Enable interrupt */
  145. rt_hw_interrupt_umask(psNuAdc->irqn);
  146. /* Enable Normal AD Conversion */
  147. _nu_adc_control(dev, NAC_ON, RT_NULL);
  148. return RT_EOK;
  149. }
  150. static rt_err_t _nu_adc_close(rt_device_t dev)
  151. {
  152. nu_adc_t psNuAdc = (nu_adc_t)dev;
  153. /* Disable Normal AD Conversion */
  154. _nu_adc_control(dev, NAC_OFF, RT_NULL);
  155. /* Disable interrupt */
  156. rt_hw_interrupt_mask(psNuAdc->irqn);
  157. /* Disable ADC Power */
  158. outpw(REG_ADC_CTL, inpw(REG_ADC_CTL) & ~ADC_CTL_ADEN);
  159. /* Disable ADC engine clock */
  160. nu_sys_ipclk_disable(psNuAdc->clkidx);
  161. return RT_EOK;
  162. }
  163. static const struct rt_adc_ops nu_adc_ops =
  164. {
  165. nu_adc_enabled,
  166. nu_adc_convert,
  167. };
  168. /* nu_adc_enabled - Enable ADC clock and wait for ready */
  169. static rt_err_t nu_adc_enabled(struct rt_adc_device *device, rt_uint32_t channel, rt_bool_t enabled)
  170. {
  171. nu_adc_t psNuADC = (nu_adc_t)device;
  172. RT_ASSERT(device != RT_NULL);
  173. if (channel >= psNuADC->chn_num)
  174. return -(RT_EINVAL);
  175. if (enabled)
  176. {
  177. psNuADC->chn_mask |= (1 << channel);
  178. }
  179. else
  180. {
  181. psNuADC->chn_mask &= ~(1 << channel);
  182. }
  183. if (psNuADC->chn_mask > 0 && ((rt_device_t)device)->ref_count == 0)
  184. {
  185. _nu_adc_open((rt_device_t)device, 0);
  186. ((rt_device_t)device)->ref_count = 1;
  187. }
  188. else if ((psNuADC->chn_mask == 0) && ((rt_device_t)device)->ref_count == 1)
  189. {
  190. _nu_adc_close((rt_device_t)device);
  191. ((rt_device_t)device)->ref_count = 0;
  192. }
  193. return RT_EOK;
  194. }
  195. static rt_err_t nu_adc_convert(struct rt_adc_device *device, rt_uint32_t channel, rt_uint32_t *value)
  196. {
  197. rt_err_t ret = RT_EOK;
  198. nu_adc_t psNuAdc = (nu_adc_t)device;
  199. RT_ASSERT(device != RT_NULL);
  200. RT_ASSERT(value != RT_NULL);
  201. if (channel >= psNuAdc->chn_num)
  202. {
  203. ret = RT_EINVAL;
  204. goto exit_nu_adc_convert;
  205. }
  206. else if ((ret = _nu_adc_control((rt_device_t)device, SWITCH_CH, (void *)channel)) != RT_EOK)
  207. {
  208. goto exit_nu_adc_convert;
  209. }
  210. else if ((ret = _nu_adc_control((rt_device_t)device, START_MST, (void *)value)) != RT_EOK)
  211. {
  212. goto exit_nu_adc_convert;
  213. }
  214. exit_nu_adc_convert:
  215. return (-ret) ;
  216. }
  217. int rt_hw_adc_init(void)
  218. {
  219. rt_err_t result = RT_ERROR;
  220. rt_device_t psDev = &g_sNuADC.dev.parent;
  221. result = rt_hw_adc_register(&g_sNuADC.dev, g_sNuADC.name, &nu_adc_ops, &g_sNuADC);
  222. RT_ASSERT(result == RT_EOK);
  223. result = _nu_adc_init(psDev);
  224. RT_ASSERT(result == RT_EOK);
  225. g_sNuADC.m_psSem = rt_sem_create("adc_mst_sem", 0, RT_IPC_FLAG_FIFO);
  226. RT_ASSERT(g_sNuADC.m_psSem != RT_NULL);
  227. return (int)result;
  228. }
  229. INIT_BOARD_EXPORT(rt_hw_adc_init);
  230. #endif //#if defined(BSP_USING_EADC)