drv_pwm.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593
  1. /*
  2. * Copyright (c) 2006-2023
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2023-06-05 zengjianwei first version
  9. * 2025-06-23 Yucai Liu Support for non-complementary PWM output with advanced timers
  10. */
  11. #include <board.h>
  12. #include <gd32f30x.h>
  13. #include <rtdevice.h>
  14. #include <rtthread.h>
  15. #ifdef RT_USING_PWM
  16. /* #define DRV_DEBUG */
  17. #define LOG_TAG "drv.pwm"
  18. #include <rtdbg.h>
  19. #define MAX_PERIOD 65535
  20. #define MIN_PERIOD 3
  21. #define MIN_PULSE 2
  22. typedef struct
  23. {
  24. rt_int8_t TimerIndex; /* timer index:0~13 */
  25. rt_uint32_t Port; /* gpio port:GPIOA/GPIOB/GPIOC/... */
  26. rt_uint32_t pin; /* gpio pin:GPIO_PIN_0~GPIO_PIN_15 */
  27. /* timer channel: -2 is ch_1n, -1 is ch_0n, 0 is ch0, 1 is ch1 */
  28. rt_int16_t channel;
  29. char *name;
  30. } TIMER_PORT_CHANNEL_MAP_S;
  31. struct gd32_pwm
  32. {
  33. struct rt_device_pwm pwm_device;
  34. TIMER_PORT_CHANNEL_MAP_S tim_handle;
  35. };
  36. static struct gd32_pwm gd32_pwm_obj[] = {
  37. #ifdef RT_USING_PWM1
  38. {.tim_handle = {3, GPIOB, GPIO_PIN_8, 2, "pwm1"}},
  39. #endif
  40. #ifdef RT_USING_PWM2
  41. {.tim_handle = {3, GPIOB, GPIO_PIN_8, 2, "pwm2"}},
  42. #endif
  43. #ifdef RT_USING_PWM3
  44. {.tim_handle = {3, GPIOB, GPIO_PIN_8, 2, "pwm3"}},
  45. #endif
  46. #ifdef RT_USING_PWM4
  47. {.tim_handle = {3, GPIOB, GPIO_PIN_8, 2, "pwm4"}},
  48. #endif
  49. #ifdef RT_USING_PWM5
  50. {.tim_handle = {3, GPIOB, GPIO_PIN_8, 2, "pwm5"}},
  51. #endif
  52. #ifdef RT_USING_PWM6
  53. {.tim_handle = {3, GPIOB, GPIO_PIN_8, 2, "pwm6"}},
  54. #endif
  55. #ifdef RT_USING_PWM7
  56. {.tim_handle = {3, GPIOB, GPIO_PIN_8, 2, "pwm7"}},
  57. #endif
  58. #ifdef RT_USING_PWM8
  59. {.tim_handle = {3, GPIOB, GPIO_PIN_8, 2, "pwm8"}},
  60. #endif
  61. #ifdef RT_USING_PWM9
  62. {.tim_handle = {3, GPIOB, GPIO_PIN_8, 2, "pwm9"}},
  63. #endif
  64. #ifdef RT_USING_PWM10
  65. {.tim_handle = {3, GPIOB, GPIO_PIN_8, 2, "pwm10"}},
  66. #endif
  67. #ifdef RT_USING_PWM11
  68. {.tim_handle = {3, GPIOB, GPIO_PIN_8, 2, "pwm11"}},
  69. #endif
  70. #ifdef RT_USING_PWM12
  71. {.tim_handle = {3, GPIOB, GPIO_PIN_8, 2, "pwm12"}},
  72. #endif
  73. #ifdef RT_USING_PWM13
  74. {.tim_handle = {3, GPIOB, GPIO_PIN_8, 2, "pwm13"}},
  75. #endif
  76. #ifdef RT_USING_PWM14
  77. {.tim_handle = {3, GPIOB, GPIO_PIN_8, 2, "pwm14"}},
  78. #endif
  79. };
  80. typedef struct
  81. {
  82. rt_uint32_t Port[7];
  83. rt_int8_t TimerIndex[14];
  84. } TIMER_PERIPH_LIST_S;
  85. static TIMER_PERIPH_LIST_S gd32_timer_periph_list = {
  86. .Port = {0, 0, 0, 0, 0, 0, 0},
  87. .TimerIndex = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
  88. };
  89. /*
  90. * 将所有用到的 gpio port 和 timer 不重复地列举出来,以方便后面不重复地初始化
  91. */
  92. static rt_err_t pwm_find_timer_periph(void)
  93. {
  94. rt_int16_t i, j, k;
  95. /* find gpio port of defined table */
  96. for (i = 0; i < sizeof(gd32_pwm_obj) / sizeof(gd32_pwm_obj[0]); ++i)
  97. {
  98. /* find -1 of gd32_periph_list's member of Port */
  99. for (j = 0; j < sizeof(gd32_timer_periph_list.Port) / sizeof(gd32_timer_periph_list.Port[0]); ++j)
  100. {
  101. if (0 == gd32_timer_periph_list.Port[j])
  102. {
  103. break;
  104. }
  105. }
  106. if (j >= sizeof(gd32_timer_periph_list.Port) / sizeof(gd32_timer_periph_list.Port[0]))
  107. {
  108. LOG_E("Can not find -1 of gd32_periph_list's member of Port!\n");
  109. break;
  110. }
  111. /* find the different of Port */
  112. for (k = 0; k < j; ++k)
  113. {
  114. if (gd32_pwm_obj[i].tim_handle.Port == gd32_timer_periph_list.Port[k])
  115. {
  116. break;
  117. }
  118. }
  119. /* if can not find the same Port */
  120. if (k == j)
  121. {
  122. gd32_timer_periph_list.Port[j] = gd32_pwm_obj[i].tim_handle.Port;
  123. }
  124. }
  125. /* find timer periph of defined table */
  126. for (i = 0; i < sizeof(gd32_pwm_obj) / sizeof(gd32_pwm_obj[0]); ++i)
  127. {
  128. /* find -1 of gd32_periph_list's member of TimerIndex */
  129. for (j = 0; j < sizeof(gd32_timer_periph_list.TimerIndex) / sizeof(gd32_timer_periph_list.TimerIndex[0]); ++j)
  130. {
  131. if (-1 == gd32_timer_periph_list.TimerIndex[j])
  132. {
  133. break;
  134. }
  135. }
  136. if (j >= sizeof(gd32_timer_periph_list.TimerIndex) / sizeof(gd32_timer_periph_list.TimerIndex[0]))
  137. {
  138. LOG_E("Can not find -1 of gd32_periph_list's member of TimerIndex!\n");
  139. break;
  140. }
  141. /* find the different of TimerIndex */
  142. for (k = 0; k < j; ++k)
  143. {
  144. if (gd32_pwm_obj[i].tim_handle.TimerIndex == gd32_timer_periph_list.TimerIndex[k])
  145. {
  146. break;
  147. }
  148. }
  149. /* if can not find the same TimerIndex */
  150. if (k == j)
  151. {
  152. gd32_timer_periph_list.TimerIndex[j] = gd32_pwm_obj[i].tim_handle.TimerIndex;
  153. }
  154. }
  155. return RT_EOK;
  156. }
  157. static rt_uint32_t index_to_timer(rt_int8_t TimerIndex)
  158. {
  159. switch (TimerIndex)
  160. {
  161. case 0:
  162. return TIMER0;
  163. case 1:
  164. return TIMER1;
  165. case 2:
  166. return TIMER2;
  167. case 3:
  168. return TIMER3;
  169. case 4:
  170. return TIMER4;
  171. case 5:
  172. return TIMER5;
  173. case 6:
  174. return TIMER6;
  175. case 7:
  176. return TIMER7;
  177. case 8:
  178. return TIMER8;
  179. case 9:
  180. return TIMER9;
  181. case 10:
  182. return TIMER10;
  183. case 11:
  184. return TIMER11;
  185. case 12:
  186. return TIMER12;
  187. case 13:
  188. return TIMER13;
  189. default:
  190. LOG_E("Unsport timer periph!\n");
  191. }
  192. return TIMER0;
  193. }
  194. static void gpio_clock_enable(rt_uint32_t Port)
  195. {
  196. switch (Port)
  197. {
  198. case GPIOA:
  199. rcu_periph_clock_enable(RCU_GPIOA);
  200. break;
  201. case GPIOB:
  202. rcu_periph_clock_enable(RCU_GPIOB);
  203. break;
  204. case GPIOC:
  205. rcu_periph_clock_enable(RCU_GPIOC);
  206. break;
  207. case GPIOD:
  208. rcu_periph_clock_enable(RCU_GPIOD);
  209. break;
  210. case GPIOE:
  211. rcu_periph_clock_enable(RCU_GPIOE);
  212. break;
  213. case GPIOF:
  214. rcu_periph_clock_enable(RCU_GPIOF);
  215. break;
  216. case GPIOG:
  217. rcu_periph_clock_enable(RCU_GPIOG);
  218. break;
  219. default:
  220. LOG_E("Unsport gpio port!\n");
  221. }
  222. }
  223. static void timer_clock_enable(rt_int8_t TimerIndex)
  224. {
  225. switch (TimerIndex)
  226. {
  227. case 0:
  228. rcu_periph_clock_enable(RCU_TIMER0);
  229. break;
  230. case 1:
  231. rcu_periph_clock_enable(RCU_TIMER1);
  232. break;
  233. case 2:
  234. rcu_periph_clock_enable(RCU_TIMER2);
  235. break;
  236. case 3:
  237. rcu_periph_clock_enable(RCU_TIMER3);
  238. break;
  239. case 4:
  240. rcu_periph_clock_enable(RCU_TIMER4);
  241. break;
  242. case 5:
  243. rcu_periph_clock_enable(RCU_TIMER5);
  244. break;
  245. case 6:
  246. rcu_periph_clock_enable(RCU_TIMER6);
  247. break;
  248. case 7:
  249. rcu_periph_clock_enable(RCU_TIMER7);
  250. break;
  251. #ifndef GD32F30X_HD
  252. case 8:
  253. rcu_periph_clock_enable(RCU_TIMER8);
  254. break;
  255. case 9:
  256. rcu_periph_clock_enable(RCU_TIMER9);
  257. break;
  258. case 10:
  259. rcu_periph_clock_enable(RCU_TIMER10);
  260. break;
  261. case 11:
  262. rcu_periph_clock_enable(RCU_TIMER11);
  263. break;
  264. case 12:
  265. rcu_periph_clock_enable(RCU_TIMER12);
  266. break;
  267. case 13:
  268. rcu_periph_clock_enable(RCU_TIMER13);
  269. break;
  270. #endif
  271. default:
  272. LOG_E("Unsport timer periph!\n");
  273. }
  274. }
  275. static void rcu_config(void)
  276. {
  277. rt_int16_t i;
  278. for (i = 0; i < sizeof(gd32_timer_periph_list.Port) / sizeof(gd32_timer_periph_list.Port[0]); ++i)
  279. {
  280. if (0 == gd32_timer_periph_list.Port[i])
  281. {
  282. break;
  283. }
  284. /* enable GPIO clock */
  285. gpio_clock_enable(gd32_timer_periph_list.Port[i]);
  286. }
  287. rcu_periph_clock_enable(RCU_AF);
  288. for (i = 0; i < sizeof(gd32_timer_periph_list.TimerIndex) / sizeof(gd32_timer_periph_list.TimerIndex[0]); ++i)
  289. {
  290. if (-1 == gd32_timer_periph_list.TimerIndex[i])
  291. {
  292. break;
  293. }
  294. /* enable timer clock */
  295. timer_clock_enable(gd32_timer_periph_list.TimerIndex[i]);
  296. timer_deinit(index_to_timer(gd32_timer_periph_list.TimerIndex[i]));
  297. }
  298. }
  299. static void gpio_config(void)
  300. {
  301. rt_int16_t i;
  302. /* config the GPIO as analog mode */
  303. for (i = 0; i < sizeof(gd32_pwm_obj) / sizeof(gd32_pwm_obj[0]); ++i)
  304. {
  305. gpio_init(gd32_pwm_obj[i].tim_handle.Port, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, gd32_pwm_obj[i].tim_handle.pin);
  306. }
  307. }
  308. static void timer_init_para(timer_parameter_struct *initpara)
  309. {
  310. rt_int16_t i;
  311. for (i = 0; i < sizeof(gd32_timer_periph_list.TimerIndex) / sizeof(gd32_timer_periph_list.TimerIndex[0]); ++i)
  312. {
  313. /* config timer */
  314. if (-1 != gd32_timer_periph_list.TimerIndex[i])
  315. {
  316. timer_init(index_to_timer(gd32_timer_periph_list.TimerIndex[i]), initpara);
  317. }
  318. }
  319. }
  320. static void channel_output_config(timer_oc_parameter_struct *ocpara)
  321. {
  322. rt_int16_t i;
  323. rt_uint32_t timer_periph;
  324. /* config the channel config */
  325. for (i = 0; i < sizeof(gd32_pwm_obj) / sizeof(gd32_pwm_obj[0]); ++i)
  326. {
  327. if (gd32_pwm_obj[i].tim_handle.channel < 0)
  328. {
  329. ocpara->outputstate = TIMER_CCX_DISABLE;
  330. ocpara->outputnstate = TIMER_CCXN_ENABLE;
  331. gd32_pwm_obj[i].tim_handle.channel = -(gd32_pwm_obj[i].tim_handle.channel + 1);
  332. }
  333. timer_periph = index_to_timer(gd32_pwm_obj[i].tim_handle.TimerIndex);
  334. timer_channel_output_config(timer_periph, gd32_pwm_obj[i].tim_handle.channel, ocpara);
  335. timer_channel_output_pulse_value_config(timer_periph, gd32_pwm_obj[i].tim_handle.channel, 7999);
  336. timer_channel_output_mode_config(timer_periph, gd32_pwm_obj[i].tim_handle.channel, TIMER_OC_MODE_PWM0);
  337. timer_channel_output_shadow_config(timer_periph, gd32_pwm_obj[i].tim_handle.channel, TIMER_OC_SHADOW_DISABLE);
  338. /* auto-reload preload shadow reg enable */
  339. /* timer_auto_reload_shadow_enable(timer_periph); */
  340. timer_channel_output_state_config(timer_periph, gd32_pwm_obj[i].tim_handle.channel, TIMER_CCX_DISABLE);
  341. timer_channel_complementary_output_state_config(timer_periph, gd32_pwm_obj[i].tim_handle.channel, TIMER_CCXN_DISABLE);
  342. }
  343. /* enable timer */
  344. for (i = 0; i < sizeof(gd32_timer_periph_list.TimerIndex) / sizeof(gd32_timer_periph_list.TimerIndex[0]); ++i)
  345. {
  346. if (-1 != gd32_timer_periph_list.TimerIndex[i])
  347. {
  348. timer_periph = index_to_timer(gd32_timer_periph_list.TimerIndex[i]);
  349. if (timer_periph == TIMER0 || timer_periph == TIMER7)
  350. {
  351. timer_primary_output_config(timer_periph, ENABLE);
  352. }
  353. timer_enable(timer_periph);
  354. }
  355. }
  356. }
  357. static void timer_config(void)
  358. {
  359. timer_oc_parameter_struct timer_ocintpara;
  360. timer_parameter_struct timer_initpara;
  361. /* TIMER configuration */
  362. timer_initpara.prescaler = 119;
  363. timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
  364. timer_initpara.counterdirection = TIMER_COUNTER_UP;
  365. timer_initpara.period = 15999;
  366. timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
  367. timer_initpara.repetitioncounter = 0;
  368. timer_init_para(&timer_initpara);
  369. /* CHX configuration in PWM mode */
  370. timer_ocintpara.outputstate = TIMER_CCX_ENABLE;
  371. timer_ocintpara.outputnstate = TIMER_CCXN_DISABLE;
  372. timer_ocintpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
  373. timer_ocintpara.ocnpolarity = TIMER_OCN_POLARITY_HIGH;
  374. timer_ocintpara.ocidlestate = TIMER_OC_IDLE_STATE_LOW;
  375. timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
  376. channel_output_config(&timer_ocintpara);
  377. }
  378. static rt_err_t drv_pwm_enable(TIMER_PORT_CHANNEL_MAP_S *pstTimerMap, struct rt_pwm_configuration *configuration,
  379. rt_bool_t enable)
  380. {
  381. if (!enable)
  382. {
  383. timer_channel_output_state_config(index_to_timer(pstTimerMap->TimerIndex), configuration->channel,
  384. TIMER_CCX_DISABLE);
  385. }
  386. else
  387. {
  388. if (configuration->complementary == RT_TRUE)
  389. {
  390. timer_channel_output_state_config(
  391. index_to_timer(pstTimerMap->TimerIndex), configuration->channel - 1, TIMER_CCXN_ENABLE);
  392. }
  393. else
  394. {
  395. timer_channel_output_state_config(
  396. index_to_timer(pstTimerMap->TimerIndex), configuration->channel, TIMER_CCX_ENABLE);
  397. }
  398. }
  399. return RT_EOK;
  400. }
  401. static rt_err_t drv_pwm_get(TIMER_PORT_CHANNEL_MAP_S *pstTimerMap, struct rt_pwm_configuration *configuration)
  402. {
  403. rt_uint64_t tim_clock;
  404. rt_uint16_t psc;
  405. rt_uint32_t chxcv;
  406. tim_clock = rcu_clock_freq_get(CK_SYS);
  407. psc = timer_prescaler_read(index_to_timer(pstTimerMap->TimerIndex));
  408. if (psc == TIMER_CKDIV_DIV2)
  409. {
  410. tim_clock = tim_clock / 2;
  411. }
  412. else if (psc == TIMER_CKDIV_DIV4)
  413. {
  414. tim_clock = tim_clock / 4;
  415. }
  416. chxcv = timer_channel_capture_value_register_read(index_to_timer(pstTimerMap->TimerIndex), configuration->channel);
  417. /* Convert nanosecond to frequency and duty cycle. 1s = 1 * 1000 * 1000 * 1000 ns */
  418. tim_clock /= 1000000UL;
  419. configuration->period = (TIMER_CAR(index_to_timer(pstTimerMap->TimerIndex)) + 1) * (psc + 1) * 1000UL / tim_clock;
  420. configuration->pulse = (chxcv + 1) * (psc + 1) * 1000UL / tim_clock;
  421. return RT_EOK;
  422. }
  423. static rt_err_t drv_pwm_set(TIMER_PORT_CHANNEL_MAP_S *pstTimerMap, struct rt_pwm_configuration *configuration)
  424. {
  425. rt_uint32_t period, pulse;
  426. rt_uint64_t tim_clock, psc;
  427. tim_clock = rcu_clock_freq_get(CK_SYS);
  428. /* Convert nanosecond to frequency and duty cycle. 1s = 1 * 1000 * 1000 * 1000 ns */
  429. tim_clock /= 1000000UL;
  430. period = (unsigned long long)configuration->period * tim_clock / 1000ULL;
  431. psc = period / MAX_PERIOD + 1;
  432. period = period / psc;
  433. timer_prescaler_config(index_to_timer(pstTimerMap->TimerIndex), psc - 1, TIMER_PSC_RELOAD_NOW);
  434. if (period < MIN_PERIOD)
  435. {
  436. period = MIN_PERIOD;
  437. }
  438. timer_autoreload_value_config(index_to_timer(pstTimerMap->TimerIndex), period - 1);
  439. pulse = (unsigned long long)configuration->pulse * tim_clock / psc / 1000ULL;
  440. if (pulse < MIN_PULSE)
  441. {
  442. pulse = MIN_PULSE;
  443. }
  444. else if (pulse > period)
  445. {
  446. pulse = period;
  447. }
  448. timer_channel_output_pulse_value_config(index_to_timer(pstTimerMap->TimerIndex), configuration->channel, pulse);
  449. timer_counter_value_config(index_to_timer(pstTimerMap->TimerIndex), 0);
  450. /* Update frequency value */
  451. timer_event_software_generate(index_to_timer(pstTimerMap->TimerIndex), TIMER_EVENT_SRC_UPG);
  452. return RT_EOK;
  453. }
  454. static rt_err_t drv_pwm_control(struct rt_device_pwm *device, int cmd, void *arg)
  455. {
  456. struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)arg;
  457. TIMER_PORT_CHANNEL_MAP_S *pstTimerMap = (TIMER_PORT_CHANNEL_MAP_S *)device->parent.user_data;
  458. switch (cmd)
  459. {
  460. case PWM_CMD_ENABLE:
  461. return drv_pwm_enable(pstTimerMap, configuration, RT_TRUE);
  462. case PWM_CMD_DISABLE:
  463. return drv_pwm_enable(pstTimerMap, configuration, RT_FALSE);
  464. case PWM_CMD_SET:
  465. return drv_pwm_set(pstTimerMap, configuration);
  466. case PWM_CMD_GET:
  467. return drv_pwm_get(pstTimerMap, configuration);
  468. default:
  469. return -RT_EINVAL;
  470. }
  471. }
  472. static struct rt_pwm_ops drv_ops = {drv_pwm_control};
  473. static rt_err_t gd32_hw_pwm_init(void)
  474. {
  475. pwm_find_timer_periph();
  476. rcu_config();
  477. gpio_config();
  478. timer_config();
  479. return RT_EOK;
  480. }
  481. static int gd32_pwm_init(void)
  482. {
  483. int i = 0;
  484. int result = RT_EOK;
  485. /* pwm init */
  486. if (gd32_hw_pwm_init() != RT_EOK)
  487. {
  488. LOG_E("PWM init failed");
  489. result = -RT_ERROR;
  490. goto __exit;
  491. }
  492. LOG_D("PWM init success");
  493. for (i = 0; i < sizeof(gd32_pwm_obj) / sizeof(gd32_pwm_obj[0]); i++)
  494. {
  495. /* register pwm device */
  496. if (rt_device_pwm_register(&gd32_pwm_obj[i].pwm_device, gd32_pwm_obj[i].tim_handle.name, &drv_ops,
  497. &gd32_pwm_obj[i].tim_handle)== RT_EOK )
  498. {
  499. LOG_D("%s register success", gd32_pwm_obj[i].tim_handle.name);
  500. }
  501. else
  502. {
  503. LOG_E("%s register failed", gd32_pwm_obj[i].tim_handle.name);
  504. result = -RT_ERROR;
  505. }
  506. }
  507. __exit:
  508. return result;
  509. }
  510. INIT_DEVICE_EXPORT(gd32_pwm_init);
  511. #endif /* RT_USING_PWM */