drv_pwm.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  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. * 2020-06-27 AHTYDHD the first version
  9. */
  10. #include "drv_pwm.h"
  11. #include <stdint.h>
  12. #include <stdbool.h>
  13. #include "inc/hw_memmap.h"
  14. #include "driverlib/pwm.h"
  15. #include "driverlib/sysctl.h"
  16. #ifdef RT_USING_PWM
  17. #include "pwm_config.h"
  18. #include "tm4c123_config.h"
  19. #include <string.h>
  20. #define LOG_TAG "drv.pwm"
  21. #include <drv_log.h>
  22. enum
  23. {
  24. #ifdef BSP_USING_PWM0
  25. PWM0_INDEX,
  26. #endif
  27. #ifdef BSP_USING_PWM1
  28. PWM1_INDEX,
  29. #endif
  30. #ifdef BSP_USING_PWM2
  31. PWM2_INDEX,
  32. #endif
  33. #ifdef BSP_USING_PWM3
  34. PWM3_INDEX,
  35. #endif
  36. #ifdef BSP_USING_PWM4
  37. PWM4_INDEX,
  38. #endif
  39. #ifdef BSP_USING_PWM5
  40. PWM5_INDEX,
  41. #endif
  42. #ifdef BSP_USING_PWM6
  43. PWM6_INDEX,
  44. #endif
  45. #ifdef BSP_USING_PWM7
  46. PWM7_INDEX,
  47. #endif
  48. };
  49. static struct tm4c123_pwm_config pwm_config[] =
  50. {
  51. #ifdef BSP_USING_PWM0
  52. PWM0_CONFIG,
  53. #endif
  54. #ifdef BSP_USING_PWM1
  55. PWM1_CONFIG,
  56. #endif
  57. #ifdef BSP_USING_PWM2
  58. PWM2_CONFIG,
  59. #endif
  60. #ifdef BSP_USING_PWM3
  61. PWM3_CONFIG,
  62. #endif
  63. #ifdef BSP_USING_PWM4
  64. PWM4_CONFIG,
  65. #endif
  66. #ifdef BSP_USING_PWM5
  67. PWM5_CONFIG,
  68. #endif
  69. #ifdef BSP_USING_PWM6
  70. PWM6_CONFIG,
  71. #endif
  72. #ifdef BSP_USING_PWM7
  73. PWM7_CONFIG,
  74. #endif
  75. };
  76. static struct tm4c123_pwm pwm_obj[sizeof(pwm_config) / sizeof(pwm_config[0])] = {0};
  77. static rt_err_t tm4c123_pwm_control(struct rt_device_pwm *device, int cmd, void *arg);
  78. static struct rt_pwm_ops drv_ops =
  79. {
  80. tm4c123_pwm_control
  81. };
  82. static rt_err_t drv_pwm_enable(char *name, struct rt_pwm_configuration *configuration, rt_bool_t enable)
  83. {
  84. int num = name[3] - 0x30;
  85. if (!enable)
  86. {
  87. if (num <= 3)
  88. {
  89. /* Converts the channel number to the channel number of Hal library */
  90. PWMOutputState(PWM0_BASE, PWM_OUT_0_BIT << (num * 2 + (configuration->channel - 1)), false);
  91. }
  92. else
  93. {
  94. PWMOutputState(PWM1_BASE, PWM_OUT_0_BIT << ((num % 4) * 2 + (configuration->channel - 1)), false);
  95. }
  96. }
  97. else
  98. {
  99. if (num <= 3)
  100. {
  101. PWMOutputState(PWM0_BASE, PWM_OUT_0_BIT << (num * 2 + (configuration->channel - 1)), true);
  102. }
  103. else
  104. {
  105. PWMOutputState(PWM1_BASE, PWM_OUT_0_BIT << ((num % 4) * 2 + (configuration->channel - 1)), true);
  106. }
  107. }
  108. return RT_EOK;
  109. }
  110. static rt_err_t drv_pwm_get(char *name, struct rt_pwm_configuration *configuration)
  111. {
  112. switch (name[3])
  113. {
  114. case '0':
  115. configuration->period = PWMGenPeriodGet(PWM0_BASE, PWM_GEN_0);
  116. configuration->pulse = PWMPulseWidthGet(PWM0_BASE, PWM_OUT_0 + (uint32_t)(configuration->channel - 1));
  117. break;
  118. case '1':
  119. configuration->period = PWMGenPeriodGet(PWM0_BASE, PWM_GEN_1);
  120. configuration->pulse = PWMPulseWidthGet(PWM0_BASE, PWM_OUT_2 + (uint32_t)(configuration->channel - 1));
  121. break;
  122. case '2':
  123. configuration->period = PWMGenPeriodGet(PWM0_BASE, PWM_GEN_2);
  124. configuration->pulse = PWMPulseWidthGet(PWM0_BASE, PWM_OUT_4 + (uint32_t)(configuration->channel - 1));
  125. break;
  126. case '3':
  127. configuration->period = PWMGenPeriodGet(PWM0_BASE, PWM_GEN_3);
  128. configuration->pulse = PWMPulseWidthGet(PWM0_BASE, PWM_OUT_6 + (uint32_t)(configuration->channel - 1));
  129. break;
  130. case '4':
  131. configuration->period = PWMGenPeriodGet(PWM1_BASE, PWM_GEN_0);
  132. configuration->pulse = PWMPulseWidthGet(PWM1_BASE, PWM_OUT_0 + (uint32_t)(configuration->channel - 1));
  133. break;
  134. case '5':
  135. configuration->period = PWMGenPeriodGet(PWM1_BASE, PWM_GEN_1);
  136. configuration->pulse = PWMPulseWidthGet(PWM1_BASE, PWM_OUT_2 + (uint32_t)(configuration->channel - 1));
  137. break;
  138. case '6':
  139. configuration->period = PWMGenPeriodGet(PWM1_BASE, PWM_GEN_2);
  140. configuration->pulse = PWMPulseWidthGet(PWM1_BASE, PWM_OUT_4 + (uint32_t)(configuration->channel - 1));
  141. break;
  142. case '7':
  143. configuration->period = PWMGenPeriodGet(PWM1_BASE, PWM_GEN_3);
  144. configuration->pulse = PWMPulseWidthGet(PWM1_BASE, PWM_OUT_6 + (uint32_t)(configuration->channel - 1));
  145. break;
  146. default:
  147. break;
  148. }
  149. return RT_EOK;
  150. }
  151. static rt_err_t drv_pwm_set(char *name, struct rt_pwm_configuration *configuration)
  152. {
  153. uint32_t sysPwmClock = SysCtlPWMClockGet();
  154. switch (name[3])
  155. {
  156. case '0':
  157. PWMGenPeriodSet(PWM0_BASE, PWM_GEN_0, configuration->period / 1000 * (sysPwmClock / 1000000)); // t(s)/(1/f) = ticks ns/1000/1000000
  158. PWMPulseWidthSet(PWM0_BASE, PWM_OUT_0 + (uint32_t)(configuration->channel - 1), configuration->pulse / 1000 * (sysPwmClock / 1000000));
  159. PWMGenEnable(PWM0_BASE, PWM_GEN_0);
  160. break;
  161. case '1':
  162. PWMGenPeriodSet(PWM0_BASE, PWM_GEN_1, configuration->period / 1000 * (sysPwmClock / 1000000));
  163. PWMPulseWidthSet(PWM0_BASE, PWM_OUT_0 + (uint32_t)(configuration->channel - 1), configuration->pulse / 1000 * (sysPwmClock / 1000000));
  164. PWMGenEnable(PWM0_BASE, PWM_GEN_1);
  165. break;
  166. case '2':
  167. PWMGenPeriodSet(PWM0_BASE, PWM_GEN_2, configuration->period / 1000 * (sysPwmClock / 1000000));
  168. PWMPulseWidthSet(PWM0_BASE, PWM_OUT_0 + (uint32_t)(configuration->channel - 1), configuration->pulse / 1000 * (sysPwmClock / 1000000));
  169. PWMGenEnable(PWM0_BASE, PWM_GEN_2);
  170. break;
  171. case '3':
  172. PWMGenPeriodSet(PWM0_BASE, PWM_GEN_3, configuration->period / 1000 * (sysPwmClock / 1000000));
  173. PWMPulseWidthSet(PWM0_BASE, PWM_OUT_0 + (uint32_t)(configuration->channel - 1), configuration->pulse / 1000 * (sysPwmClock / 1000000));
  174. PWMGenEnable(PWM0_BASE, PWM_GEN_3);
  175. break;
  176. case '4':
  177. PWMGenPeriodSet(PWM1_BASE, PWM_GEN_0, configuration->period / 1000 * (sysPwmClock / 1000000));
  178. PWMPulseWidthSet(PWM1_BASE, PWM_OUT_0 + (uint32_t)(configuration->channel - 1), configuration->pulse / 1000 * (sysPwmClock / 1000000));
  179. PWMGenEnable(PWM1_BASE, PWM_GEN_0);
  180. break;
  181. case '5':
  182. PWMGenPeriodSet(PWM1_BASE, PWM_GEN_1, configuration->period / 1000 * (sysPwmClock / 1000000));
  183. PWMPulseWidthSet(PWM1_BASE, PWM_OUT_2 + (uint32_t)(configuration->channel - 1), configuration->pulse / 1000 * (sysPwmClock / 1000000));
  184. PWMGenEnable(PWM1_BASE, PWM_GEN_1);
  185. break;
  186. case '6':
  187. PWMGenPeriodSet(PWM1_BASE, PWM_GEN_2, configuration->period / 1000 * (sysPwmClock / 1000000));
  188. PWMPulseWidthSet(PWM1_BASE, PWM_OUT_4 + (uint32_t)(configuration->channel - 1), configuration->pulse / 1000 * (sysPwmClock / 1000000));
  189. PWMGenEnable(PWM1_BASE, PWM_GEN_2);
  190. break;
  191. case '7':
  192. PWMGenPeriodSet(PWM1_BASE, PWM_GEN_3, configuration->period / 1000 * (sysPwmClock / 1000000));
  193. PWMPulseWidthSet(PWM1_BASE, PWM_OUT_6 + (uint32_t)(configuration->channel - 1), configuration->pulse / 1000 * (sysPwmClock / 1000000));
  194. PWMGenEnable(PWM1_BASE, PWM_GEN_3);
  195. break;
  196. default:
  197. break;
  198. }
  199. return RT_EOK;
  200. }
  201. static rt_err_t tm4c123_pwm_control(struct rt_device_pwm *device, int cmd, void *arg)
  202. {
  203. struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)arg;
  204. switch (cmd)
  205. {
  206. case PWM_CMD_ENABLE:
  207. return drv_pwm_enable(device->parent.parent.name, configuration, RT_TRUE);
  208. case PWM_CMD_DISABLE:
  209. return drv_pwm_enable(device->parent.parent.name, configuration, RT_FALSE);
  210. case PWM_CMD_SET:
  211. return drv_pwm_set(device->parent.parent.name, configuration);
  212. case PWM_CMD_GET:
  213. return drv_pwm_get(device->parent.parent.name, configuration);
  214. default:
  215. return RT_EINVAL;
  216. }
  217. }
  218. static rt_err_t tm4c123_hw_pwm_init(struct tm4c123_pwm *device)
  219. {
  220. rt_err_t result = RT_EOK;
  221. RT_ASSERT(device != RT_NULL);
  222. pwm_hw_config();
  223. switch (device->config->name[3])
  224. {
  225. case '0':
  226. PWMGenConfigure(PWM0_BASE, PWM_GEN_0, device->config->counterMode |
  227. device->config->syncMode);
  228. break;
  229. case '1':
  230. PWMGenConfigure(PWM0_BASE, PWM_GEN_1, device->config->counterMode |
  231. device->config->syncMode);
  232. break;
  233. case '2':
  234. PWMGenConfigure(PWM0_BASE, PWM_GEN_2, device->config->counterMode |
  235. device->config->syncMode);
  236. break;
  237. case '3':
  238. PWMGenConfigure(PWM0_BASE, PWM_GEN_3, device->config->counterMode |
  239. device->config->syncMode);
  240. break;
  241. case '4':
  242. PWMGenConfigure(PWM1_BASE, PWM_GEN_0, device->config->counterMode |
  243. device->config->syncMode);
  244. break;
  245. case '5':
  246. PWMGenConfigure(PWM1_BASE, PWM_GEN_1, device->config->counterMode |
  247. device->config->syncMode);
  248. break;
  249. case '6':
  250. PWMGenConfigure(PWM1_BASE, PWM_GEN_2, device->config->counterMode |
  251. device->config->syncMode);
  252. break;
  253. case '7':
  254. PWMGenConfigure(PWM1_BASE, PWM_GEN_3, device->config->counterMode |
  255. device->config->syncMode);
  256. break;
  257. default:
  258. LOG_E("%s PWMGenConfigure failed", device->config->name);
  259. result = -RT_ERROR;
  260. return result;
  261. }
  262. return result;
  263. }
  264. int rt_hw_pwm_init(void)
  265. {
  266. int i = 0;
  267. rt_size_t obj_num = sizeof(pwm_obj) / sizeof(struct tm4c123_pwm);
  268. rt_err_t result = RT_EOK;
  269. for (i = 0 ; i < obj_num; i++)
  270. {
  271. pwm_obj[i].config = &pwm_config[i];
  272. pwm_obj[i].pwm_device.ops = &drv_ops;
  273. /*pwm_init*/
  274. if (tm4c123_hw_pwm_init(&pwm_obj[i]) != RT_EOK)
  275. {
  276. LOG_E("%s init failed", pwm_obj[i].config->name);
  277. result = -RT_ERROR;
  278. return result;
  279. }
  280. else
  281. {
  282. LOG_D("%s init success", pwm_obj[i].config->name);
  283. /* register pwm device */
  284. if (rt_device_pwm_register(&pwm_obj[i].pwm_device, pwm_obj[i].config->name, &drv_ops, RT_NULL) == RT_EOK)
  285. {
  286. LOG_D("%s register success", pwm_obj[i].config->name);
  287. }
  288. else
  289. {
  290. LOG_E("%s register failed", pwm_obj[i].config->name);
  291. result = -RT_ERROR;
  292. }
  293. }
  294. }
  295. return result;
  296. }
  297. #endif /* RT_USING_PWM */
  298. /************************** end of file ******************/