drv_pwm.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. /*
  2. * Copyright (c) 2019 Winner Microelectronics Co., Ltd.
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2018-11-22 fanwenl 1st version
  9. */
  10. #include <rtthread.h>
  11. #include <rtdevice.h>
  12. #include "wm_type_def.h"
  13. #include "wm_cpu.h"
  14. #include "wm_pwm.h"
  15. #include "wm_gpio_afsel.h"
  16. #include "drv_pwm.h"
  17. #include "pin_map.h"
  18. #ifdef BSP_USING_PWM
  19. #define MAX_PERIOD 255
  20. #define MIN_PERIOD 2
  21. #define MIN_PULSE 1
  22. #define MAX_CLKDIV 65535
  23. static rt_err_t wm_pwm_set(rt_uint8_t channel, struct rt_pwm_configuration *configuration)
  24. {
  25. rt_uint32_t period, pulse;
  26. rt_uint32_t psc;
  27. pwm_init_param pwm_param;
  28. int ret = WM_FAILED;
  29. tls_sys_clk sysclk;
  30. tls_sys_clk_get(&sysclk);
  31. rt_memset(&pwm_param, 0, sizeof(pwm_init_param));
  32. pwm_param.channel = channel;
  33. pwm_param.cnt_type = WM_PWM_CNT_TYPE_EDGE_ALIGN_OUT;
  34. pwm_param.loop_type = WM_PWM_LOOP_TYPE_LOOP;
  35. pwm_param.mode = WM_PWM_OUT_MODE_INDPT;
  36. pwm_param.inverse_en = DISABLE;
  37. pwm_param.pnum = 0;
  38. pwm_param.pnum_int = DISABLE;
  39. period = (unsigned long long)configuration->period * sysclk.apbclk / 1000ULL;
  40. psc = period / MAX_PERIOD + 1;
  41. if (psc > MAX_CLKDIV)
  42. {
  43. psc = MAX_CLKDIV;
  44. }
  45. pwm_param.clkdiv = psc;
  46. period = period / psc;
  47. if (period < MIN_PERIOD)
  48. {
  49. period = MIN_PERIOD;
  50. }
  51. else if (period > MAX_PERIOD)
  52. {
  53. period = MAX_PERIOD;
  54. }
  55. pwm_param.period = period - 1;
  56. pulse = (unsigned long long)configuration->pulse * sysclk.apbclk / psc / 1000ULL;
  57. if (pulse < MIN_PULSE)
  58. {
  59. pulse = MIN_PULSE;
  60. }
  61. else if (pulse > period)
  62. {
  63. pulse = period;
  64. }
  65. pwm_param.duty = pulse - 1;
  66. ret = tls_pwm_out_init(pwm_param);
  67. if (ret == WM_SUCCESS)
  68. {
  69. return RT_EOK;
  70. }
  71. else
  72. {
  73. return RT_ERROR;
  74. }
  75. }
  76. static rt_err_t wm_pwm_get(rt_uint8_t channel, struct rt_pwm_configuration *configuration)
  77. {
  78. tls_sys_clk sysclk;
  79. uint32_t clkdiv;
  80. uint8_t duty, period;
  81. tls_sys_clk_get(&sysclk);
  82. tls_pwm_get_info(channel, &clkdiv, &duty, &period);
  83. configuration->period = (period + 1) * clkdiv * 1000UL / sysclk.apbclk;
  84. configuration->pulse = (duty + 1) * clkdiv * 1000UL / sysclk.apbclk;
  85. return RT_EOK;
  86. }
  87. static rt_err_t wm_pwm_control(struct rt_device_pwm *device, int cmd, void *arg)
  88. {
  89. struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)arg;
  90. int ret = WM_FAILED;
  91. rt_uint32_t channel = 0;
  92. channel = configuration->channel - 1;
  93. if (channel > 4)
  94. return RT_EINVAL;
  95. switch (cmd)
  96. {
  97. case PWM_CMD_ENABLE:
  98. ret = tls_pwm_start(channel);
  99. if (ret == WM_SUCCESS)
  100. return RT_EOK;
  101. else
  102. return RT_ERROR;
  103. case PWM_CMD_DISABLE:
  104. ret = tls_pwm_stop(channel);
  105. if (ret == WM_SUCCESS)
  106. return RT_EOK;
  107. else
  108. return RT_ERROR;
  109. case PWM_CMD_SET:
  110. return wm_pwm_set(channel, configuration);
  111. case PWM_CMD_GET:
  112. return wm_pwm_get(channel, configuration);
  113. default:
  114. return RT_EINVAL;
  115. }
  116. }
  117. static struct rt_pwm_ops drv_ops =
  118. {
  119. wm_pwm_control
  120. };
  121. static struct rt_device_pwm wm_pwm;
  122. int wm_hw_pwm_init(void)
  123. {
  124. rt_int16_t gpio_pin;
  125. /*io config*/
  126. #ifdef USING_PWM_CH1
  127. gpio_pin = wm_get_pin(WM_PWM_CH1_PIN);
  128. if (gpio_pin >= 0)
  129. {
  130. wm_pwm1_config((enum tls_io_name)gpio_pin);
  131. }
  132. #endif
  133. #ifdef USING_PWM_CH2
  134. gpio_pin = wm_get_pin(WM_PWM_CH2_PIN);
  135. if (gpio_pin >= 0)
  136. {
  137. wm_pwm2_config((enum tls_io_name)gpio_pin);
  138. }
  139. #endif
  140. #ifdef USING_PWM_CH3
  141. gpio_pin = wm_get_pin(WM_PWM_CH3_PIN);
  142. if (gpio_pin >= 0)
  143. {
  144. wm_pwm3_config((enum tls_io_name)gpio_pin);
  145. }
  146. #endif
  147. #ifdef USING_PWM_CH4
  148. gpio_pin = wm_get_pin(WM_PWM_CH4_PIN);
  149. if (gpio_pin >= 0)
  150. {
  151. wm_pwm4_config((enum tls_io_name)gpio_pin);
  152. }
  153. #endif
  154. #ifdef USING_PWM_CH5
  155. gpio_pin = wm_get_pin(WM_PWM_CH5_PIN);
  156. if (gpio_pin >= 0)
  157. {
  158. wm_pwm5_config((enum tls_io_name)gpio_pin);
  159. }
  160. #endif
  161. #if defined(USING_PWM_CH1) || defined(USING_PWM_CH2) || defined(USING_PWM_CH3) || \
  162. defined(USING_PWM_CH4) || defined(USING_PWM_CH5)
  163. rt_device_pwm_register(&wm_pwm, "pwm", &drv_ops, 0);
  164. #endif
  165. return RT_EOK;
  166. }
  167. INIT_DEVICE_EXPORT(wm_hw_pwm_init);
  168. #endif /* BSP_USING_PWM */