drv_ecap.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  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-10-7 Wayne First version
  10. *
  11. ******************************************************************************/
  12. #include <rtconfig.h>
  13. #if defined(BSP_USING_ECAP)
  14. #include <rtdevice.h>
  15. #include "drv_sys.h"
  16. #include "drv_common.h"
  17. #include "nu_bitutil.h"
  18. #define ECAP_CHANNEL_NUM 0x3
  19. #define ECAP_CHANNEL_MSK ((1<<ECAP_CHANNEL_NUM)-1)
  20. #define ECAP_CLK_DIV ECAP_CAPTURE_TIMER_CLKDIV_32
  21. /* Private typedef --------------------------------------------------------------*/
  22. enum
  23. {
  24. ECAP_START = -1,
  25. #if defined(BSP_USING_ECAP0)
  26. ECAP0_IDX,
  27. ECAP1_IDX,
  28. ECAP2_IDX,
  29. #endif
  30. #if defined(BSP_USING_ECAP1)
  31. ECAP3_IDX,
  32. ECAP4_IDX,
  33. ECAP5_IDX,
  34. #endif
  35. #if defined(BSP_USING_ECAP2)
  36. ECAP6_IDX,
  37. ECAP7_IDX,
  38. ECAP8_IDX,
  39. #endif
  40. ECAP_CNT
  41. };
  42. struct nu_ecap
  43. {
  44. struct rt_inputcapture_device parent;
  45. ECAP_T *base;
  46. char *name;
  47. IRQn_Type irqn;
  48. uint32_t rstidx;
  49. uint32_t modid;
  50. float fUsPerTick;
  51. uint8_t u8Channel;
  52. rt_bool_t bfirstData;
  53. uint32_t u32CurrentCnt;
  54. uint32_t u32LastCnt;
  55. rt_bool_t input_data_level;
  56. } ;
  57. typedef struct nu_ecap *nu_ecap_t;
  58. /* Private functions ------------------------------------------------------------*/
  59. static rt_err_t nu_ecap_init(struct rt_inputcapture_device *inputcapture);
  60. static rt_err_t nu_ecap_open(struct rt_inputcapture_device *inputcapture);
  61. static rt_err_t nu_ecap_close(struct rt_inputcapture_device *inputcapture);
  62. static rt_err_t nu_ecap_get_pulsewidth(struct rt_inputcapture_device *inputcapture, rt_uint32_t *pulsewidth_us);
  63. /* Private define ---------------------------------------------------------------*/
  64. #define NU_ECAP_GET_LEVEL(status, channel) ((status&(ECAP_STATUS_CAP0_Msk<<channel))?1:0)
  65. #define ECAP_GET_CLK_DIV_INDEX(ecap) ((ecap)->CTL1 = ((ecap)->CTL1 & ECAP_CTL1_CLKSEL_Msk)>>ECAP_CTL1_CLKSEL_Pos)
  66. /* Public functions -------------------------------------------------------------*/
  67. /* Private variables ------------------------------------------------------------*/
  68. static struct nu_ecap nu_ecap_arr [] =
  69. {
  70. #if defined(BSP_USING_ECAP0)
  71. { .base = ECAP0, .name = "ecap0i0", .irqn = ECAP0_IRQn, .rstidx = ECAP0_RST, .modid = ECAP0_MODULE },
  72. { .base = ECAP0, .name = "ecap0i1", .irqn = ECAP0_IRQn, .rstidx = ECAP0_RST, .modid = ECAP0_MODULE },
  73. { .base = ECAP0, .name = "ecap0i2", .irqn = ECAP0_IRQn, .rstidx = ECAP0_RST, .modid = ECAP0_MODULE },
  74. #endif
  75. #if defined(BSP_USING_ECAP1)
  76. { .base = ECAP1, .name = "ecap1i0", .irqn = ECAP1_IRQn, .rstidx = ECAP1_RST, .modid = ECAP1_MODULE },
  77. { .base = ECAP1, .name = "ecap1i1", .irqn = ECAP1_IRQn, .rstidx = ECAP1_RST, .modid = ECAP1_MODULE },
  78. { .base = ECAP1, .name = "ecap1i2", .irqn = ECAP1_IRQn, .rstidx = ECAP1_RST, .modid = ECAP1_MODULE },
  79. #endif
  80. #if defined(BSP_USING_ECAP2)
  81. { .base = ECAP2, .name = "ecap2i0", .irqn = ECAP2_IRQn, .rstidx = ECAP1_RST, .modid = ECAP2_MODULE },
  82. { .base = ECAP2, .name = "ecap2i1", .irqn = ECAP2_IRQn, .rstidx = ECAP1_RST, .modid = ECAP2_MODULE },
  83. { .base = ECAP2, .name = "ecap2i2", .irqn = ECAP2_IRQn, .rstidx = ECAP1_RST, .modid = ECAP2_MODULE },
  84. #endif
  85. };
  86. static struct rt_inputcapture_ops nu_ecap_ops =
  87. {
  88. .init = nu_ecap_init,
  89. .open = nu_ecap_open,
  90. .close = nu_ecap_close,
  91. .get_pulsewidth = nu_ecap_get_pulsewidth,
  92. };
  93. /* Functions define ------------------------------------------------------------*/
  94. static void nu_ecap_isr(int vector, void *param)
  95. {
  96. /* Get base address of uart register */
  97. rt_int32_t irqindex;
  98. nu_ecap_t psNuEcap = (nu_ecap_t)param;
  99. ECAP_T *base = psNuEcap->base;
  100. /* Get input Capture status */
  101. uint32_t u32Status = ECAP_GET_INT_STATUS(base);
  102. uint32_t u32ChStatus = u32Status & ECAP_CHANNEL_MSK;
  103. /* Check input capture channel flag */
  104. /* Find index of pin is attached in pool. */
  105. while ((irqindex = nu_ctz(u32ChStatus)) < ECAP_CHANNEL_NUM) // Count Trailing Zeros ==> Find First One
  106. {
  107. if (u32Status & (ECAP_STATUS_CAPTF0_Msk << (psNuEcap->u8Channel)))
  108. {
  109. /* Clear input capture channel flag */
  110. ECAP_CLR_CAPTURE_FLAG(base, ECAP_STATUS_CAPTF0_Msk << (psNuEcap->u8Channel));
  111. psNuEcap->input_data_level = NU_ECAP_GET_LEVEL(u32Status, psNuEcap->u8Channel);
  112. psNuEcap->u32CurrentCnt = ECAP_GET_CNT_HOLD_VALUE(base, psNuEcap->u8Channel);
  113. rt_hw_inputcapture_isr(&psNuEcap->parent, psNuEcap->input_data_level);
  114. }
  115. }
  116. }
  117. static rt_err_t nu_ecap_get_pulsewidth(struct rt_inputcapture_device *inputcapture, rt_uint32_t *pulsewidth_us)
  118. {
  119. rt_err_t ret = RT_EOK;
  120. float fTempCnt;
  121. nu_ecap_t psNuEcap = (nu_ecap_t) inputcapture;
  122. RT_ASSERT(inputcapture != RT_NULL);
  123. if (psNuEcap->bfirstData)
  124. {
  125. psNuEcap->bfirstData = RT_FALSE;
  126. ret = -RT_ERROR;
  127. return -(ret);
  128. }
  129. if (psNuEcap->u32CurrentCnt > psNuEcap->u32LastCnt)
  130. fTempCnt = psNuEcap->u32CurrentCnt - psNuEcap->u32LastCnt;
  131. else /* Overrun case */
  132. fTempCnt = psNuEcap->u32CurrentCnt + ((0x1000000 - psNuEcap->u32LastCnt) + 1);
  133. *pulsewidth_us = (int)(fTempCnt * psNuEcap->fUsPerTick);
  134. psNuEcap->u32LastCnt = psNuEcap->u32CurrentCnt;
  135. return -(ret);
  136. }
  137. static float get_ecap_tick_time_us(nu_ecap_t psNuEcap)
  138. {
  139. uint8_t u8ClockDivider[8] = { 1, 4, 16, 32, 64, 96, 112, 128};
  140. if (psNuEcap->base == ECAP0)
  141. return ((float)1000000 / ((float)CLK_GetPCLK2Freq() / u8ClockDivider[(psNuEcap->base->CTL1 & ECAP_CTL1_CLKSEL_Msk) >> ECAP_CTL1_CLKSEL_Pos]));
  142. else
  143. return ((float)1000000 / ((float)CLK_GetPCLK1Freq() / u8ClockDivider[(psNuEcap->base->CTL1 & ECAP_CTL1_CLKSEL_Msk) >> ECAP_CTL1_CLKSEL_Pos]));
  144. }
  145. static rt_err_t nu_ecap_init(struct rt_inputcapture_device *inputcapture)
  146. {
  147. return RT_EOK;
  148. }
  149. static rt_err_t nu_ecap_open(struct rt_inputcapture_device *inputcapture)
  150. {
  151. rt_err_t ret = RT_EOK;
  152. nu_ecap_t psNuEcap = (nu_ecap_t) inputcapture;
  153. RT_ASSERT(inputcapture != RT_NULL);
  154. psNuEcap->fUsPerTick = get_ecap_tick_time_us(psNuEcap);
  155. /* Enable ECAP Input Channel */
  156. ECAP_ENABLE_INPUT_CHANNEL(psNuEcap->base, 0x1 << (ECAP_CTL0_IC0EN_Pos + psNuEcap->u8Channel));
  157. /* Input Channel interrupt enabled */
  158. ECAP_EnableINT(psNuEcap->base, 0x1 << (ECAP_CTL0_CAPIEN0_Pos + psNuEcap->u8Channel));
  159. /* Enable interrupt. */
  160. if ((psNuEcap->base->CTL0 & (ECAP_CHANNEL_MSK << ECAP_CTL0_CAPIEN0_Pos)) != 0U)
  161. rt_hw_interrupt_umask(psNuEcap->irqn);
  162. /* ECAP_CNT starts up-counting */
  163. ECAP_CNT_START(psNuEcap->base);
  164. return ret;
  165. }
  166. static rt_err_t nu_ecap_close(struct rt_inputcapture_device *inputcapture)
  167. {
  168. rt_err_t ret = RT_EOK;
  169. nu_ecap_t psNuEcap = (nu_ecap_t) inputcapture;
  170. RT_ASSERT(inputcapture != RT_NULL);
  171. /* Input Channel interrupt disabled */
  172. ECAP_DisableINT(psNuEcap->base, 0x1 << (ECAP_CTL0_CAPIEN0_Pos + psNuEcap->u8Channel));
  173. /* Disable interrupt. */
  174. if ((psNuEcap->base->CTL0 & (ECAP_CHANNEL_MSK << ECAP_CTL0_CAPIEN0_Pos)) == 0U)
  175. rt_hw_interrupt_mask(psNuEcap->irqn);
  176. /* Disable ECAP Input Channel */
  177. ECAP_DISABLE_INPUT_CHANNEL(psNuEcap->base, 0x1 << (ECAP_CTL0_IC0EN_Pos + psNuEcap->u8Channel));
  178. /* Clear input capture channel flag */
  179. ECAP_CLR_CAPTURE_FLAG(psNuEcap->base, 0x1 << (ECAP_STATUS_CAPTF0_Pos + psNuEcap->u8Channel));
  180. return ret;
  181. }
  182. static void nu_ecap_channel_init(ECAP_T *base)
  183. {
  184. /* Enable ECAP */
  185. ECAP_Open(base, ECAP_DISABLE_COMPARE);
  186. ECAP_SEL_TIMER_CLK_DIV(base, ECAP_CLK_DIV);
  187. /* Select Reload function */
  188. ECAP_SET_CNT_CLEAR_EVENT(base, ECAP_CTL1_OVRLDEN_Msk);
  189. /* Enable ECAP source IC */
  190. ECAP_SEL_INPUT_SRC(base, ECAP_IC0, ECAP_CAP_INPUT_SRC_FROM_IC);
  191. ECAP_SEL_INPUT_SRC(base, ECAP_IC1, ECAP_CAP_INPUT_SRC_FROM_IC);
  192. ECAP_SEL_INPUT_SRC(base, ECAP_IC2, ECAP_CAP_INPUT_SRC_FROM_IC);
  193. /* Select IC detect rising edge */
  194. ECAP_SEL_CAPTURE_EDGE(base, ECAP_IC0, ECAP_RISING_FALLING_EDGE);
  195. ECAP_SEL_CAPTURE_EDGE(base, ECAP_IC1, ECAP_RISING_FALLING_EDGE);
  196. ECAP_SEL_CAPTURE_EDGE(base, ECAP_IC2, ECAP_RISING_FALLING_EDGE);
  197. }
  198. /* Init and register ecap capture */
  199. static int rt_hw_ecap_init(void)
  200. {
  201. int i;
  202. rt_err_t ret = RT_EOK;
  203. for (i = (ECAP_START + 1); i < ECAP_CNT; i++)
  204. {
  205. nu_ecap_t psNuEcap = &nu_ecap_arr[i];
  206. psNuEcap->u8Channel = i % ECAP_CHANNEL_NUM;
  207. psNuEcap->bfirstData = RT_TRUE;
  208. psNuEcap->u32CurrentCnt = 0;
  209. psNuEcap->u32LastCnt = 0;
  210. psNuEcap->parent.ops = &nu_ecap_ops;
  211. if ((psNuEcap->u8Channel % ECAP_CHANNEL_NUM) == 0)
  212. {
  213. /* register ecap module */
  214. CLK_EnableModuleClock(psNuEcap->modid);
  215. SYS_ResetModule(psNuEcap->rstidx);
  216. nu_ecap_channel_init(psNuEcap->base);
  217. /* register isr */
  218. rt_hw_interrupt_install(psNuEcap->irqn, nu_ecap_isr, psNuEcap, psNuEcap->name);
  219. }
  220. /* register inputcapture device */
  221. ret = rt_device_inputcapture_register(&psNuEcap->parent, psNuEcap->name, psNuEcap);
  222. RT_ASSERT(ret == RT_EOK);
  223. }
  224. return 0;
  225. }
  226. INIT_DEVICE_EXPORT(rt_hw_ecap_init);
  227. #endif //#if defined(BSP_USING_ECAP)