drv_bpwm.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  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. * 2020-5-22 YHKuo First version
  10. *
  11. ******************************************************************************/
  12. #include <rtconfig.h>
  13. #if defined(BSP_USING_BPWM)
  14. #define LOG_TAG "drv.bpwm"
  15. #define DBG_ENABLE
  16. #define DBG_SECTION_NAME LOG_TAG
  17. #define DBG_LEVEL DBG_INFO
  18. #define DBG_COLOR
  19. #include <rtdbg.h>
  20. #include <stdint.h>
  21. #include <rtdevice.h>
  22. #include <rthw.h>
  23. #include "NuMicro.h"
  24. #define DEFAULT_DUTY 50
  25. #define DEFAULT_FREQ 1000
  26. enum
  27. {
  28. BPWM_START = -1,
  29. #if defined(BSP_USING_BPWM0)
  30. BPWM0_IDX,
  31. #endif
  32. #if defined(BSP_USING_BPWM1)
  33. BPWM1_IDX,
  34. #endif
  35. BPWM_CNT
  36. };
  37. struct nu_bpwm
  38. {
  39. struct rt_device_pwm dev;
  40. char *name;
  41. BPWM_T *bpwm_base;
  42. rt_int32_t pwm_period_time;
  43. };
  44. typedef struct nu_bpwm *nu_bpwm_t;
  45. static struct nu_bpwm nu_bpwm_arr [] =
  46. {
  47. #if defined(BSP_USING_BPWM0)
  48. {
  49. .name = "bpwm0",
  50. .bpwm_base = BPWM0,
  51. },
  52. #endif
  53. #if defined(BSP_USING_BPWM1)
  54. {
  55. .name = "bpwm1",
  56. .bpwm_base = BPWM1,
  57. },
  58. #endif
  59. {0}
  60. }; /* bpwm nu_epwm */
  61. static rt_err_t nu_bpwm_control(struct rt_device_pwm *device, int cmd, void *arg);
  62. static struct rt_pwm_ops nu_bpwm_ops =
  63. {
  64. .control = nu_bpwm_control
  65. };
  66. static rt_err_t nu_bpwm_enable(struct rt_device_pwm *device, struct rt_pwm_configuration *configuration, rt_bool_t enable)
  67. {
  68. rt_err_t result = RT_EOK;
  69. BPWM_T *pwm_base = ((nu_bpwm_t)device)->bpwm_base;
  70. rt_uint32_t pwm_channel = configuration->channel;
  71. if (enable == RT_TRUE)
  72. {
  73. BPWM_EnableOutput(pwm_base, 1 << pwm_channel);
  74. BPWM_Start(pwm_base, 1 << pwm_channel);
  75. }
  76. else if (enable == RT_FALSE)
  77. {
  78. BPWM_DisableOutput(pwm_base, 1 << pwm_channel);
  79. BPWM_ForceStop(pwm_base, 1 << pwm_channel);
  80. }
  81. return result;
  82. }
  83. static rt_err_t nu_bpwm_set(struct rt_device_pwm *device, struct rt_pwm_configuration *configuration)
  84. {
  85. if ((configuration->period) <= 0)
  86. return -(RT_ERROR);
  87. rt_uint32_t pwm_freq, pwm_dutycycle;
  88. BPWM_T *pwm_base = ((nu_bpwm_t)device)->bpwm_base;
  89. rt_uint8_t pwm_channel = configuration->channel;
  90. rt_uint32_t pwm_period = configuration->period;
  91. rt_uint32_t pwm_pulse = configuration->pulse;
  92. pwm_dutycycle = (pwm_pulse * 100) / pwm_period;
  93. if (BPWM_GET_CNR(pwm_base, pwm_channel) != 0)
  94. {
  95. pwm_period = ((nu_bpwm_t)device)->pwm_period_time;
  96. LOG_I("%s output frequency is determined, user can only change the duty\n", ((nu_bpwm_t)device)->name);
  97. }
  98. else
  99. {
  100. ((nu_bpwm_t)device)->pwm_period_time = pwm_period;
  101. }
  102. pwm_freq = 1000000000 / pwm_period;
  103. BPWM_ConfigOutputChannel(pwm_base, pwm_channel, pwm_freq, pwm_dutycycle) ;
  104. return RT_EOK;
  105. }
  106. static rt_uint32_t nu_bpwm_clksr(struct rt_device_pwm *device)
  107. {
  108. rt_uint32_t u32Src, u32BPWMClockSrc;
  109. BPWM_T *pwm_base = ((nu_bpwm_t)device)->bpwm_base;
  110. if (pwm_base == BPWM0)
  111. {
  112. u32Src = CLK->CLKSEL2 & CLK_CLKSEL2_BPWM0SEL_Msk;
  113. }
  114. else /* (bpwm == BPWM1) */
  115. {
  116. u32Src = CLK->CLKSEL2 & CLK_CLKSEL2_BPWM1SEL_Msk;
  117. }
  118. if (u32Src == 0U)
  119. {
  120. /* clock source is from PLL clock */
  121. u32BPWMClockSrc = CLK_GetPLLClockFreq();
  122. }
  123. else
  124. {
  125. /* clock source is from PCLK */
  126. SystemCoreClockUpdate();
  127. if (pwm_base == BPWM0)
  128. {
  129. u32BPWMClockSrc = CLK_GetPCLK0Freq();
  130. }
  131. else /* (bpwm == BPWM1) */
  132. {
  133. u32BPWMClockSrc = CLK_GetPCLK1Freq();
  134. }
  135. }
  136. return u32BPWMClockSrc;
  137. }
  138. static rt_err_t nu_bpwm_get(struct rt_device_pwm *device, struct rt_pwm_configuration *configuration)
  139. {
  140. rt_uint32_t pwm_real_period, pwm_real_duty, time_tick, u32BPWMClockSrc ;
  141. BPWM_T *pwm_base = ((nu_bpwm_t)device)->bpwm_base;
  142. rt_uint32_t pwm_channel = configuration->channel;
  143. rt_uint32_t pwm_prescale = pwm_base->CLKPSC;
  144. rt_uint32_t pwm_period = BPWM_GET_CNR(pwm_base, pwm_channel);
  145. rt_uint32_t pwm_pulse = BPWM_GET_CMR(pwm_base, pwm_channel);
  146. u32BPWMClockSrc = nu_bpwm_clksr(device);
  147. time_tick = 1000000000000 / u32BPWMClockSrc;
  148. pwm_real_period = (((pwm_prescale + 1) * (pwm_period + 1)) * time_tick) / 1000;
  149. pwm_real_duty = (((pwm_prescale + 1) * pwm_pulse * time_tick)) / 1000;
  150. configuration->period = pwm_real_period;
  151. configuration->pulse = pwm_real_duty;
  152. LOG_I("%s %d %d %d\n", ((nu_bpwm_t)device)->name, configuration->channel, configuration->period, configuration->pulse);
  153. return RT_EOK;
  154. }
  155. static rt_err_t nu_bpwm_control(struct rt_device_pwm *device, int cmd, void *arg)
  156. {
  157. struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)arg;
  158. RT_ASSERT(device != RT_NULL);
  159. RT_ASSERT(configuration != RT_NULL);
  160. if (((configuration->channel) + 1) > BPWM_CHANNEL_NUM)
  161. return -(RT_ERROR);
  162. switch (cmd)
  163. {
  164. case PWM_CMD_ENABLE:
  165. return nu_bpwm_enable(device, configuration, RT_TRUE);
  166. case PWM_CMD_DISABLE:
  167. return nu_bpwm_enable(device, configuration, RT_FALSE);
  168. case PWM_CMD_SET:
  169. return nu_bpwm_set(device, configuration);
  170. case PWM_CMD_GET:
  171. return nu_bpwm_get(device, configuration);
  172. default:
  173. return RT_EINVAL;
  174. }
  175. }
  176. int rt_hw_bpwm_init(void)
  177. {
  178. rt_err_t ret;
  179. rt_uint8_t i;
  180. for (i = (BPWM_START + 1); i < BPWM_CNT; i++)
  181. {
  182. ret = rt_device_pwm_register(&nu_bpwm_arr[i].dev, nu_bpwm_arr[i].name, &nu_bpwm_ops, RT_NULL);
  183. RT_ASSERT(ret == RT_EOK);
  184. }
  185. return 0;
  186. }
  187. INIT_DEVICE_EXPORT(rt_hw_bpwm_init);
  188. #endif