drv_adc.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. /*
  2. * Copyright (c) 2006-2022, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2022-03-04 stevetong459 first version
  9. * 2022-07-15 Aligagago add apm32F4 serie MCU support
  10. */
  11. #include <board.h>
  12. #if defined(BSP_USING_ADC1) || defined(BSP_USING_ADC2) || defined(BSP_USING_ADC3)
  13. //#define DRV_DEBUG
  14. #define LOG_TAG "drv.adc"
  15. #define DBG_LVL DBG_INFO
  16. #include <rtdbg.h>
  17. #define DRV_ADC_CHANNEL_MAX_NUM 14
  18. #define DRV_ADC_TIME_OUT 0xFFF
  19. #define _ADC_GET_PORT(pin_num) ((GPIO_T *)(GPIOA_BASE + (0x400u * (((pin_num) >> 4) & 0xFu))))
  20. #define _ADC_GET_PIN(pin_num) ((uint16_t)(1u << ((pin_num) & 0xFu)))
  21. struct apm32_adc
  22. {
  23. const char *name;
  24. ADC_T *adc;
  25. ADC_Config_T adc_config;
  26. rt_base_t channel_pin[DRV_ADC_CHANNEL_MAX_NUM];
  27. struct rt_adc_device adc_dev;
  28. };
  29. #ifdef APM32F10X_HD
  30. static struct apm32_adc adc_config[] =
  31. {
  32. #ifdef BSP_USING_ADC1
  33. {
  34. "adc1",
  35. ADC1,
  36. {
  37. ADC_MODE_INDEPENDENT,
  38. DISABLE,
  39. DISABLE,
  40. ADC_EXT_TRIG_CONV_None,
  41. ADC_DATA_ALIGN_RIGHT,
  42. 1
  43. },
  44. {
  45. GET_PIN(A, 0), GET_PIN(A, 1), GET_PIN(A, 2), GET_PIN(A, 3), GET_PIN(A, 4),
  46. GET_PIN(A, 5), GET_PIN(A, 6), GET_PIN(A, 7), GET_PIN(B, 0), GET_PIN(B, 1),
  47. GET_PIN(C, 0), GET_PIN(C, 1), GET_PIN(C, 2), GET_PIN(C, 3)
  48. },
  49. RT_NULL
  50. },
  51. #endif
  52. #ifdef BSP_USING_ADC2
  53. {
  54. "adc2",
  55. ADC2,
  56. {
  57. ADC_MODE_INDEPENDENT,
  58. DISABLE,
  59. DISABLE,
  60. ADC_EXT_TRIG_CONV_None,
  61. ADC_DATA_ALIGN_RIGHT,
  62. 1
  63. },
  64. {
  65. GET_PIN(A, 0), GET_PIN(A, 1), GET_PIN(A, 2), GET_PIN(A, 3), GET_PIN(A, 4),
  66. GET_PIN(A, 5), GET_PIN(A, 6), GET_PIN(A, 7), GET_PIN(B, 0), GET_PIN(B, 1),
  67. GET_PIN(C, 0), GET_PIN(C, 1), GET_PIN(C, 2), GET_PIN(C, 3)
  68. },
  69. RT_NULL
  70. },
  71. #endif
  72. #ifdef BSP_USING_ADC3
  73. {
  74. "adc3",
  75. ADC3,
  76. {
  77. ADC_MODE_INDEPENDENT,
  78. DISABLE,
  79. DISABLE,
  80. ADC_EXT_TRIG_CONV_None,
  81. ADC_DATA_ALIGN_RIGHT,
  82. 1
  83. },
  84. {
  85. GET_PIN(A, 0), GET_PIN(A, 1), GET_PIN(A, 2), GET_PIN(A, 3), GET_PIN(F, 6),
  86. GET_PIN(F, 7), GET_PIN(F, 8), GET_PIN(F, 9), GET_PIN(F, 10)
  87. },
  88. RT_NULL
  89. },
  90. #endif
  91. };
  92. #elif APM32F40X
  93. static struct apm32_adc adc_config[] =
  94. {
  95. #ifdef BSP_USING_ADC1
  96. {
  97. "adc1",
  98. ADC1,
  99. {
  100. ADC_RESOLUTION_12BIT,
  101. DISABLE,
  102. DISABLE,
  103. ADC_EXT_TRIG_EDGE_NONE,
  104. ADC_EXT_TRIG_CONV_TMR1_CC1,
  105. ADC_DATA_ALIGN_RIGHT,
  106. 1
  107. },
  108. {
  109. GET_PIN(A, 0), GET_PIN(A, 1), GET_PIN(A, 2), GET_PIN(A, 3), GET_PIN(A, 4),
  110. GET_PIN(A, 5), GET_PIN(A, 6), GET_PIN(A, 7), GET_PIN(B, 0), GET_PIN(B, 1),
  111. GET_PIN(C, 0), GET_PIN(C, 1), GET_PIN(C, 2), GET_PIN(C, 3)
  112. },
  113. RT_NULL
  114. },
  115. #endif
  116. #ifdef BSP_USING_ADC2
  117. {
  118. "adc2",
  119. ADC2,
  120. {
  121. ADC_RESOLUTION_12BIT,
  122. DISABLE,
  123. DISABLE,
  124. ADC_EXT_TRIG_EDGE_NONE,
  125. ADC_EXT_TRIG_CONV_TMR1_CC1,
  126. ADC_DATA_ALIGN_RIGHT,
  127. 1
  128. },
  129. {
  130. GET_PIN(A, 0), GET_PIN(A, 1), GET_PIN(A, 2), GET_PIN(A, 3), GET_PIN(A, 4),
  131. GET_PIN(A, 5), GET_PIN(A, 6), GET_PIN(A, 7), GET_PIN(B, 0), GET_PIN(B, 1),
  132. GET_PIN(C, 0), GET_PIN(C, 1), GET_PIN(C, 2), GET_PIN(C, 3)
  133. },
  134. RT_NULL
  135. },
  136. #endif
  137. #ifdef BSP_USING_ADC3
  138. {
  139. "adc3",
  140. ADC3,
  141. {
  142. ADC_RESOLUTION_12BIT,
  143. DISABLE,
  144. DISABLE,
  145. ADC_EXT_TRIG_EDGE_NONE,
  146. ADC_EXT_TRIG_CONV_TMR1_CC1,
  147. ADC_DATA_ALIGN_RIGHT,
  148. 1
  149. },
  150. {
  151. GET_PIN(A, 0), GET_PIN(A, 1), GET_PIN(A, 2), GET_PIN(A, 3), GET_PIN(F, 6),
  152. GET_PIN(F, 7), GET_PIN(F, 8), GET_PIN(F, 9), GET_PIN(F, 10), GET_PIN(F, 3),
  153. GET_PIN(C, 0), GET_PIN(C, 1), GET_PIN(C, 2), GET_PIN(C, 3)
  154. },
  155. RT_NULL
  156. },
  157. #endif
  158. };
  159. #endif
  160. static rt_err_t _adc_channel_check(struct rt_adc_device *device, rt_uint32_t channel)
  161. {
  162. struct apm32_adc *adc_cfg = ((struct apm32_adc *)device->parent.user_data);
  163. #ifdef APM32F10X_HD
  164. if (adc_cfg->adc == ADC3)
  165. {
  166. if (channel <= 8)
  167. {
  168. return RT_EOK;
  169. }
  170. }
  171. else
  172. {
  173. if (channel <= 13)
  174. {
  175. return RT_EOK;
  176. }
  177. }
  178. #elif APM32F40X
  179. if (channel <= 13)
  180. {
  181. return RT_EOK;
  182. }
  183. #endif
  184. LOG_E("channel %d of %s is not supported.", channel, adc_cfg->name);
  185. return -RT_ERROR;
  186. }
  187. static rt_err_t _adc_gpio_init(struct rt_adc_device *device, rt_uint32_t channel)
  188. {
  189. struct apm32_adc *adc_cfg = ((struct apm32_adc *)device->parent.user_data);
  190. GPIO_Config_T hw_gpio_config;
  191. if (_adc_channel_check(device, channel) != RT_EOK)
  192. {
  193. return -RT_ERROR;
  194. }
  195. #ifdef APM32F10X_HD
  196. RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOA << ((adc_cfg->channel_pin[channel] >> 4) & 0xFu));
  197. hw_gpio_config.mode = GPIO_MODE_ANALOG;
  198. #elif APM32F40X
  199. RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_GPIOA << ((adc_cfg->channel_pin[channel] >> 4) & 0xFu));
  200. hw_gpio_config.mode = GPIO_MODE_AN;
  201. #endif
  202. hw_gpio_config.pin = _ADC_GET_PIN(adc_cfg->channel_pin[channel]);
  203. GPIO_Config(_ADC_GET_PORT(adc_cfg->channel_pin[channel]), &hw_gpio_config);
  204. return RT_EOK;
  205. }
  206. /**
  207. * @brief This function will control the adc to enable or disable.
  208. *
  209. * @param device is a pointer to adc device.
  210. *
  211. * @param channel is the adc channel.
  212. *
  213. * @param enabled is the status to indicate enable or disable.
  214. *
  215. * @return RT_EOK indicates successful enable or disable adc, other value indicates failed.
  216. */
  217. static rt_err_t _adc_enabled(struct rt_adc_device *device, rt_uint32_t channel, rt_bool_t enabled)
  218. {
  219. struct apm32_adc *adc_cfg = ((struct apm32_adc *)device->parent.user_data);
  220. RT_ASSERT(device != RT_NULL);
  221. if (enabled)
  222. {
  223. if (adc_cfg->adc == ADC1)
  224. {
  225. RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_ADC1);
  226. }
  227. else if (adc_cfg->adc == ADC2)
  228. {
  229. RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_ADC2);
  230. }
  231. else
  232. {
  233. RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_ADC3);
  234. }
  235. if (_adc_gpio_init(device, channel) != RT_EOK)
  236. {
  237. return -RT_ERROR;
  238. }
  239. ADC_Config(adc_cfg->adc, &adc_cfg->adc_config);
  240. ADC_Enable(adc_cfg->adc);
  241. }
  242. else
  243. {
  244. ADC_Disable(adc_cfg->adc);
  245. }
  246. return RT_EOK;
  247. }
  248. /**
  249. * @brief This function will get the adc conversion value.
  250. *
  251. * @param device is a pointer to adc device.
  252. *
  253. * @param channel is the adc channel.
  254. *
  255. * @param value is a pointer to the adc conversion value.
  256. *
  257. * @return RT_EOK indicates successful get adc value, other value indicates failed.
  258. */
  259. static rt_err_t _adc_get_value(struct rt_adc_device *device, rt_uint32_t channel, rt_uint32_t *value)
  260. {
  261. struct apm32_adc *adc_cfg = ((struct apm32_adc *)device->parent.user_data);
  262. volatile rt_uint32_t counter = 0;
  263. RT_ASSERT(device != RT_NULL);
  264. RT_ASSERT(value != RT_NULL);
  265. if (_adc_channel_check(device, channel) != RT_EOK)
  266. {
  267. return -RT_ERROR;
  268. }
  269. #ifdef APM32F10X_HD
  270. ADC_ConfigRegularChannel(adc_cfg->adc, channel, 1, ADC_SAMPLETIME_13CYCLES5);
  271. ADC_StartCalibration(adc_cfg->adc);
  272. /* Check the end of ADC calibration */
  273. while (ADC_ReadCalibrationStartFlag(adc_cfg->adc))
  274. {
  275. if (++counter > DRV_ADC_TIME_OUT)
  276. {
  277. return RT_ETIMEOUT;
  278. }
  279. }
  280. ADC_EnableSoftwareStartConv(adc_cfg->adc);
  281. #elif APM32F40X
  282. ADC_ConfigRegularChannel(adc_cfg->adc, channel, 1, ADC_SAMPLETIME_15CYCLES);
  283. ADC_SoftwareStartConv(adc_cfg->adc);
  284. #endif
  285. counter = 0;
  286. while (!ADC_ReadStatusFlag(adc_cfg->adc, ADC_FLAG_EOC))
  287. {
  288. if (++counter > DRV_ADC_TIME_OUT)
  289. {
  290. return RT_ETIMEOUT;
  291. }
  292. }
  293. *value = ADC_ReadConversionValue(adc_cfg->adc);
  294. return RT_EOK;
  295. }
  296. static const struct rt_adc_ops _adc_ops =
  297. {
  298. .enabled = _adc_enabled,
  299. .convert = _adc_get_value,
  300. };
  301. /**
  302. * @brief ADC initialization function.
  303. *
  304. * @return RT_EOK indicates successful initialization, other value indicates failed;
  305. */
  306. static int rt_hw_adc_init(void)
  307. {
  308. rt_err_t result = RT_EOK;
  309. rt_size_t obj_num = sizeof(adc_config) / sizeof(struct apm32_adc);
  310. rt_uint32_t i = 0;
  311. for (i = 0; i < obj_num; i++)
  312. {
  313. /* register ADC device */
  314. if (rt_hw_adc_register(&adc_config[i].adc_dev, adc_config[i].name, &_adc_ops, adc_config))
  315. {
  316. LOG_D("%s init success", adc_config[i].name);
  317. }
  318. else
  319. {
  320. LOG_D("%s init failed", adc_config[i].name);
  321. result = -RT_ERROR;
  322. }
  323. }
  324. return result;
  325. }
  326. INIT_BOARD_EXPORT(rt_hw_adc_init);
  327. #endif /* BSP_USING_ADCX */