drv_pwm.c 8.2 KB

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