drv_acmp.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  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. * 2011-02-21 onelife Initial creation for EFM32
  9. * 2011-06-17 onelife Modify init and control function for efm32lib v2 upgrading
  10. */
  11. /***************************************************************************//**
  12. * @addtogroup efm32
  13. * @{
  14. ******************************************************************************/
  15. /* Includes ------------------------------------------------------------------*/
  16. #include "board.h"
  17. #include "drv_acmp.h"
  18. #if (defined(RT_USING_ACMP0) || defined(RT_USING_ACMP1))
  19. /* Private typedef -----------------------------------------------------------*/
  20. /* Private define ------------------------------------------------------------*/
  21. /* Private macro -------------------------------------------------------------*/
  22. #ifdef RT_ACMP_DEBUG
  23. #define acmp_debug(format,args...) rt_kprintf(format, ##args)
  24. #else
  25. #define acmp_debug(format,args...)
  26. #endif
  27. /* Private variables ---------------------------------------------------------*/
  28. #ifdef RT_USING_ACMP0
  29. static struct rt_device acmp0_device;
  30. #endif
  31. #ifdef RT_USING_ACMP1
  32. static struct rt_device acmp1_device;
  33. #endif
  34. /* Private function prototypes -----------------------------------------------*/
  35. ACMP_WarmTime_TypeDef efm32_acmp_WarmTimeCalc(rt_uint32_t hfperFreq);
  36. /* Private functions ---------------------------------------------------------*/
  37. /***************************************************************************//**
  38. * @brief
  39. * Initialize ACMP device
  40. *
  41. * @details
  42. *
  43. * @note
  44. *
  45. * @param[in] dev
  46. * Pointer to device descriptor
  47. *
  48. * @return
  49. * Error code
  50. ******************************************************************************/
  51. static rt_err_t rt_acmp_init(rt_device_t dev)
  52. {
  53. RT_ASSERT(dev != RT_NULL);
  54. struct efm32_acmp_device_t *acmp;
  55. acmp = (struct efm32_acmp_device_t *)(dev->user_data);
  56. acmp->hook.cbFunc = RT_NULL;
  57. acmp->hook.userPtr = RT_NULL;
  58. return RT_EOK;
  59. }
  60. /***************************************************************************//**
  61. * @brief
  62. * Configure ACMP device
  63. *
  64. * @details
  65. *
  66. * @note
  67. *
  68. * @param[in] dev
  69. * Pointer to device descriptor
  70. *
  71. * @param[in] cmd
  72. * ACMP control command
  73. *
  74. * @param[in] args
  75. * Arguments
  76. *
  77. * @return
  78. * Error code
  79. ******************************************************************************/
  80. static rt_err_t rt_acmp_control(
  81. rt_device_t dev,
  82. rt_uint8_t cmd,
  83. void *args)
  84. {
  85. RT_ASSERT(dev != RT_NULL);
  86. struct efm32_acmp_device_t *acmp;
  87. acmp = (struct efm32_acmp_device_t *)(dev->user_data);
  88. switch (cmd)
  89. {
  90. case RT_DEVICE_CTRL_SUSPEND:
  91. /* Suspend device */
  92. dev->flag |= RT_DEVICE_FLAG_SUSPENDED;
  93. ACMP_Disable(acmp->acmp_device);
  94. break;
  95. case RT_DEVICE_CTRL_RESUME:
  96. /* Resume device */
  97. dev->flag &= ~RT_DEVICE_FLAG_SUSPENDED;
  98. ACMP_Enable(acmp->acmp_device);
  99. break;
  100. case RT_DEVICE_CTRL_ACMP_INIT:
  101. {
  102. rt_bool_t int_en = false;
  103. struct efm32_acmp_control_t *control;
  104. control = (struct efm32_acmp_control_t *)args;
  105. acmp_debug("ACMP: control -> init start\n");
  106. /* Configure ACMPn */
  107. if (control->init == RT_NULL)
  108. {
  109. return -RT_ERROR;
  110. }
  111. ACMP_Init(acmp->acmp_device, control->init);
  112. ACMP_ChannelSet(acmp->acmp_device, control->negInput, control->posInput);
  113. if (control->output != RT_NULL)
  114. {
  115. ACMP_GPIOSetup(
  116. acmp->acmp_device,
  117. control->output->location,
  118. control->output->enable,
  119. control->output->invert);
  120. int_en = true;
  121. }
  122. if (control->hook.cbFunc != RT_NULL)
  123. {
  124. acmp->hook.cbFunc = control->hook.cbFunc;
  125. acmp->hook.userPtr = control->hook.userPtr;
  126. int_en = true;
  127. }
  128. if (int_en)
  129. {
  130. /* Enable edge interrupt */
  131. ACMP_IntEnable(acmp->acmp_device, ACMP_IEN_EDGE);
  132. ACMP_IntClear(acmp->acmp_device, ACMP_IFC_EDGE);
  133. /* Enable ACMP0/1 interrupt vector in NVIC */
  134. NVIC_ClearPendingIRQ(ACMP0_IRQn);
  135. NVIC_SetPriority(ACMP0_IRQn, EFM32_IRQ_PRI_DEFAULT);
  136. NVIC_EnableIRQ(ACMP0_IRQn);
  137. }
  138. }
  139. break;
  140. case RT_DEVICE_CTRL_ACMP_OUTPUT:
  141. *((rt_bool_t *)args) = \
  142. (acmp->acmp_device->STATUS & ACMP_STATUS_ACMPOUT) ? true : false;
  143. break;
  144. default:
  145. return -RT_ERROR;
  146. }
  147. return RT_EOK;
  148. }
  149. /***************************************************************************//**
  150. * @brief
  151. * Register ACMP device
  152. *
  153. * @details
  154. *
  155. * @note
  156. *
  157. * @param[in] device
  158. * Pointer to device descriptor
  159. *
  160. * @param[in] name
  161. * Device name
  162. *
  163. * @param[in] flag
  164. * Configuration flags
  165. *
  166. * @param[in] acmp
  167. * Pointer to ACMP device descriptor
  168. *
  169. * @return
  170. * Error code
  171. ******************************************************************************/
  172. rt_err_t rt_hw_acmp_register(
  173. rt_device_t device,
  174. const char *name,
  175. rt_uint32_t flag,
  176. struct efm32_acmp_device_t *acmp)
  177. {
  178. RT_ASSERT(device != RT_NULL);
  179. device->type = RT_Device_Class_Char; /* fixme: should be acmp type */
  180. device->rx_indicate = RT_NULL;
  181. device->tx_complete = RT_NULL;
  182. device->init = rt_acmp_init;
  183. device->open = RT_NULL;
  184. device->close = RT_NULL;
  185. device->read = RT_NULL;
  186. device->write = RT_NULL;
  187. device->control = rt_acmp_control;
  188. device->user_data = acmp;
  189. /* register a character device */
  190. return rt_device_register(device, name, flag);
  191. }
  192. /***************************************************************************//**
  193. * @brief
  194. * ACMP edge trigger interrupt handler
  195. *
  196. * @details
  197. *
  198. * @note
  199. ******************************************************************************/
  200. void rt_hw_acmp_isr(rt_device_t dev)
  201. {
  202. RT_ASSERT(dev != RT_NULL);
  203. struct efm32_acmp_device_t *acmp;
  204. acmp = (struct efm32_acmp_device_t *)(dev->user_data);
  205. if (acmp->hook.cbFunc != RT_NULL)
  206. {
  207. (acmp->hook.cbFunc)(acmp->hook.userPtr);
  208. }
  209. }
  210. /***************************************************************************//**
  211. * @brief
  212. * Initialize the specified ACMP unit
  213. *
  214. * @details
  215. *
  216. * @note
  217. *
  218. * @param[in] device
  219. * Pointer to device descriptor
  220. *
  221. * @param[in] unitNumber
  222. * Unit number
  223. *
  224. * @return
  225. * Pointer to ACMP device
  226. ******************************************************************************/
  227. static struct efm32_acmp_device_t *rt_hw_acmp_unit_init(
  228. rt_device_t device,
  229. rt_uint8_t unitNumber)
  230. {
  231. struct efm32_acmp_device_t *acmp;
  232. efm32_irq_hook_init_t hook;
  233. CMU_Clock_TypeDef acmpClock;
  234. do
  235. {
  236. /* Allocate device */
  237. acmp = rt_malloc(sizeof(struct efm32_acmp_device_t));
  238. if (acmp == RT_NULL)
  239. {
  240. acmp_debug("ACMP err: no mem for ACMP%d\n", unitNumber);
  241. break;
  242. }
  243. /* Initialization */
  244. if (unitNumber >= ACMP_COUNT)
  245. {
  246. break;
  247. }
  248. switch (unitNumber)
  249. {
  250. case 0:
  251. acmp->acmp_device = ACMP0;
  252. acmpClock = (CMU_Clock_TypeDef)cmuClock_ACMP0;
  253. break;
  254. case 1:
  255. acmp->acmp_device = ACMP1;
  256. acmpClock = (CMU_Clock_TypeDef)cmuClock_ACMP1;
  257. break;
  258. default:
  259. break;
  260. }
  261. /* Enable ACMP clock */
  262. CMU_ClockEnable(acmpClock, true);
  263. /* Reset */
  264. ACMP_Reset(acmp->acmp_device);
  265. /* Config interrupt and NVIC */
  266. hook.type = efm32_irq_type_acmp;
  267. hook.unit = unitNumber;
  268. hook.cbFunc = rt_hw_acmp_isr;
  269. hook.userPtr = device;
  270. efm32_irq_hook_register(&hook);
  271. return acmp;
  272. } while(0);
  273. if (acmp)
  274. {
  275. rt_free(acmp);
  276. }
  277. rt_kprintf("ACMP: Init failed!\n");
  278. return RT_NULL;
  279. }
  280. /***************************************************************************//**
  281. * @brief
  282. * Initialize all ACMP module related hardware and register ACMP device to
  283. * kernel
  284. *
  285. * @details
  286. *
  287. * @note
  288. *
  289. ******************************************************************************/
  290. void rt_hw_acmp_init(void)
  291. {
  292. struct efm32_acmp_device_t *acmp;
  293. #ifdef RT_USING_ACMP0
  294. if ((acmp = rt_hw_acmp_unit_init(&acmp0_device, 0)) != RT_NULL)
  295. {
  296. rt_hw_acmp_register(&acmp0_device, RT_ACMP0_NAME, EFM32_NO_DATA, acmp);
  297. }
  298. #endif
  299. #ifdef RT_USING_ACMP1
  300. if ((acmp = rt_hw_acmp_unit_init(&acmp1_device, 1)) != RT_NULL)
  301. {
  302. rt_hw_acmp_register(&acmp1_device, RT_ACMP1_NAME, EFM32_NO_DATA, acmp);
  303. }
  304. #endif
  305. }
  306. /***************************************************************************//**
  307. * @brief
  308. * Calculate the warm-up time value providing at least 10us
  309. *
  310. * @param[in] hfperFreq
  311. * Frequency in Hz of reference HFPER clock. Set to 0 to use currently defined
  312. * HFPER clock setting
  313. *
  314. * @return
  315. * Warm-up time value to use for ACMP in order to achieve at least 10us
  316. ******************************************************************************/
  317. ACMP_WarmTime_TypeDef efm32_acmp_WarmTimeCalc(rt_uint32_t hfperFreq)
  318. {
  319. if (!hfperFreq)
  320. {
  321. hfperFreq = CMU_ClockFreqGet(cmuClock_HFPER);
  322. /* Just in case, make sure we get non-zero freq for below calculation */
  323. if (!hfperFreq)
  324. {
  325. hfperFreq = 1;
  326. }
  327. }
  328. /* Determine number of HFPERCLK cycle >= 10us */
  329. if (4 * 1000000 / hfperFreq > 10)
  330. {
  331. return acmpWarmTime4;
  332. }
  333. else if (8 * 1000000 / hfperFreq > 10)
  334. {
  335. return acmpWarmTime8;
  336. }
  337. else if (16 * 1000000 / hfperFreq > 10)
  338. {
  339. return acmpWarmTime16;
  340. }
  341. else if (32 * 1000000 / hfperFreq > 10)
  342. {
  343. return acmpWarmTime32;
  344. }
  345. else if (64 * 1000000 / hfperFreq > 10)
  346. {
  347. return acmpWarmTime64;
  348. }
  349. else if (128 * 1000000 / hfperFreq > 10)
  350. {
  351. return acmpWarmTime128;
  352. }
  353. else if (256 * 1000000 / hfperFreq > 10)
  354. {
  355. return acmpWarmTime256;
  356. }
  357. else if (512 * 1000000 / hfperFreq > 10)
  358. {
  359. return acmpWarmTime512;
  360. }
  361. }
  362. #endif
  363. /***************************************************************************//**
  364. * @}
  365. ******************************************************************************/