drv_pwm.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. /*
  2. * Copyright (c) 2006-2018, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2020-06-02 hqfang first version
  9. */
  10. #include "drv_pwm.h"
  11. // #define DBG_LVL DBG_INFO
  12. #include <rtdbg.h>
  13. #ifdef BSP_USING_PWM
  14. #if !defined(BSP_USING_PWM0) && !defined(BSP_USING_PWM1) && !defined(BSP_USING_PWM2) \
  15. && !defined(BSP_USING_PWM3) && !defined(BSP_USING_PWM4)
  16. #error "Please define at least one BSP_USING_PWMx"
  17. /* this driver can be disabled at menuconfig -> Hardware Drivers Config -> On-chip Peripheral Drivers -> Enable PWM */
  18. #endif
  19. static struct gd32_pwm_config pwm_config[] =
  20. {
  21. #ifdef BSP_USING_PWM0
  22. {
  23. "pwm0",
  24. TIMER0,
  25. 1000000,
  26. },
  27. #endif
  28. #ifdef BSP_USING_PWM1
  29. {
  30. "pwm1",
  31. TIMER1,
  32. 1000000,
  33. },
  34. #endif
  35. #ifdef BSP_USING_PWM2
  36. {
  37. "pwm2",
  38. TIMER2,
  39. 1000000,
  40. },
  41. #endif
  42. #ifdef BSP_USING_PWM3
  43. {
  44. "pwm3",
  45. TIMER3,
  46. 1000000,
  47. },
  48. #endif
  49. #ifdef BSP_USING_PWM4
  50. {
  51. "pwm4",
  52. TIMER4,
  53. 1000000,
  54. },
  55. #endif
  56. };
  57. #define GD32_MAX_PWM_CHANNELS TIMER_CH_3
  58. static struct gd32_pwm pwm_obj[sizeof(pwm_config) / sizeof(pwm_config[0])] = {0};
  59. static rt_err_t gd32_pwm_enable(struct rt_device_pwm *device, struct rt_pwm_configuration *configuration, rt_bool_t enable)
  60. {
  61. struct gd32_pwm_config *config;
  62. config = (struct gd32_pwm_config *)device->parent.user_data;
  63. RT_ASSERT(config);
  64. if (configuration->channel > GD32_MAX_PWM_CHANNELS)
  65. {
  66. return RT_EINVAL;
  67. }
  68. if (!enable)
  69. {
  70. timer_channel_output_state_config(config->periph, configuration->channel, TIMER_CCX_DISABLE);
  71. }
  72. else
  73. {
  74. timer_channel_output_state_config(config->periph, configuration->channel, TIMER_CCX_ENABLE);
  75. }
  76. return RT_EOK;
  77. }
  78. static uint32_t gd32_get_pwm_clk(rt_uint32_t periph)
  79. {
  80. uint32_t clk;
  81. uint8_t clkpre;
  82. if (periph != TIMER0)
  83. {
  84. clk = rcu_clock_freq_get(CK_APB1);
  85. clkpre = GET_BITS(RCU_CFG0, 8, 10);
  86. }
  87. else
  88. {
  89. clk = rcu_clock_freq_get(CK_APB2);
  90. clkpre = GET_BITS(RCU_CFG0, 11, 13);
  91. }
  92. if (clkpre >= 4)
  93. {
  94. clk = clk * 2;
  95. }
  96. return clk;
  97. }
  98. static rt_err_t gd32_pwm_get(struct rt_device_pwm *device, struct rt_pwm_configuration *configuration)
  99. {
  100. uint32_t pwmclk;
  101. uint16_t prescale, period, clkdiv, pulse;
  102. struct gd32_pwm_config *config;
  103. config = (struct gd32_pwm_config *)device->parent.user_data;
  104. RT_ASSERT(config);
  105. pwmclk = gd32_get_pwm_clk(config->periph);
  106. prescale = (uint16_t)TIMER_PSC(config->periph) + 1;
  107. clkdiv = ((uint16_t)(TIMER_CTL0(config->periph) & TIMER_CTL0_CKDIV) >> 8);
  108. clkdiv = 1 << clkdiv;
  109. period = (uint16_t)TIMER_CAR(config->periph) + 1;
  110. pulse = (uint16_t)REG32((config->periph) + 0x34U + configuration->channel << 2) + 1;
  111. pwmclk = pwmclk / prescale / clkdiv;
  112. LOG_I("current pwmclk is %d\n", pwmclk);
  113. configuration->period = (uint64_t)period * 1000000000 / pwmclk;
  114. configuration->pulse = (uint64_t)pulse * 1000000000 / pwmclk;
  115. return RT_EOK;
  116. }
  117. static rt_err_t gd32_pwm_set(struct rt_device_pwm *device, struct rt_pwm_configuration *configuration)
  118. {
  119. timer_oc_parameter_struct timer_ocinitpara;
  120. timer_parameter_struct timer_initpara;
  121. uint32_t pwmclk, pwmclkv2;
  122. uint64_t period_cmp;
  123. uint16_t prescale, period, clkdiv, pulse;
  124. struct gd32_pwm_config *config;
  125. config = (struct gd32_pwm_config *)device->parent.user_data;
  126. RT_ASSERT(config);
  127. if (configuration->channel > GD32_MAX_PWM_CHANNELS)
  128. {
  129. LOG_I("max channel supported is %d\n", GD32_MAX_PWM_CHANNELS);
  130. return RT_EINVAL;
  131. }
  132. if (configuration->period < configuration->pulse)
  133. {
  134. LOG_I("period should > pulse \n");
  135. return RT_EINVAL;
  136. }
  137. pwmclk = gd32_get_pwm_clk(config->periph);
  138. // min period value >= 100
  139. period_cmp = (uint64_t)(1000000000 / pwmclk) * 10;
  140. if (configuration->period < period_cmp)
  141. {
  142. return RT_EINVAL;
  143. }
  144. period_cmp = (uint64_t)(1000000000 / (pwmclk / 65536 / 4)) * 65536;
  145. if (configuration->period > period_cmp)
  146. {
  147. return RT_EINVAL;
  148. }
  149. period_cmp = (uint64_t) pwmclk * configuration->period / 1000000000;
  150. if (period_cmp < 65536)
  151. {
  152. prescale = 0;
  153. clkdiv = TIMER_CKDIV_DIV1;
  154. period = period_cmp;
  155. }
  156. else if (period_cmp < 4294967296)
  157. {
  158. prescale = period_cmp / 65536;
  159. period = period_cmp / (prescale + 1);
  160. clkdiv = TIMER_CKDIV_DIV1;
  161. }
  162. else if (period_cmp < 8589934592)
  163. {
  164. prescale = period_cmp / 65536;
  165. period = period_cmp / (prescale + 1) / 2;
  166. clkdiv = TIMER_CKDIV_DIV2;
  167. }
  168. else
  169. {
  170. prescale = period_cmp / 65536;
  171. period = period_cmp / (prescale + 1) / 4;
  172. clkdiv = TIMER_CKDIV_DIV4;
  173. }
  174. pwmclkv2 = pwmclk / (prescale + 1) / (1 << clkdiv);
  175. LOG_I("current pwmclk is %d\n", pwmclkv2);
  176. LOG_I("Set channel %d, period %dns, pulse %dns\n", configuration->channel, \
  177. configuration->period, configuration->pulse);
  178. pulse = (uint64_t)period * configuration->pulse / configuration->period;
  179. LOG_I("pwmclk %d, pwmcmp %d, prescale %d, period %d, pulse %d, clkdiv %d\n", \
  180. pwmclk, (uint32_t)period_cmp, prescale, period, pulse, clkdiv);
  181. /* initialize TIMER init parameter struct */
  182. timer_struct_para_init(&timer_initpara);
  183. /* TIMER configuration */
  184. timer_initpara.prescaler = prescale;
  185. timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
  186. timer_initpara.counterdirection = TIMER_COUNTER_UP;
  187. timer_initpara.period = period;
  188. timer_initpara.clockdivision = clkdiv;
  189. timer_initpara.repetitioncounter = 0;
  190. timer_init(config->periph, &timer_initpara);
  191. /* initialize TIMER channel output parameter struct */
  192. timer_channel_output_struct_para_init(&timer_ocinitpara);
  193. /* CH0, CH1 and CH2 configuration in PWM mode */
  194. timer_ocinitpara.outputstate = TIMER_CCX_DISABLE;
  195. timer_ocinitpara.outputnstate = TIMER_CCXN_DISABLE;
  196. timer_ocinitpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
  197. timer_ocinitpara.ocnpolarity = TIMER_OCN_POLARITY_HIGH;
  198. timer_ocinitpara.ocidlestate = TIMER_OC_IDLE_STATE_LOW;
  199. timer_ocinitpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
  200. timer_channel_output_config(config->periph, configuration->channel, &timer_ocinitpara);
  201. /* Channel configuration in PWM mode */
  202. timer_channel_output_pulse_value_config(config->periph, configuration->channel, pulse);
  203. timer_channel_output_mode_config(config->periph, configuration->channel, TIMER_OC_MODE_PWM0);
  204. timer_channel_output_shadow_config(config->periph, configuration->channel, TIMER_OC_SHADOW_DISABLE);
  205. timer_primary_output_config(config->periph, ENABLE);
  206. /* auto-reload preload enable */
  207. timer_auto_reload_shadow_enable(config->periph);
  208. timer_enable(config->periph);
  209. return RT_EOK;
  210. }
  211. static rt_err_t gd32_pwm_control(struct rt_device_pwm *device, int cmd, void *arg)
  212. {
  213. struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)arg;
  214. switch (cmd)
  215. {
  216. case PWM_CMD_ENABLE:
  217. return gd32_pwm_enable(device, configuration, RT_TRUE);
  218. case PWM_CMD_DISABLE:
  219. return gd32_pwm_enable(device, configuration, RT_FALSE);
  220. case PWM_CMD_SET:
  221. return gd32_pwm_set(device, configuration);
  222. case PWM_CMD_GET:
  223. return gd32_pwm_get(device, configuration);
  224. default:
  225. return RT_EINVAL;
  226. }
  227. }
  228. static rt_err_t gd32_pwm_init(struct gd32_pwm_config *config)
  229. {
  230. timer_oc_parameter_struct timer_ocinitpara;
  231. timer_parameter_struct timer_initpara;
  232. uint32_t pwmclk;
  233. uint16_t prescale;
  234. pwmclk = gd32_get_pwm_clk(config->periph);
  235. /* period 1ms, duty 50% */
  236. prescale = pwmclk / 1000 / 1000 - 1;
  237. config->period = 1000000;
  238. LOG_I("pwmclk %d, prescale %d, period %d, clkdiv %d\n", pwmclk, prescale, 999, 0);
  239. /* initialize TIMER init parameter struct */
  240. timer_struct_para_init(&timer_initpara);
  241. /* TIMER configuration */
  242. timer_initpara.prescaler = prescale;
  243. timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
  244. timer_initpara.counterdirection = TIMER_COUNTER_UP;
  245. timer_initpara.period = 999;
  246. timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
  247. timer_initpara.repetitioncounter = 0;
  248. timer_init(config->periph, &timer_initpara);
  249. /* initialize TIMER channel output parameter struct */
  250. timer_channel_output_struct_para_init(&timer_ocinitpara);
  251. /* CH0, CH1 and CH2 configuration in PWM mode */
  252. timer_ocinitpara.outputstate = TIMER_CCX_DISABLE;
  253. timer_ocinitpara.outputnstate = TIMER_CCXN_DISABLE;
  254. timer_ocinitpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
  255. timer_ocinitpara.ocnpolarity = TIMER_OCN_POLARITY_HIGH;
  256. timer_ocinitpara.ocidlestate = TIMER_OC_IDLE_STATE_LOW;
  257. timer_ocinitpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
  258. /* Channel configuration in PWM mode */
  259. for (int i = 0; i <= GD32_MAX_PWM_CHANNELS; i ++)
  260. {
  261. timer_channel_output_config(config->periph, i, &timer_ocinitpara);
  262. timer_channel_output_pulse_value_config(config->periph, i, 499);
  263. timer_channel_output_mode_config(config->periph, i, TIMER_OC_MODE_PWM0);
  264. timer_channel_output_shadow_config(config->periph, i, TIMER_OC_SHADOW_DISABLE);
  265. }
  266. timer_primary_output_config(config->periph, ENABLE);
  267. /* auto-reload preload enable */
  268. timer_auto_reload_shadow_enable(config->periph);
  269. timer_enable(config->periph);
  270. return RT_EOK;
  271. }
  272. static struct rt_pwm_ops gd32_drv_ops =
  273. {
  274. .control = gd32_pwm_control
  275. };
  276. static int rt_pwm_init(void)
  277. {
  278. int i = 0;
  279. int result = RT_EOK;
  280. #ifdef BSP_USING_PWM0
  281. rcu_periph_clock_enable(RCU_TIMER0);
  282. #endif
  283. #ifdef BSP_USING_PWM1
  284. rcu_periph_clock_enable(RCU_TIMER1);
  285. #endif
  286. #ifdef BSP_USING_PWM2
  287. rcu_periph_clock_enable(RCU_TIMER2);
  288. #endif
  289. #ifdef BSP_USING_PWM3
  290. rcu_periph_clock_enable(RCU_TIMER3);
  291. #endif
  292. #ifdef BSP_USING_PWM4
  293. rcu_periph_clock_enable(RCU_TIMER4);
  294. #endif
  295. rcu_periph_clock_enable(RCU_AF);
  296. for (i = 0; i < sizeof(pwm_obj) / sizeof(pwm_obj[0]); i++)
  297. {
  298. pwm_obj[i].config = &pwm_config[i];
  299. rt_device_pwm_register(&pwm_obj[i].pwm_device, pwm_config[i].name, &gd32_drv_ops, pwm_obj[i].config);
  300. gd32_pwm_init(&pwm_config[i]);
  301. }
  302. return result;
  303. }
  304. INIT_DEVICE_EXPORT(rt_pwm_init);
  305. #endif /* RT_USING_PWM */