drv_pwm.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  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. rt_err_t hpm_generate_central_aligned_waveform(uint8_t pwm_index, uint8_t channel, uint32_t period, uint32_t pulse)
  81. {
  82. #if defined(HPMSOC_HAS_HPMSDK_PWMV2)
  83. PWMV2_Type * pwm_base;
  84. pwm_counter_t pwm_counter;
  85. #else
  86. PWM_Type * pwm_base;
  87. pwm_cmp_config_t cmp_config[2] = {0};
  88. pwm_config_t pwm_config = {0};
  89. #endif
  90. uint32_t duty;
  91. uint32_t reload = 0;
  92. uint32_t freq;
  93. pwm_base = pwm_base_tbl[pwm_index];
  94. init_pwm_pins(pwm_base);
  95. freq = board_init_pwm_clock(pwm_base);
  96. if(period != 0) {
  97. reload = (uint64_t)freq * period / 1000000000;
  98. } else {
  99. reload = 0;
  100. }
  101. duty = (uint64_t)freq * pulse / 1000000000;
  102. #if defined(HPMSOC_HAS_HPMSDK_PWMV2)
  103. pwm_counter = pwmv2_counter_tbl[channel];
  104. pwmv2_disable_counter(pwm_base, pwm_counter);
  105. pwmv2_reset_counter(pwm_base, pwm_counter);
  106. pwmv2_shadow_register_unlock(pwm_base);
  107. pwmv2_set_shadow_val(pwm_base, channel / 2, reload, 0, false); /**< cnt use 0-3 shadow */
  108. pwmv2_set_shadow_val(pwm_base, channel * 2 + 4, reload + 1, 0, false);
  109. pwmv2_set_shadow_val(pwm_base, channel * 2 + 5, reload, 0, false);
  110. pwmv2_counter_select_data_offset_from_shadow_value(pwm_base, pwm_counter, channel / 2);
  111. pwmv2_counter_burst_disable(pwm_base, pwm_counter);
  112. pwmv2_set_reload_update_time(pwm_base, pwm_counter, pwm_reload_update_on_reload);
  113. pwmv2_select_cmp_source(pwm_base, channel * 2, cmp_value_from_shadow_val, channel * 2 + 4);
  114. pwmv2_select_cmp_source(pwm_base, channel * 2 + 1, cmp_value_from_shadow_val, channel * 2 + 5);
  115. pwmv2_shadow_register_lock(pwm_base);
  116. pwmv2_disable_four_cmp(pwm_base, channel);
  117. pwmv2_channel_enable_output(pwm_base, channel);
  118. pwmv2_enable_counter(pwm_base, pwm_counter);
  119. pwmv2_start_pwm_output(pwm_base, pwm_counter);
  120. pwmv2_shadow_register_unlock(pwm_base);
  121. pwmv2_set_shadow_val(pwm_base, channel * 2, (reload - duty) >> 1, 0, false);
  122. pwmv2_set_shadow_val(pwm_base, channel * 2, (reload + duty) >> 1, 0, false);
  123. pwmv2_shadow_register_lock(pwm_base);
  124. #else
  125. pwm_stop_counter(pwm_base);
  126. pwm_get_default_pwm_config(pwm_base, &pwm_config);
  127. /*
  128. * reload and start counter
  129. */
  130. pwm_set_reload(pwm_base, 0, reload);
  131. pwm_set_start_count(pwm_base, 0, 0);
  132. /*
  133. * config cmp1 and cmp2
  134. */
  135. cmp_config[0].mode = pwm_cmp_mode_output_compare;
  136. cmp_config[0].cmp = (reload - duty) >> 1;
  137. cmp_config[0].update_trigger = pwm_shadow_register_update_on_shlk;
  138. cmp_config[1].mode = pwm_cmp_mode_output_compare;
  139. cmp_config[1].cmp = (reload + duty) >> 1;
  140. cmp_config[1].update_trigger = pwm_shadow_register_update_on_shlk;
  141. pwm_config.enable_output = true;
  142. pwm_config.dead_zone_in_half_cycle = 0;
  143. pwm_config.invert_output = false;
  144. /*
  145. * config pwm
  146. */
  147. if (status_success != pwm_setup_waveform(pwm_base, channel, &pwm_config, channel * 2, cmp_config, 2)) {
  148. return -RT_ERROR;
  149. }
  150. pwm_start_counter(pwm_base);
  151. pwm_issue_shadow_register_lock_event(pwm_base);
  152. #endif
  153. return RT_EOK;
  154. }
  155. rt_err_t hpm_set_central_aligned_waveform(uint8_t pwm_index, uint8_t channel, uint32_t period, uint32_t pulse)
  156. {
  157. #if defined(HPMSOC_HAS_HPMSDK_PWMV2)
  158. PWMV2_Type * pwm_base;
  159. #else
  160. PWM_Type * pwm_base;
  161. pwm_config_t pwm_config = {0};
  162. #endif
  163. uint32_t duty;
  164. uint32_t reload = 0;
  165. uint32_t freq;
  166. pwm_base = pwm_base_tbl[pwm_index];
  167. freq = board_init_pwm_clock(pwm_base);
  168. if(period != 0) {
  169. reload = (uint64_t)freq * period / 1000000000;
  170. } else {
  171. reload = 0;
  172. }
  173. duty = (uint64_t)freq * pulse / 1000000000;
  174. #if defined(HPMSOC_HAS_HPMSDK_PWMV2)
  175. pwmv2_shadow_register_unlock(pwm_base);
  176. pwmv2_set_shadow_val(pwm_base, channel / 2, reload, 0, false); /**< cnt use 0-3 shadow */
  177. pwmv2_set_shadow_val(pwm_base, channel * 2 + 4, (reload - duty) >> 1, 0, false);
  178. pwmv2_set_shadow_val(pwm_base, channel * 2 + 5, (reload + duty) >> 1, 0, false);
  179. pwmv2_shadow_register_lock(pwm_base);
  180. #else
  181. pwm_get_default_pwm_config(pwm_base, &pwm_config);
  182. pwm_set_reload(pwm_base, 0, reload);
  183. pwm_update_raw_cmp_central_aligned(pwm_base, channel * 2, channel * 2 + 1, (reload - duty) >> 1, (reload + duty) >> 1);
  184. pwm_issue_shadow_register_lock_event(pwm_base);
  185. #endif
  186. return RT_EOK;
  187. }
  188. rt_err_t hpm_disable_pwm(uint8_t pwm_index, uint8_t channel)
  189. {
  190. #if defined(HPMSOC_HAS_HPMSDK_PWMV2)
  191. PWMV2_Type * pwm_base;
  192. pwm_base = pwm_base_tbl[pwm_index];
  193. pwmv2_shadow_register_unlock(pwm_base);
  194. pwmv2_set_shadow_val(pwm_base, channel * 2 + 4, 0, 0, false);
  195. pwmv2_set_shadow_val(pwm_base, channel * 2 + 5, 0, 0, false);
  196. pwmv2_shadow_register_lock(pwm_base);
  197. #else
  198. pwm_disable_output(pwm_base_tbl[pwm_index], channel);
  199. #endif
  200. return RT_EOK;
  201. }
  202. rt_err_t hpm_pwm_control(struct rt_device_pwm * device, int cmd, void *arg)
  203. {
  204. uint8_t channel;
  205. uint32_t period;
  206. uint32_t pulse;
  207. rt_err_t sta = RT_EOK;
  208. unsigned char pwm_name;
  209. struct rt_pwm_configuration * configuration;
  210. configuration = (struct rt_pwm_configuration * )arg;
  211. channel = configuration->channel;
  212. period = configuration->period;
  213. pulse = configuration->pulse;
  214. if (strcmp("pwm0", device->parent.parent.name) == 0) {
  215. pwm_name = 0;
  216. } else if (strcmp("pwm1", device->parent.parent.name) == 0) {
  217. pwm_name = 1;
  218. } else if (strcmp("pwm2", device->parent.parent.name) == 0) {
  219. pwm_name = 2;
  220. } else if (strcmp("pwm3", device->parent.parent.name) == 0) {
  221. pwm_name = 3;
  222. } else {
  223. return -RT_ERROR;
  224. }
  225. switch(cmd) {
  226. case PWM_CMD_ENABLE: {
  227. sta = hpm_generate_central_aligned_waveform(pwm_name, channel, period, pulse);
  228. break;
  229. }
  230. case PWM_CMD_DISABLE: {
  231. hpm_disable_pwm(pwm_name, channel);
  232. break;
  233. }
  234. case PWM_CMD_SET: {
  235. sta = hpm_set_central_aligned_waveform(pwm_name, channel, period, pulse);
  236. break;
  237. }
  238. case PWM_CMD_GET: {
  239. sta = RT_EOK;
  240. break;
  241. }
  242. default: {
  243. sta = -RT_ERROR;
  244. break;
  245. }
  246. }
  247. return sta;
  248. }
  249. rt_err_t hpm_pwm_dev_control(rt_device_t device, int cmd, void *arg)
  250. {
  251. uint8_t channel;
  252. uint32_t period;
  253. uint32_t pulse;
  254. rt_err_t sta = RT_EOK;
  255. uint8_t pwm_name;
  256. struct rt_pwm_configuration * configuration;
  257. configuration = (struct rt_pwm_configuration * )arg;
  258. channel = configuration->channel;
  259. period = configuration->period;
  260. pulse = configuration->pulse;
  261. if (strcmp("pwm0", device->parent.name) == 0) {
  262. pwm_name = 0;
  263. } else if (strcmp("pwm1", device->parent.name) == 0) {
  264. pwm_name = 1;
  265. } else if (strcmp("pwm2", device->parent.name) == 0) {
  266. pwm_name = 2;
  267. } else if (strcmp("pwm3", device->parent.name) == 0) {
  268. pwm_name = 3;
  269. } else {
  270. return -RT_ERROR;
  271. }
  272. switch(cmd) {
  273. case PWM_CMD_ENABLE: {
  274. sta = hpm_generate_central_aligned_waveform(pwm_name, channel, period, pulse);
  275. break;
  276. }
  277. case PWM_CMD_DISABLE: {
  278. hpm_disable_pwm(pwm_name, channel);
  279. break;
  280. }
  281. case PWM_CMD_SET: {
  282. sta = hpm_set_central_aligned_waveform(pwm_name, channel, period, pulse);
  283. break;
  284. }
  285. case PWM_CMD_GET: {
  286. sta = RT_EOK;
  287. break;
  288. }
  289. default: {
  290. sta = -RT_ERROR;
  291. break;
  292. }
  293. }
  294. return sta;
  295. }
  296. const static struct rt_pwm_ops hpm_pwm_ops = {
  297. .control = &hpm_pwm_control
  298. };
  299. static struct rt_device hpm_pwm_parent = {
  300. .control = hpm_pwm_dev_control
  301. };
  302. #ifdef HPM_PWM0
  303. static struct rt_device_pwm hpm_dev_pwm0 = {
  304. .ops = &hpm_pwm_ops,
  305. };
  306. #endif
  307. #ifdef HPM_PWM1
  308. static struct rt_device_pwm hpm_dev_pwm1 = {
  309. .ops = &hpm_pwm_ops,
  310. };
  311. #endif
  312. #ifdef HPM_PWM2
  313. static struct rt_device_pwm hpm_dev_pwm2 = {
  314. .ops = &hpm_pwm_ops,
  315. };
  316. #endif
  317. #ifdef HPM_PWM3
  318. static struct rt_device_pwm hpm_dev_pwm3 = {
  319. .ops = &hpm_pwm_ops,
  320. };
  321. #endif
  322. int rt_hw_pwm_init(void)
  323. {
  324. int ret = RT_EOK;
  325. #ifdef HPM_PWM0
  326. hpm_dev_pwm0.parent = hpm_pwm_parent;
  327. ret = rt_device_pwm_register(&hpm_dev_pwm0, "pwm0", &hpm_pwm_ops, RT_NULL);
  328. #endif
  329. #ifdef HPM_PWM1
  330. hpm_dev_pwm1.parent = hpm_pwm_parent;
  331. ret = rt_device_pwm_register(&hpm_dev_pwm1, "pwm1", &hpm_pwm_ops, RT_NULL);
  332. #endif
  333. #ifdef HPM_PWM2
  334. hpm_dev_pwm2.parent = hpm_pwm_parent;
  335. ret = rt_device_pwm_register(&hpm_dev_pwm2, "pwm2", &hpm_pwm_ops, RT_NULL);
  336. #endif
  337. #ifdef HPM_PWM3
  338. hpm_dev_pwm3.parent = hpm_pwm_parent;
  339. ret = rt_device_pwm_register(&hpm_dev_pwm3, "pwm3", &hpm_pwm_ops, RT_NULL);
  340. #endif
  341. return ret;
  342. }
  343. INIT_BOARD_EXPORT(rt_hw_pwm_init);
  344. #endif /* BSP_USING_PWM */