drv_pwm.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. /*
  2. * Copyright (c) 2022-2024 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. * 2023-06-10 HPMicro Add PWMv2 support
  12. */
  13. #include <rtthread.h>
  14. #if defined(BSP_USING_PWM) || defined(BSP_USING_PWMV2)
  15. #if defined(BSP_USING_PWMV2)
  16. #define HPMSOC_HAS_HPMSDK_PWMV2
  17. #endif
  18. #include <rthw.h>
  19. #include <rtdevice.h>
  20. #include "board.h"
  21. #include "drv_gpio.h"
  22. #if defined(HPMSOC_HAS_HPMSDK_PWMV2)
  23. #include "hpm_pwmv2_drv.h"
  24. #else
  25. #include "hpm_pwm_drv.h"
  26. #endif
  27. #include "hpm_clock_drv.h"
  28. #ifdef HPM_PWM3
  29. #define PWM_INSTANCE_NUM 4
  30. #elif defined(HPM_PWM2)
  31. #define PWM_INSTANCE_NUM 3
  32. #elif defined(HPM_PWM1)
  33. #define PWM_INSTANCE_NUM 2
  34. #else
  35. #define PWM_INSTANCE_NUM 1
  36. #endif
  37. #if defined(HPMSOC_HAS_HPMSDK_PWMV2)
  38. static PWMV2_Type * pwm_base_tbl[PWM_INSTANCE_NUM] = {
  39. #else
  40. static PWM_Type * pwm_base_tbl[PWM_INSTANCE_NUM] = {
  41. #endif
  42. HPM_PWM0,
  43. #ifdef HPM_PWM1
  44. HPM_PWM1,
  45. #endif
  46. #ifdef HPM_PWM2
  47. HPM_PWM2,
  48. #endif
  49. #ifdef HPM_PWM3
  50. HPM_PWM3
  51. #endif
  52. };
  53. #if defined(HPMSOC_HAS_HPMSDK_PWMV2)
  54. #ifdef PWMV2_CNT_3
  55. #define PWMV2_CNT_NUM 4
  56. #elif PWMV2_CNT_2
  57. #define PWMV2_CNT_NUM 3
  58. #elif PWMV2_CNT_1
  59. #define PWMV2_CNT_NUM 2
  60. #else
  61. #define PWMV2_CNT_NUM 1
  62. #endif
  63. static pwm_counter_t pwmv2_counter_tbl[PWMV2_CNT_NUM * 2] = {
  64. pwm_counter_0,
  65. pwm_counter_0,
  66. #ifdef PWMV2_CNT_1
  67. pwm_counter_1,
  68. pwm_counter_1,
  69. #endif
  70. #ifdef PWMV2_CNT_2
  71. pwm_counter_2,
  72. pwm_counter_2,
  73. #endif
  74. #ifdef PWMV2_CNT_3
  75. pwm_counter_3,
  76. pwm_counter_3,
  77. #endif
  78. };
  79. #endif
  80. #if defined(HPMSOC_HAS_HPMSDK_PWMV2)
  81. extern uint32_t rtt_board_init_pwm_clock(PWMV2_Type *ptr);
  82. #else
  83. extern uint32_t rtt_board_init_pwm_clock(PWM_Type *ptr);
  84. #endif
  85. rt_err_t hpm_generate_central_aligned_waveform(uint8_t pwm_index, uint8_t channel, uint32_t period, uint32_t pulse)
  86. {
  87. #if defined(HPMSOC_HAS_HPMSDK_PWMV2)
  88. PWMV2_Type * pwm_base;
  89. pwm_counter_t pwm_counter;
  90. #else
  91. PWM_Type * pwm_base;
  92. pwm_cmp_config_t cmp_config[2] = {0};
  93. pwm_config_t pwm_config = {0};
  94. #endif
  95. uint32_t duty;
  96. uint32_t reload = 0;
  97. uint32_t freq;
  98. pwm_base = pwm_base_tbl[pwm_index];
  99. init_pwm_pins(pwm_base);
  100. freq = rtt_board_init_pwm_clock(pwm_base);
  101. if(period != 0) {
  102. reload = (uint64_t)freq * period / 1000000000;
  103. } else {
  104. reload = 0;
  105. }
  106. duty = (uint64_t)freq * pulse / 1000000000;
  107. #if defined(HPMSOC_HAS_HPMSDK_PWMV2)
  108. pwm_counter = pwmv2_counter_tbl[channel];
  109. pwmv2_disable_counter(pwm_base, pwm_counter);
  110. pwmv2_reset_counter(pwm_base, pwm_counter);
  111. pwmv2_shadow_register_unlock(pwm_base);
  112. pwmv2_set_shadow_val(pwm_base, channel / 2, reload, 0, false); /**< cnt use 0-3 shadow */
  113. pwmv2_set_shadow_val(pwm_base, channel * 2 + 4, reload + 1, 0, false);
  114. pwmv2_set_shadow_val(pwm_base, channel * 2 + 5, reload, 0, false);
  115. pwmv2_counter_select_data_offset_from_shadow_value(pwm_base, pwm_counter, channel / 2);
  116. pwmv2_counter_burst_disable(pwm_base, pwm_counter);
  117. pwmv2_set_reload_update_time(pwm_base, pwm_counter, pwm_reload_update_on_reload);
  118. pwmv2_select_cmp_source(pwm_base, channel * 2, cmp_value_from_shadow_val, channel * 2 + 4);
  119. pwmv2_select_cmp_source(pwm_base, channel * 2 + 1, cmp_value_from_shadow_val, channel * 2 + 5);
  120. pwmv2_shadow_register_lock(pwm_base);
  121. pwmv2_disable_four_cmp(pwm_base, channel);
  122. pwmv2_channel_enable_output(pwm_base, channel);
  123. pwmv2_enable_counter(pwm_base, pwm_counter);
  124. pwmv2_start_pwm_output(pwm_base, pwm_counter);
  125. pwmv2_shadow_register_unlock(pwm_base);
  126. pwmv2_set_shadow_val(pwm_base, channel * 2, (reload - duty) >> 1, 0, false);
  127. pwmv2_set_shadow_val(pwm_base, channel * 2, (reload + duty) >> 1, 0, false);
  128. pwmv2_shadow_register_lock(pwm_base);
  129. #else
  130. pwm_stop_counter(pwm_base);
  131. pwm_get_default_pwm_config(pwm_base, &pwm_config);
  132. /*
  133. * reload and start counter
  134. */
  135. pwm_set_reload(pwm_base, 0, reload);
  136. pwm_set_start_count(pwm_base, 0, 0);
  137. /*
  138. * config cmp1 and cmp2
  139. */
  140. cmp_config[0].mode = pwm_cmp_mode_output_compare;
  141. cmp_config[0].cmp = (reload - duty) >> 1;
  142. cmp_config[0].update_trigger = pwm_shadow_register_update_on_shlk;
  143. cmp_config[1].mode = pwm_cmp_mode_output_compare;
  144. cmp_config[1].cmp = (reload + duty) >> 1;
  145. cmp_config[1].update_trigger = pwm_shadow_register_update_on_shlk;
  146. pwm_config.enable_output = true;
  147. pwm_config.dead_zone_in_half_cycle = 0;
  148. pwm_config.invert_output = false;
  149. /*
  150. * config pwm
  151. */
  152. if (status_success != pwm_setup_waveform(pwm_base, channel, &pwm_config, channel * 2, cmp_config, 2)) {
  153. return -RT_ERROR;
  154. }
  155. pwm_start_counter(pwm_base);
  156. pwm_issue_shadow_register_lock_event(pwm_base);
  157. #endif
  158. return RT_EOK;
  159. }
  160. rt_err_t hpm_set_central_aligned_waveform(uint8_t pwm_index, uint8_t channel, uint32_t period, uint32_t pulse)
  161. {
  162. #if defined(HPMSOC_HAS_HPMSDK_PWMV2)
  163. PWMV2_Type * pwm_base;
  164. #else
  165. PWM_Type * pwm_base;
  166. pwm_config_t pwm_config = {0};
  167. #endif
  168. uint32_t duty;
  169. uint32_t reload = 0;
  170. uint32_t freq;
  171. pwm_base = pwm_base_tbl[pwm_index];
  172. freq = rtt_board_init_pwm_clock(pwm_base);
  173. if(period != 0) {
  174. reload = (uint64_t)freq * period / 1000000000;
  175. } else {
  176. reload = 0;
  177. }
  178. duty = (uint64_t)freq * pulse / 1000000000;
  179. #if defined(HPMSOC_HAS_HPMSDK_PWMV2)
  180. pwmv2_shadow_register_unlock(pwm_base);
  181. pwmv2_set_shadow_val(pwm_base, channel / 2, reload, 0, false); /**< cnt use 0-3 shadow */
  182. pwmv2_set_shadow_val(pwm_base, channel * 2 + 4, (reload - duty) >> 1, 0, false);
  183. pwmv2_set_shadow_val(pwm_base, channel * 2 + 5, (reload + duty) >> 1, 0, false);
  184. pwmv2_shadow_register_lock(pwm_base);
  185. #else
  186. pwm_get_default_pwm_config(pwm_base, &pwm_config);
  187. pwm_set_reload(pwm_base, 0, reload);
  188. pwm_update_raw_cmp_central_aligned(pwm_base, channel * 2, channel * 2 + 1, (reload - duty) >> 1, (reload + duty) >> 1);
  189. pwm_issue_shadow_register_lock_event(pwm_base);
  190. #endif
  191. return RT_EOK;
  192. }
  193. rt_err_t hpm_disable_pwm(uint8_t pwm_index, uint8_t channel)
  194. {
  195. #if defined(HPMSOC_HAS_HPMSDK_PWMV2)
  196. PWMV2_Type * pwm_base;
  197. pwm_base = pwm_base_tbl[pwm_index];
  198. pwmv2_shadow_register_unlock(pwm_base);
  199. pwmv2_set_shadow_val(pwm_base, channel * 2 + 4, 0, 0, false);
  200. pwmv2_set_shadow_val(pwm_base, channel * 2 + 5, 0, 0, false);
  201. pwmv2_shadow_register_lock(pwm_base);
  202. #else
  203. pwm_disable_output(pwm_base_tbl[pwm_index], channel);
  204. #endif
  205. return RT_EOK;
  206. }
  207. rt_err_t hpm_pwm_control(struct rt_device_pwm * device, int cmd, void *arg)
  208. {
  209. uint8_t channel;
  210. uint32_t period;
  211. uint32_t pulse;
  212. rt_err_t sta = RT_EOK;
  213. unsigned char pwm_name;
  214. struct rt_pwm_configuration * configuration;
  215. configuration = (struct rt_pwm_configuration * )arg;
  216. channel = configuration->channel;
  217. period = configuration->period;
  218. pulse = configuration->pulse;
  219. if (strcmp("pwm0", device->parent.parent.name) == 0) {
  220. pwm_name = 0;
  221. } else if (strcmp("pwm1", device->parent.parent.name) == 0) {
  222. pwm_name = 1;
  223. } else if (strcmp("pwm2", device->parent.parent.name) == 0) {
  224. pwm_name = 2;
  225. } else if (strcmp("pwm3", device->parent.parent.name) == 0) {
  226. pwm_name = 3;
  227. } else {
  228. return -RT_ERROR;
  229. }
  230. switch(cmd) {
  231. case PWM_CMD_ENABLE: {
  232. sta = hpm_generate_central_aligned_waveform(pwm_name, channel, period, pulse);
  233. break;
  234. }
  235. case PWM_CMD_DISABLE: {
  236. hpm_disable_pwm(pwm_name, channel);
  237. break;
  238. }
  239. case PWM_CMD_SET: {
  240. sta = hpm_set_central_aligned_waveform(pwm_name, channel, period, pulse);
  241. break;
  242. }
  243. case PWM_CMD_GET: {
  244. sta = RT_EOK;
  245. break;
  246. }
  247. default: {
  248. sta = -RT_ERROR;
  249. break;
  250. }
  251. }
  252. return sta;
  253. }
  254. rt_err_t hpm_pwm_dev_control(rt_device_t device, int cmd, void *arg)
  255. {
  256. uint8_t channel;
  257. uint32_t period;
  258. uint32_t pulse;
  259. rt_err_t sta = RT_EOK;
  260. uint8_t pwm_name;
  261. struct rt_pwm_configuration * configuration;
  262. configuration = (struct rt_pwm_configuration * )arg;
  263. channel = configuration->channel;
  264. period = configuration->period;
  265. pulse = configuration->pulse;
  266. if (strcmp("pwm0", device->parent.name) == 0) {
  267. pwm_name = 0;
  268. } else if (strcmp("pwm1", device->parent.name) == 0) {
  269. pwm_name = 1;
  270. } else if (strcmp("pwm2", device->parent.name) == 0) {
  271. pwm_name = 2;
  272. } else if (strcmp("pwm3", device->parent.name) == 0) {
  273. pwm_name = 3;
  274. } else {
  275. return -RT_ERROR;
  276. }
  277. switch(cmd) {
  278. case PWM_CMD_ENABLE: {
  279. sta = hpm_generate_central_aligned_waveform(pwm_name, channel, period, pulse);
  280. break;
  281. }
  282. case PWM_CMD_DISABLE: {
  283. hpm_disable_pwm(pwm_name, channel);
  284. break;
  285. }
  286. case PWM_CMD_SET: {
  287. sta = hpm_set_central_aligned_waveform(pwm_name, channel, period, pulse);
  288. break;
  289. }
  290. case PWM_CMD_GET: {
  291. sta = RT_EOK;
  292. break;
  293. }
  294. default: {
  295. sta = -RT_ERROR;
  296. break;
  297. }
  298. }
  299. return sta;
  300. }
  301. const static struct rt_pwm_ops hpm_pwm_ops = {
  302. .control = &hpm_pwm_control
  303. };
  304. static struct rt_device hpm_pwm_parent = {
  305. .control = hpm_pwm_dev_control
  306. };
  307. #ifdef HPM_PWM0
  308. static struct rt_device_pwm hpm_dev_pwm0 = {
  309. .ops = &hpm_pwm_ops,
  310. };
  311. #endif
  312. #ifdef HPM_PWM1
  313. static struct rt_device_pwm hpm_dev_pwm1 = {
  314. .ops = &hpm_pwm_ops,
  315. };
  316. #endif
  317. #ifdef HPM_PWM2
  318. static struct rt_device_pwm hpm_dev_pwm2 = {
  319. .ops = &hpm_pwm_ops,
  320. };
  321. #endif
  322. #ifdef HPM_PWM3
  323. static struct rt_device_pwm hpm_dev_pwm3 = {
  324. .ops = &hpm_pwm_ops,
  325. };
  326. #endif
  327. int rt_hw_pwm_init(void)
  328. {
  329. int ret = RT_EOK;
  330. #ifdef HPM_PWM0
  331. hpm_dev_pwm0.parent = hpm_pwm_parent;
  332. ret = rt_device_pwm_register(&hpm_dev_pwm0, "pwm0", &hpm_pwm_ops, RT_NULL);
  333. #endif
  334. #ifdef HPM_PWM1
  335. hpm_dev_pwm1.parent = hpm_pwm_parent;
  336. ret = rt_device_pwm_register(&hpm_dev_pwm1, "pwm1", &hpm_pwm_ops, RT_NULL);
  337. #endif
  338. #ifdef HPM_PWM2
  339. hpm_dev_pwm2.parent = hpm_pwm_parent;
  340. ret = rt_device_pwm_register(&hpm_dev_pwm2, "pwm2", &hpm_pwm_ops, RT_NULL);
  341. #endif
  342. #ifdef HPM_PWM3
  343. hpm_dev_pwm3.parent = hpm_pwm_parent;
  344. ret = rt_device_pwm_register(&hpm_dev_pwm3, "pwm3", &hpm_pwm_ops, RT_NULL);
  345. #endif
  346. return ret;
  347. }
  348. INIT_BOARD_EXPORT(rt_hw_pwm_init);
  349. #endif /* BSP_USING_PWM */