drv_pwm.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. /*
  2. * Copyright (c) 2006-2021, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2021-10-25 KevinXu first version
  9. */
  10. #include "drv_pwm.h"
  11. #ifdef RT_USING_PWM
  12. /* Declare the control function first */
  13. static rt_err_t drv_pwm_control(struct rt_device_pwm *, int, void *);
  14. static struct rt_pwm_ops drv_ops =
  15. {
  16. drv_pwm_control
  17. };
  18. static struct ra_pwm ra6m4_pwm_obj[BSP_PWMS_NUM] =
  19. {
  20. #ifdef BSP_USING_PWM0
  21. [BSP_PWM0_INDEX] = PWM_DRV_INITIALIZER(0),
  22. #endif
  23. #ifdef BSP_USING_PWM1
  24. [BSP_PWM1_INDEX] = PWM_DRV_INITIALIZER(1),
  25. #endif
  26. #ifdef BSP_USING_PWM2
  27. [BSP_PWM2_INDEX] = PWM_DRV_INITIALIZER(2),
  28. #endif
  29. #ifdef BSP_USING_PWM3
  30. [BSP_PWM3_INDEX] = PWM_DRV_INITIALIZER(3),
  31. #endif
  32. #ifdef BSP_USING_PWM4
  33. [BSP_PWM4_INDEX] = PWM_DRV_INITIALIZER(4),
  34. #endif
  35. #ifdef BSP_USING_PWM5
  36. [BSP_PWM5_INDEX] = PWM_DRV_INITIALIZER(5),
  37. #endif
  38. #ifdef BSP_USING_PWM6
  39. [BSP_PWM6_INDEX] = PWM_DRV_INITIALIZER(6),
  40. #endif
  41. #ifdef BSP_USING_PWM7
  42. [BSP_PWM7_INDEX] = PWM_DRV_INITIALIZER(7),
  43. #endif
  44. #ifdef BSP_USING_PWM8
  45. [BSP_PWM8_INDEX] = PWM_DRV_INITIALIZER(8),
  46. #endif
  47. #ifdef BSP_USING_PWM9
  48. [BSP_PWM9_INDEX] = PWM_DRV_INITIALIZER(9),
  49. #endif
  50. };
  51. /* Convert the raw PWM period counts into ns */
  52. static rt_uint32_t _convert_counts_ns(uint32_t source_div, uint32_t raw)
  53. {
  54. uint32_t pclkd_freq_hz = R_FSP_SystemClockHzGet(FSP_PRIV_CLOCK_PCLKD) >> source_div;
  55. uint32_t ns = (uint32_t)(((uint64_t)raw * 1000000000ULL) / pclkd_freq_hz);
  56. return ns;
  57. }
  58. /* Convert ns into raw PWM period counts */
  59. static rt_uint32_t _convert_ns_counts(uint32_t source_div, uint32_t raw)
  60. {
  61. uint32_t pclkd_freq_hz = R_FSP_SystemClockHzGet(FSP_PRIV_CLOCK_PCLKD) >> source_div;
  62. uint32_t counts = (uint32_t)(((uint64_t)raw * (uint64_t)pclkd_freq_hz) / 1000000000ULL);
  63. return counts;
  64. }
  65. /* PWM_CMD_ENABLE or PWM_CMD_DISABLE */
  66. static rt_err_t drv_pwm_enable(struct ra_pwm *device,
  67. struct rt_pwm_configuration *configuration,
  68. rt_bool_t enable)
  69. {
  70. fsp_err_t err = FSP_SUCCESS;
  71. if (enable)
  72. {
  73. err = R_GPT_Start(device->g_ctrl);
  74. }
  75. else
  76. {
  77. err = R_GPT_Stop(device->g_ctrl);
  78. }
  79. return (err == FSP_SUCCESS) ? RT_EOK : -RT_ERROR;
  80. }
  81. /* PWM_CMD_GET */
  82. static rt_err_t drv_pwm_get(struct ra_pwm *device,
  83. struct rt_pwm_configuration *configuration)
  84. {
  85. timer_info_t info;
  86. if (R_GPT_InfoGet(device->g_ctrl, &info) != FSP_SUCCESS)
  87. return -RT_ERROR;
  88. configuration->pulse =
  89. _convert_counts_ns(device->g_cfg->source_div, device->g_cfg->duty_cycle_counts);
  90. configuration->period =
  91. _convert_counts_ns(device->g_cfg->source_div, info.period_counts);
  92. configuration->channel = device->g_cfg->channel;
  93. return RT_EOK;
  94. }
  95. /* PWM_CMD_SET */
  96. static rt_err_t drv_pwm_set(struct ra_pwm *device,
  97. struct rt_pwm_configuration *conf)
  98. {
  99. uint32_t counts;
  100. fsp_err_t fsp_erra;
  101. fsp_err_t fsp_errb;
  102. rt_err_t rt_err;
  103. uint32_t pulse;
  104. uint32_t period;
  105. struct rt_pwm_configuration orig_conf;
  106. rt_err = drv_pwm_get(device, &orig_conf);
  107. if (rt_err != RT_EOK)
  108. {
  109. return rt_err;
  110. }
  111. /* Pulse cannot last longer than period. */
  112. period = conf->period;
  113. pulse = (period >= conf->pulse) ? conf->pulse : period;
  114. /* Not to set period again if it's not changed. */
  115. if (period != orig_conf.period)
  116. {
  117. counts = _convert_ns_counts(device->g_cfg->source_div, period);
  118. fsp_erra = R_GPT_PeriodSet(device->g_ctrl, counts);
  119. if (fsp_erra != FSP_SUCCESS)
  120. {
  121. return -RT_ERROR;
  122. }
  123. }
  124. /* Two pins of a channel will not be separated. */
  125. counts = _convert_ns_counts(device->g_cfg->source_div, pulse);
  126. fsp_erra = R_GPT_DutyCycleSet(device->g_ctrl, counts, GPT_IO_PIN_GTIOCA);
  127. fsp_errb = R_GPT_DutyCycleSet(device->g_ctrl, counts, GPT_IO_PIN_GTIOCB);
  128. if (fsp_erra != FSP_SUCCESS || fsp_errb != FSP_SUCCESS)
  129. {
  130. return -RT_ERROR;
  131. }
  132. return RT_EOK;
  133. }
  134. /**
  135. * Implement of control method in struct rt_pwm_ops.
  136. */
  137. static rt_err_t drv_pwm_control(struct rt_device_pwm *device, int cmd, void *arg)
  138. {
  139. struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)arg;
  140. struct ra_pwm *pwm_device = (struct ra_pwm *)device->parent.user_data;
  141. /**
  142. * There's actually only one GPT timer with 10 channels. In this case, the
  143. * timer is separated into 10 PWM devices, so each device has only one
  144. * channel.
  145. */
  146. if (configuration->channel != 0)
  147. {
  148. return -RT_EINVAL;
  149. }
  150. switch (cmd)
  151. {
  152. case PWM_CMD_ENABLE:
  153. return drv_pwm_enable(pwm_device, configuration, RT_TRUE);
  154. case PWM_CMD_DISABLE:
  155. return drv_pwm_enable(pwm_device, configuration, RT_FALSE);
  156. case PWM_CMD_GET:
  157. return drv_pwm_get(pwm_device, configuration);
  158. case PWM_CMD_SET:
  159. return drv_pwm_set(pwm_device, configuration);
  160. default:
  161. return -RT_EINVAL;
  162. }
  163. return RT_EOK;
  164. }
  165. /**
  166. * This is to register the PWM device
  167. *
  168. * Note that the PWM driver only supports one fixed pin.
  169. */
  170. int rt_hw_pwm_init(void)
  171. {
  172. rt_err_t ret = RT_EOK;
  173. rt_err_t rt_err = RT_EOK;
  174. fsp_err_t fsp_err = FSP_SUCCESS;
  175. for (int i = 0; i < BSP_PWMS_NUM; i++)
  176. {
  177. fsp_err = R_GPT_Open(ra6m4_pwm_obj[i].g_ctrl,
  178. ra6m4_pwm_obj[i].g_cfg);
  179. rt_err = rt_device_pwm_register(&ra6m4_pwm_obj[i].pwm_device,
  180. ra6m4_pwm_obj[i].name,
  181. &drv_ops,
  182. &ra6m4_pwm_obj[i]);
  183. if (fsp_err != FSP_SUCCESS || rt_err != RT_EOK)
  184. {
  185. ret = -RT_ERROR;
  186. }
  187. }
  188. return ret;
  189. }
  190. INIT_BOARD_EXPORT(rt_hw_pwm_init);
  191. #endif /* RT_USING_PWM */