drv_pwm.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. /*
  2. * Copyright (c) 2022 hpm
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2022-01-11 will First version
  9. */
  10. #include <rtthread.h>
  11. #ifdef BSP_USING_PWM
  12. #include <rthw.h>
  13. #include <rtdevice.h>
  14. #include "board.h"
  15. #include "drv_gpio.h"
  16. #include "hpm_pwm_drv.h"
  17. #include "hpm_clock_drv.h"
  18. static PWM_Type * pwm_base_tbl[4] = {HPM_PWM0, HPM_PWM1, HPM_PWM2, HPM_PWM3};
  19. static const clock_name_t pwm_clock_tbl[4] = {clock_mot0, clock_mot1, clock_mot2, clock_mot3};
  20. rt_err_t hpm_generate_central_aligned_waveform(uint8_t pwm_index, uint8_t channel, uint32_t period, uint32_t pulse)
  21. {
  22. uint8_t cmp_index = 0;
  23. uint32_t duty;
  24. pwm_cmp_config_t cmp_config[4] = {0};
  25. pwm_config_t pwm_config = {0};
  26. uint32_t reload = 0;
  27. uint32_t freq;
  28. PWM_Type * pwm_name_index;
  29. clock_name_t pwm_clock;
  30. pwm_clock = pwm_clock_tbl[pwm_index];
  31. pwm_name_index = pwm_base_tbl[pwm_index];
  32. freq = clock_get_frequency(pwm_clock);
  33. if(period != 0) {
  34. reload = (uint64_t)freq * period / 1000000000;
  35. } else {
  36. reload = 0;
  37. }
  38. pwm_stop_counter(pwm_name_index);
  39. pwm_get_default_pwm_config(pwm_name_index, &pwm_config);
  40. /*
  41. * reload and start counter
  42. */
  43. pwm_set_reload(pwm_name_index, 0, reload);
  44. pwm_set_start_count(pwm_name_index, 0, 0);
  45. /*
  46. * config cmp1 and cmp2 and cmp3
  47. */
  48. cmp_config[0].mode = pwm_cmp_mode_output_compare;
  49. cmp_config[0].cmp = reload + 1;
  50. cmp_config[0].update_trigger = pwm_shadow_register_update_on_hw_event;
  51. cmp_config[1].mode = pwm_cmp_mode_output_compare;
  52. cmp_config[1].cmp = reload + 1;
  53. cmp_config[1].update_trigger = pwm_shadow_register_update_on_hw_event;
  54. cmp_config[3].mode = pwm_cmp_mode_output_compare;
  55. cmp_config[3].cmp = reload;
  56. cmp_config[3].update_trigger = pwm_shadow_register_update_on_modify;
  57. pwm_config.enable_output = true;
  58. pwm_config.dead_zone_in_half_cycle = 0;
  59. pwm_config.invert_output = true;
  60. /*
  61. * config pwm
  62. */
  63. if (status_success != pwm_setup_waveform(pwm_name_index, channel, &pwm_config, channel * 2, cmp_config, 2)) {
  64. return RT_FALSE;
  65. }
  66. pwm_load_cmp_shadow_on_capture(pwm_name_index, cmp_index + 17, 0);
  67. pwm_config_cmp(pwm_name_index, cmp_index + 17, &cmp_config[3]);
  68. pwm_start_counter(pwm_name_index);
  69. pwm_issue_shadow_register_lock_event(pwm_name_index);
  70. duty = (uint64_t)freq * pulse / 1000000000;
  71. pwm_update_raw_cmp_central_aligned(pwm_name_index, channel * 2, channel * 2 + 1, (reload - duty) >> 1, (reload + duty) >> 1);
  72. return RT_TRUE;
  73. }
  74. rt_err_t hpm_set_central_aligned_waveform(uint8_t pwm_index, uint8_t channel, uint32_t period, uint32_t pulse)
  75. {
  76. uint8_t cmp_index = 0;
  77. uint32_t duty;
  78. pwm_cmp_config_t cmp_config[4] = {0};
  79. pwm_config_t pwm_config = {0};
  80. uint32_t reload = 0;
  81. uint32_t freq;
  82. PWM_Type * pwm_name_index;
  83. clock_name_t pwm_clock;
  84. pwm_clock = pwm_clock_tbl[pwm_index];
  85. pwm_name_index = pwm_base_tbl[pwm_index];
  86. freq = clock_get_frequency(pwm_clock);
  87. if(period != 0) {
  88. reload = (uint64_t)freq * period / 1000000000;
  89. } else {
  90. reload = 0;
  91. }
  92. pwm_get_default_pwm_config(pwm_name_index, &pwm_config);
  93. pwm_set_reload(pwm_name_index, 0, reload);
  94. cmp_config[3].mode = pwm_cmp_mode_output_compare;
  95. cmp_config[3].cmp = reload;
  96. cmp_config[3].update_trigger = pwm_shadow_register_update_on_modify;
  97. // pwm_load_cmp_shadow_on_capture(pwm_name_index, cmp_index + 4, 0);
  98. pwm_config_cmp(pwm_name_index, cmp_index + 4, &cmp_config[3]);
  99. pwm_issue_shadow_register_lock_event(pwm_name_index);
  100. duty = (uint64_t)freq * pulse / 1000000000;
  101. pwm_update_raw_cmp_central_aligned(pwm_name_index, channel * 2, channel * 2 + 1, (reload - duty) >> 1, (reload + duty) >> 1);
  102. return RT_TRUE;
  103. }
  104. rt_err_t hpm_disable_pwm(uint8_t pwm_index, uint8_t channel)
  105. {
  106. pwm_disable_output(pwm_base_tbl[pwm_index], channel);
  107. return RT_TRUE;
  108. }
  109. rt_err_t hpm_pwm_control(struct rt_device_pwm * device, int cmd, void *arg)
  110. {
  111. uint8_t channel;
  112. uint32_t period;
  113. uint32_t pulse;
  114. rt_err_t sta = RT_TRUE;
  115. unsigned char pwm_name;
  116. struct rt_pwm_configuration * configuration;
  117. configuration = (struct rt_pwm_configuration * )arg;
  118. channel = configuration->channel;
  119. period = configuration->period;
  120. pulse = configuration->pulse;
  121. if (strcmp("pwm0", device->parent.parent.name) == 0) {
  122. pwm_name = 0;
  123. } else if (strcmp("pwm1", device->parent.parent.name) == 0) {
  124. pwm_name = 1;
  125. } else if (strcmp("pwm2", device->parent.parent.name) == 0) {
  126. pwm_name = 2;
  127. } else if (strcmp("pwm3", device->parent.parent.name) == 0) {
  128. pwm_name = 3;
  129. } else {
  130. return RT_FALSE;
  131. }
  132. switch(cmd) {
  133. case PWM_CMD_ENABLE: {
  134. sta = hpm_generate_central_aligned_waveform(pwm_name, channel, period, pulse);
  135. break;
  136. }
  137. case PWM_CMD_DISABLE: {
  138. hpm_disable_pwm(pwm_name, channel);
  139. break;
  140. }
  141. case PWM_CMD_SET: {
  142. sta = hpm_set_central_aligned_waveform(pwm_name, channel, period, pulse);
  143. break;
  144. }
  145. case PWM_CMD_GET: {
  146. sta = RT_TRUE;
  147. break;
  148. }
  149. default: {
  150. sta = RT_FALSE;
  151. break;
  152. }
  153. }
  154. return sta;
  155. }
  156. rt_err_t hpm_pwm_dev_control(rt_device_t device, int cmd, void *arg)
  157. {
  158. uint8_t channel;
  159. uint32_t period;
  160. uint32_t pulse;
  161. rt_err_t sta = RT_TRUE;
  162. uint8_t pwm_name;
  163. struct rt_pwm_configuration * configuration;
  164. configuration = (struct rt_pwm_configuration * )arg;
  165. channel = configuration->channel;
  166. period = configuration->period;
  167. pulse = configuration->pulse;
  168. if (strcmp("pwm0", device->parent.name) == 0) {
  169. pwm_name = 0;
  170. } else if (strcmp("pwm1", device->parent.name) == 0) {
  171. pwm_name = 1;
  172. } else if (strcmp("pwm2", device->parent.name) == 0) {
  173. pwm_name = 2;
  174. } else if (strcmp("pwm3", device->parent.name) == 0) {
  175. pwm_name = 3;
  176. } else {
  177. return RT_FALSE;
  178. }
  179. switch(cmd) {
  180. case PWM_CMD_ENABLE: {
  181. sta = hpm_generate_central_aligned_waveform(pwm_name, channel, period, pulse);
  182. break;
  183. }
  184. case PWM_CMD_DISABLE: {
  185. hpm_disable_pwm(pwm_name, channel);
  186. break;
  187. }
  188. case PWM_CMD_SET: {
  189. sta = hpm_set_central_aligned_waveform(pwm_name, channel, period, pulse);
  190. break;
  191. }
  192. case PWM_CMD_GET: {
  193. sta = RT_TRUE;
  194. break;
  195. }
  196. default: {
  197. sta = RT_FALSE;
  198. break;
  199. }
  200. }
  201. return sta;
  202. }
  203. const static struct rt_pwm_ops hpm_pwm_ops = {
  204. .control = &hpm_pwm_control
  205. };
  206. static struct rt_device hpm_pwm_parent = {
  207. .control = hpm_pwm_dev_control
  208. };
  209. static struct rt_device_pwm hpm_dev_pwm0 = {
  210. .ops = &hpm_pwm_ops,
  211. };
  212. static struct rt_device_pwm hpm_dev_pwm1 = {
  213. .ops = &hpm_pwm_ops,
  214. };
  215. static struct rt_device_pwm hpm_dev_pwm2 = {
  216. .ops = &hpm_pwm_ops,
  217. };
  218. static struct rt_device_pwm hpm_dev_pwm3 = {
  219. .ops = &hpm_pwm_ops,
  220. };
  221. int rt_hw_pwm_init(void)
  222. {
  223. int ret = RT_EOK;
  224. hpm_dev_pwm0.parent = hpm_pwm_parent;
  225. hpm_dev_pwm1.parent = hpm_pwm_parent;
  226. hpm_dev_pwm2.parent = hpm_pwm_parent;
  227. hpm_dev_pwm3.parent = hpm_pwm_parent;
  228. ret = rt_device_pwm_register(&hpm_dev_pwm0, "pwm0", &hpm_pwm_ops, RT_NULL);
  229. ret = rt_device_pwm_register(&hpm_dev_pwm1, "pwm1", &hpm_pwm_ops, RT_NULL);
  230. ret = rt_device_pwm_register(&hpm_dev_pwm2, "pwm2", &hpm_pwm_ops, RT_NULL);
  231. ret = rt_device_pwm_register(&hpm_dev_pwm3, "pwm3", &hpm_pwm_ops, RT_NULL);
  232. return ret;
  233. }
  234. INIT_BOARD_EXPORT(rt_hw_pwm_init);
  235. #endif /* BSP_USING_GPIO */