drv_pwm_capture.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. /**************************************************************************//**
  2. *
  3. * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0
  6. *
  7. * Change Logs:
  8. * Date Author Notes
  9. * 2021-02-17 klcheng First version
  10. *
  11. ******************************************************************************/
  12. #include <rtconfig.h>
  13. #if defined(BSP_USING_PWM_CAPTURE)
  14. #if ((BSP_USING_PWM0_CAPTURE_CHMSK+BSP_USING_PWM1_CAPTURE_CHMSK)!=0)
  15. #include <rtdevice.h>
  16. #include "NuMicro.h"
  17. /* Private typedef --------------------------------------------------------------*/
  18. typedef struct nu_capture
  19. {
  20. struct rt_inputcapture_device parent;
  21. PWM_T *pwm;
  22. uint8_t u8Channel;
  23. IRQn_Type irq;
  24. uint32_t u32CurrentRisingCnt;
  25. uint32_t u32CurrentFallingCnt;
  26. uint32_t u32LastRisingCnt;
  27. uint32_t u32LastFallingCnt;
  28. rt_bool_t input_data_level;
  29. rt_bool_t pwm_init;
  30. struct nu_capture *pair;
  31. } nu_capture_t;
  32. /* Private functions ------------------------------------------------------------*/
  33. static rt_err_t nu_capture_init(struct rt_inputcapture_device *inputcapture);
  34. static rt_err_t nu_capture_open(struct rt_inputcapture_device *inputcapture);
  35. static rt_err_t nu_capture_close(struct rt_inputcapture_device *inputcapture);
  36. static rt_err_t nu_capture_get_pulsewidth(struct rt_inputcapture_device *inputcapture, rt_uint32_t *pulsewidth_us);
  37. /* Public functions -------------------------------------------------------------*/
  38. /* Private variables ------------------------------------------------------------*/
  39. #if (BSP_USING_PWM0_CAPTURE_CHMSK!=0)
  40. static const char *nu_pwm0_device_name[PWM_CHANNEL_NUM] = {"pwm0i0", "pwm0i1", "pwm0i2", "pwm0i3", "pwm0i4", "pwm0i5"};
  41. static nu_capture_t nu_pwm0_capture[PWM_CHANNEL_NUM] = {0};
  42. #endif
  43. #if (BSP_USING_PWM1_CAPTURE_CHMSK!=0)
  44. static const char *nu_pwm1_device_name[PWM_CHANNEL_NUM] = {"pwm1i0", "pwm1i1", "pwm1i2", "pwm1i3", "pwm1i4", "pwm1i5"};
  45. static nu_capture_t nu_pwm1_capture[PWM_CHANNEL_NUM] = {0};
  46. #endif
  47. static struct rt_inputcapture_ops nu_capture_ops =
  48. {
  49. .init = nu_capture_init,
  50. .open = nu_capture_open,
  51. .close = nu_capture_close,
  52. .get_pulsewidth = nu_capture_get_pulsewidth,
  53. };
  54. /* Functions define ------------------------------------------------------------*/
  55. static rt_err_t CalPulseWidth(nu_capture_t *nu_capture)
  56. {
  57. /* Read the capture counter value if falling/rising edge */
  58. if (PWM_GetCaptureIntFlag(nu_capture->pwm, nu_capture->u8Channel) == 1)//Rising edge
  59. {
  60. PWM_ClearCaptureIntFlag(nu_capture->pwm, nu_capture->u8Channel, PWM_CAPTURE_INT_RISING_LATCH);
  61. nu_capture->u32CurrentRisingCnt = PWM_GET_CAPTURE_RISING_DATA(nu_capture->pwm, nu_capture->u8Channel);
  62. }
  63. else if (PWM_GetCaptureIntFlag(nu_capture->pwm, nu_capture->u8Channel) == 2)//Falling edge
  64. {
  65. PWM_ClearCaptureIntFlag(nu_capture->pwm, nu_capture->u8Channel, PWM_CAPTURE_INT_FALLING_LATCH);
  66. nu_capture->u32CurrentFallingCnt += PWM_GET_CAPTURE_FALLING_DATA(nu_capture->pwm, nu_capture->u8Channel);
  67. }
  68. else
  69. {
  70. PWM_ClearCaptureIntFlag(nu_capture->pwm, nu_capture->u8Channel, PWM_CAPTURE_INT_RISING_LATCH);
  71. PWM_ClearCaptureIntFlag(nu_capture->pwm, nu_capture->u8Channel, PWM_CAPTURE_INT_FALLING_LATCH);
  72. return -(RT_ERROR);
  73. }
  74. return RT_EOK;
  75. }
  76. #if (BSP_USING_PWM0_CAPTURE_CHMSK!=0)
  77. void PWM0_IRQHandler(void)
  78. {
  79. /* enter interrupt */
  80. rt_interrupt_enter();
  81. for (uint8_t i = 0; i < PWM_CHANNEL_NUM ; i++)
  82. {
  83. if (PWM_GetCaptureIntFlag(nu_pwm0_capture[i].pwm, nu_pwm0_capture[i].u8Channel) != 0)
  84. {
  85. /* Calculate pulse width */
  86. if (CalPulseWidth(&nu_pwm0_capture[i]) == RT_EOK)
  87. {
  88. rt_hw_inputcapture_isr(&nu_pwm0_capture[i].parent, nu_pwm0_capture[i].input_data_level);
  89. }
  90. }
  91. }
  92. /* leave interrupt */
  93. rt_interrupt_leave();
  94. }
  95. #endif
  96. #if (BSP_USING_PWM1_CAPTURE_CHMSK!=0)
  97. void PWM1_IRQHandler(void)
  98. {
  99. /* enter interrupt */
  100. rt_interrupt_enter();
  101. for (uint8_t i = 0; i < PWM_CHANNEL_NUM ; i++)
  102. {
  103. if (PWM_GetCaptureIntFlag(nu_pwm1_capture[i].pwm, nu_pwm1_capture[i].u8Channel) != 0)
  104. {
  105. /* Calculate pulse width */
  106. if (CalPulseWidth(&nu_pwm1_capture[i]) == RT_EOK)
  107. {
  108. rt_hw_inputcapture_isr(&nu_pwm1_capture[i].parent, nu_pwm1_capture[i].input_data_level);
  109. }
  110. }
  111. }
  112. /* leave interrupt */
  113. rt_interrupt_leave();
  114. }
  115. #endif
  116. static rt_err_t nu_capture_get_pulsewidth(struct rt_inputcapture_device *inputcapture, rt_uint32_t *pulsewidth_us)
  117. {
  118. rt_err_t ret = RT_EOK;
  119. nu_capture_t *nu_capture;
  120. nu_capture = (nu_capture_t *)inputcapture;
  121. if (nu_capture->u32CurrentFallingCnt)
  122. {
  123. if (nu_capture->u32CurrentFallingCnt > nu_capture->u32LastRisingCnt)
  124. *pulsewidth_us = nu_capture->u32CurrentFallingCnt - nu_capture->u32LastRisingCnt;
  125. else /* Overrun case */
  126. *pulsewidth_us = nu_capture->u32CurrentFallingCnt + (0x10000 - nu_capture->u32LastRisingCnt);
  127. nu_capture->input_data_level = RT_FALSE;
  128. nu_capture->u32LastFallingCnt = nu_capture->u32CurrentFallingCnt;
  129. nu_capture->u32CurrentFallingCnt = 0;
  130. }
  131. else if (nu_capture->u32CurrentRisingCnt)
  132. {
  133. if (nu_capture->u32CurrentRisingCnt > nu_capture->u32LastFallingCnt)
  134. *pulsewidth_us = nu_capture->u32CurrentRisingCnt - nu_capture->u32LastFallingCnt;
  135. else /* Overrun case */
  136. *pulsewidth_us = nu_capture->u32CurrentRisingCnt + (0x10000 - nu_capture->u32LastFallingCnt);
  137. nu_capture->input_data_level = RT_TRUE;
  138. nu_capture->u32LastRisingCnt = nu_capture->u32CurrentRisingCnt;
  139. nu_capture->u32CurrentRisingCnt = 0;
  140. }
  141. else
  142. {
  143. ret = RT_ERROR;
  144. }
  145. return -(ret);
  146. }
  147. static rt_err_t nu_pwm_init(nu_capture_t *nu_capture)
  148. {
  149. rt_err_t ret = RT_ERROR;
  150. static rt_bool_t bPWM0Inited = RT_FALSE;
  151. static rt_bool_t bPWM1Inited = RT_FALSE;
  152. if (nu_capture->pwm == PWM0)
  153. {
  154. if (bPWM0Inited == RT_FALSE)
  155. {
  156. /* Enable PWM0 clock */
  157. SYS_UnlockReg();
  158. CLK_EnableModuleClock(PWM0_MODULE);
  159. CLK_SetModuleClock(PWM0_MODULE, CLK_CLKSEL2_PWM0SEL_PCLK0, 0);
  160. SYS_LockReg();
  161. bPWM0Inited = RT_TRUE;
  162. }
  163. ret = RT_EOK;
  164. }
  165. else if (nu_capture->pwm == PWM1)
  166. {
  167. if (bPWM1Inited == RT_FALSE)
  168. {
  169. /* Enable PWM1 clock */
  170. SYS_UnlockReg();
  171. CLK_EnableModuleClock(PWM1_MODULE);
  172. CLK_SetModuleClock(PWM1_MODULE, CLK_CLKSEL2_PWM1SEL_PCLK1, 0);
  173. SYS_LockReg();
  174. bPWM1Inited = RT_TRUE;
  175. }
  176. ret = RT_EOK;
  177. }
  178. return -(ret);
  179. }
  180. static rt_err_t nu_capture_init(struct rt_inputcapture_device *inputcapture)
  181. {
  182. rt_err_t ret = RT_EOK;
  183. nu_capture_t *nu_capture;
  184. RT_ASSERT(inputcapture != RT_NULL);
  185. nu_capture = (nu_capture_t *) inputcapture;
  186. if (nu_pwm_init(nu_capture) != RT_EOK)
  187. {
  188. rt_kprintf("Failed to initialize PWM%d.\n", nu_capture->pwm);
  189. ret = RT_ERROR;
  190. }
  191. return -(ret);
  192. }
  193. static rt_err_t nu_capture_open(struct rt_inputcapture_device *inputcapture)
  194. {
  195. rt_err_t ret = RT_EOK;
  196. nu_capture_t *nu_capture;
  197. RT_ASSERT(inputcapture != RT_NULL);
  198. nu_capture = (nu_capture_t *) inputcapture;
  199. /* Enable capture rising/falling edge interrupt */
  200. PWM_EnableCaptureInt(nu_capture->pwm, nu_capture->u8Channel, PWM_CAPTURE_INT_FALLING_LATCH | PWM_CAPTURE_INT_RISING_LATCH);
  201. /* Enable PWM NVIC interrupt */
  202. NVIC_EnableIRQ(nu_capture->irq);
  203. /* Enable Capture Function for PWM */
  204. PWM_EnableCapture(nu_capture->pwm, 0x1 << nu_capture->u8Channel);
  205. if ((nu_capture->pwm_init == RT_FALSE) && (nu_capture->pair->pwm_init == RT_FALSE))
  206. {
  207. nu_capture->pwm_init = RT_TRUE;
  208. /* Set capture time as 1000 nanosecond */
  209. PWM_ConfigCaptureChannel(nu_capture->pwm, nu_capture->u8Channel, 1000, 0);
  210. /* Set counter type as down count */
  211. PWM_SET_ALIGNED_TYPE(nu_capture->pwm, 0x1 << nu_capture->u8Channel, PWM_UP_COUNTER);
  212. /* Enable PWM Timer */
  213. PWM_Start(nu_capture->pwm, 0x1 << nu_capture->u8Channel);
  214. }
  215. return ret;
  216. }
  217. static rt_err_t nu_capture_close(struct rt_inputcapture_device *inputcapture)
  218. {
  219. rt_err_t ret = RT_EOK;
  220. nu_capture_t *nu_capture;
  221. RT_ASSERT(inputcapture != RT_NULL);
  222. nu_capture = (nu_capture_t *) inputcapture;
  223. /* Disable capture rising/falling edge interrupt */
  224. PWM_DisableCaptureInt(nu_capture->pwm, nu_capture->u8Channel, PWM_CAPTURE_INT_FALLING_LATCH | PWM_CAPTURE_INT_RISING_LATCH);
  225. /* Disable PWM NVIC interrupt */
  226. NVIC_DisableIRQ(nu_capture->irq);
  227. /* Enable PWM Timer */
  228. PWM_Stop(nu_capture->pwm, 0x1 << nu_capture->u8Channel);
  229. nu_capture->pwm_init = RT_FALSE;
  230. return ret;
  231. }
  232. /* Init and register pwm capture */
  233. int nu_pwm_capture_device_init(void)
  234. {
  235. /* Init PWM0 6 channel and PWM1 6 channel */
  236. #if (BSP_USING_PWM0_CAPTURE_CHMSK!=0)
  237. for (int i = 0; i < PWM_CHANNEL_NUM; i++)
  238. {
  239. if (BSP_USING_PWM0_CAPTURE_CHMSK & (0x1 << i))
  240. {
  241. nu_pwm0_capture[i].pwm = PWM0;
  242. nu_pwm0_capture[i].u8Channel = i;
  243. nu_pwm0_capture[i].irq = PWM0_IRQn;
  244. nu_pwm0_capture[i].u32CurrentRisingCnt = 0;
  245. nu_pwm0_capture[i].u32CurrentFallingCnt = 0;
  246. nu_pwm0_capture[i].parent.ops = &nu_capture_ops;
  247. nu_pwm0_capture[i].pair = &nu_pwm0_capture[((i>>1) << 1) == i? i+1 : i-1];
  248. nu_pwm0_capture[i].pwm_init = RT_FALSE;
  249. /* register inputcapture device */
  250. rt_device_inputcapture_register(&nu_pwm0_capture[i].parent, nu_pwm0_device_name[i], &nu_pwm0_capture[i]);
  251. }
  252. }
  253. #endif //#if (BSP_USING_PWM0_CAPTURE_CHMSK!=0)
  254. #if (BSP_USING_PWM1_CAPTURE_CHMSK!=0)
  255. for (int i = 0; i < PWM_CHANNEL_NUM; i++)
  256. {
  257. if (BSP_USING_PWM1_CAPTURE_CHMSK & (0x1 << i))
  258. {
  259. nu_pwm1_capture[i].pwm = PWM1;
  260. nu_pwm1_capture[i].u8Channel = i;
  261. nu_pwm1_capture[i].irq = PWM1_IRQn;
  262. nu_pwm1_capture[i].u32CurrentRisingCnt = 0;
  263. nu_pwm1_capture[i].u32CurrentFallingCnt = 0;
  264. nu_pwm1_capture[i].parent.ops = &nu_capture_ops;
  265. nu_pwm1_capture[i].pair = &nu_pwm1_capture[((i>>1) << 1) == i? i+1 : i-1];
  266. nu_pwm1_capture[i].pwm_init = RT_FALSE;
  267. /* register inputcapture device */
  268. rt_device_inputcapture_register(&nu_pwm1_capture[i].parent, nu_pwm1_device_name[i], &nu_pwm1_capture[i]);
  269. }
  270. }
  271. #endif //#if (BSP_USING_PWM1_CAPTURE_CHMSK!=0)
  272. return 0;
  273. }
  274. INIT_DEVICE_EXPORT(nu_pwm_capture_device_init);
  275. #endif //#if ((BSP_USING_PWM0_CAPTURE_CHMSK+BSP_USING_PWM1_CAPTURE_CHMSK)!=0)
  276. #endif //#if defined(BSP_USING_PWM_CAPTURE)