rt_drv_pwm.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. /*
  2. * Copyright (c) 2006-2022, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2018-05-07 aozima the first version
  9. * 2022-05-14 Stanley Lwin add pwm function
  10. * 2022-07-25 liYony fix complementary outputs and add usage information in finsh
  11. * 2022-08-31 liYony Add complementary output section to framework for management
  12. */
  13. #include <rtdevice.h>
  14. static rt_err_t _pwm_control(rt_device_t dev, int cmd, void *args)
  15. {
  16. rt_err_t result = RT_EOK;
  17. struct rt_device_pwm *pwm = (struct rt_device_pwm *)dev;
  18. struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)args;
  19. switch (cmd)
  20. {
  21. case PWMN_CMD_ENABLE:
  22. configuration->complementary = RT_TRUE;
  23. break;
  24. case PWMN_CMD_DISABLE:
  25. configuration->complementary = RT_FALSE;
  26. break;
  27. default:
  28. if(pwm->ops->control)
  29. result = pwm->ops->control(pwm, cmd, args);
  30. break;
  31. }
  32. return result;
  33. }
  34. /*
  35. pos: channel
  36. void *buffer: rt_uint32_t pulse[size]
  37. size : number of pulse, only set to sizeof(rt_uint32_t).
  38. */
  39. static rt_size_t _pwm_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
  40. {
  41. rt_err_t result = RT_EOK;
  42. struct rt_device_pwm *pwm = (struct rt_device_pwm *)dev;
  43. rt_uint32_t *pulse = (rt_uint32_t *)buffer;
  44. struct rt_pwm_configuration configuration = {0};
  45. configuration.channel = (pos > 0) ? (pos) : (-pos);
  46. if (pwm->ops->control)
  47. {
  48. result = pwm->ops->control(pwm, PWM_CMD_GET, &configuration);
  49. if (result != RT_EOK)
  50. {
  51. return 0;
  52. }
  53. *pulse = configuration.pulse;
  54. }
  55. return size;
  56. }
  57. /*
  58. pos: channel
  59. void *buffer: rt_uint32_t pulse[size]
  60. size : number of pulse, only set to sizeof(rt_uint32_t).
  61. */
  62. static rt_size_t _pwm_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
  63. {
  64. rt_err_t result = RT_EOK;
  65. struct rt_device_pwm *pwm = (struct rt_device_pwm *)dev;
  66. rt_uint32_t *pulse = (rt_uint32_t *)buffer;
  67. struct rt_pwm_configuration configuration = {0};
  68. configuration.channel = (pos > 0) ? (pos) : (-pos);
  69. if (pwm->ops->control)
  70. {
  71. result = pwm->ops->control(pwm, PWM_CMD_GET, &configuration);
  72. if (result != RT_EOK)
  73. {
  74. return 0;
  75. }
  76. configuration.pulse = *pulse;
  77. result = pwm->ops->control(pwm, PWM_CMD_SET, &configuration);
  78. if (result != RT_EOK)
  79. {
  80. return 0;
  81. }
  82. }
  83. return size;
  84. }
  85. #ifdef RT_USING_DEVICE_OPS
  86. static const struct rt_device_ops pwm_device_ops =
  87. {
  88. RT_NULL,
  89. RT_NULL,
  90. RT_NULL,
  91. _pwm_read,
  92. _pwm_write,
  93. _pwm_control
  94. };
  95. #endif /* RT_USING_DEVICE_OPS */
  96. rt_err_t rt_device_pwm_register(struct rt_device_pwm *device, const char *name, const struct rt_pwm_ops *ops, const void *user_data)
  97. {
  98. rt_err_t result = RT_EOK;
  99. rt_memset(device, 0, sizeof(struct rt_device_pwm));
  100. #ifdef RT_USING_DEVICE_OPS
  101. device->parent.ops = &pwm_device_ops;
  102. #else
  103. device->parent.init = RT_NULL;
  104. device->parent.open = RT_NULL;
  105. device->parent.close = RT_NULL;
  106. device->parent.read = _pwm_read;
  107. device->parent.write = _pwm_write;
  108. device->parent.control = _pwm_control;
  109. #endif /* RT_USING_DEVICE_OPS */
  110. device->parent.type = RT_Device_Class_PWM;
  111. device->ops = ops;
  112. device->parent.user_data = (void *)user_data;
  113. result = rt_device_register(&device->parent, name, RT_DEVICE_FLAG_RDWR);
  114. return result;
  115. }
  116. rt_err_t rt_pwm_enable(struct rt_device_pwm *device, int channel)
  117. {
  118. rt_err_t result = RT_EOK;
  119. struct rt_pwm_configuration configuration = {0};
  120. if (!device)
  121. {
  122. return -RT_EIO;
  123. }
  124. /* Make it is positive num forever */
  125. configuration.channel = (channel > 0) ? (channel) : (-channel);
  126. /* If channel is a positive number (0 ~ n), it means using normal output pin.
  127. * If channel is a negative number (0 ~ -n), it means using complementary output pin. */
  128. if(channel > 0)
  129. {
  130. result = rt_device_control(&device->parent, PWMN_CMD_DISABLE, &configuration);
  131. }
  132. else
  133. {
  134. result = rt_device_control(&device->parent, PWMN_CMD_ENABLE, &configuration);
  135. }
  136. result = rt_device_control(&device->parent, PWM_CMD_ENABLE, &configuration);
  137. return result;
  138. }
  139. rt_err_t rt_pwm_disable(struct rt_device_pwm *device, int channel)
  140. {
  141. rt_err_t result = RT_EOK;
  142. struct rt_pwm_configuration configuration = {0};
  143. if (!device)
  144. {
  145. return -RT_EIO;
  146. }
  147. /* Make it is positive num forever */
  148. configuration.channel = (channel > 0) ? (channel) : (-channel);
  149. /* If channel is a positive number (0 ~ n), it means using normal output pin.
  150. * If channel is a negative number (0 ~ -n), it means using complementary output pin. */
  151. if(channel > 0)
  152. {
  153. result = rt_device_control(&device->parent, PWMN_CMD_DISABLE, &configuration);
  154. }
  155. else
  156. {
  157. result = rt_device_control(&device->parent, PWMN_CMD_ENABLE, &configuration);
  158. }
  159. result = rt_device_control(&device->parent, PWM_CMD_DISABLE, &configuration);
  160. return result;
  161. }
  162. rt_err_t rt_pwm_set(struct rt_device_pwm *device, int channel, rt_uint32_t period, rt_uint32_t pulse)
  163. {
  164. rt_err_t result = RT_EOK;
  165. struct rt_pwm_configuration configuration = {0};
  166. if (!device)
  167. {
  168. return -RT_EIO;
  169. }
  170. configuration.channel = (channel > 0) ? (channel) : (-channel);
  171. configuration.period = period;
  172. configuration.pulse = pulse;
  173. result = rt_device_control(&device->parent, PWM_CMD_SET, &configuration);
  174. return result;
  175. }
  176. rt_err_t rt_pwm_set_period(struct rt_device_pwm *device, int channel, rt_uint32_t period)
  177. {
  178. rt_err_t result = RT_EOK;
  179. struct rt_pwm_configuration configuration = {0};
  180. if (!device)
  181. {
  182. return -RT_EIO;
  183. }
  184. configuration.channel = (channel > 0) ? (channel) : (-channel);
  185. configuration.period = period;
  186. result = rt_device_control(&device->parent, PWM_CMD_SET_PERIOD, &configuration);
  187. return result;
  188. }
  189. rt_err_t rt_pwm_set_pulse(struct rt_device_pwm *device, int channel, rt_uint32_t pulse)
  190. {
  191. rt_err_t result = RT_EOK;
  192. struct rt_pwm_configuration configuration = {0};
  193. if (!device)
  194. {
  195. return -RT_EIO;
  196. }
  197. configuration.channel = (channel > 0) ? (channel) : (-channel);
  198. configuration.pulse = pulse;
  199. result = rt_device_control(&device->parent, PWM_CMD_SET_PULSE, &configuration);
  200. return result;
  201. }
  202. rt_err_t rt_pwm_get(struct rt_device_pwm *device, struct rt_pwm_configuration *cfg)
  203. {
  204. rt_err_t result = RT_EOK;
  205. if (!device)
  206. {
  207. return -RT_EIO;
  208. }
  209. result = rt_device_control(&device->parent, PWM_CMD_GET, cfg);
  210. return result;
  211. }
  212. #ifdef RT_USING_FINSH
  213. #include <stdlib.h>
  214. #include <string.h>
  215. #include <finsh.h>
  216. static int pwm(int argc, char **argv)
  217. {
  218. rt_err_t result = -RT_ERROR;
  219. char *result_str;
  220. static struct rt_device_pwm *pwm_device = RT_NULL;
  221. struct rt_pwm_configuration cfg = {0};
  222. if(argc > 1)
  223. {
  224. if(!strcmp(argv[1], "probe"))
  225. {
  226. if(argc == 3)
  227. {
  228. pwm_device = (struct rt_device_pwm *)rt_device_find(argv[2]);
  229. result_str = (pwm_device == RT_NULL) ? "failure" : "success";
  230. rt_kprintf("probe %s %s\n", argv[2], result_str);
  231. }
  232. else
  233. {
  234. rt_kprintf("pwm probe <device name> - probe pwm by name\n");
  235. }
  236. }
  237. else
  238. {
  239. if(pwm_device == RT_NULL)
  240. {
  241. rt_kprintf("Please using 'pwm probe <device name>' first.\n");
  242. return -RT_ERROR;
  243. }
  244. if(!strcmp(argv[1], "enable"))
  245. {
  246. if(argc == 3)
  247. {
  248. result = rt_pwm_enable(pwm_device, atoi(argv[2]));
  249. result_str = (result == RT_EOK) ? "success" : "failure";
  250. rt_kprintf("%s channel %d is enabled %s \n", pwm_device->parent.parent.name, atoi(argv[2]), result_str);
  251. }
  252. else
  253. {
  254. rt_kprintf("pwm enable <channel> - enable pwm channel\n");
  255. rt_kprintf(" e.g. MSH >pwm enable 1 - PWM_CH1 nomal\n");
  256. rt_kprintf(" e.g. MSH >pwm enable -1 - PWM_CH1N complememtary\n");
  257. }
  258. }
  259. else if(!strcmp(argv[1], "disable"))
  260. {
  261. if(argc == 3)
  262. {
  263. result = rt_pwm_disable(pwm_device, atoi(argv[2]));
  264. }
  265. else
  266. {
  267. rt_kprintf("pwm disable <channel> - disable pwm channel\n");
  268. }
  269. }
  270. else if(!strcmp(argv[1], "get"))
  271. {
  272. cfg.channel = atoi(argv[2]);
  273. result = rt_pwm_get(pwm_device, &cfg);
  274. if(result == RT_EOK)
  275. {
  276. rt_kprintf("Info of device [%s] channel [%d]:\n",pwm_device, atoi(argv[2]));
  277. rt_kprintf("period : %d\n", cfg.period);
  278. rt_kprintf("pulse : %d\n", cfg.pulse);
  279. rt_kprintf("Duty cycle : %d%%\n",(int)(((double)(cfg.pulse)/(cfg.period)) * 100));
  280. }
  281. else
  282. {
  283. rt_kprintf("Get info of device: [%s] error.\n", pwm_device);
  284. }
  285. }
  286. else if (!strcmp(argv[1], "set"))
  287. {
  288. if(argc == 5)
  289. {
  290. result = rt_pwm_set(pwm_device, atoi(argv[2]), atoi(argv[3]), atoi(argv[4]));
  291. rt_kprintf("pwm info set on %s at channel %d\n",pwm_device,atoi(argv[2]));
  292. }
  293. else
  294. {
  295. rt_kprintf("Set info of device: [%s] error\n", pwm_device);
  296. rt_kprintf("Usage: pwm set <channel> <period> <pulse>\n");
  297. }
  298. }
  299. else
  300. {
  301. rt_kprintf("pwm get <channel> - get pwm channel info\n");
  302. }
  303. }
  304. }
  305. else
  306. {
  307. rt_kprintf("Usage: \n");
  308. rt_kprintf("pwm probe <device name> - probe pwm by name\n");
  309. rt_kprintf("pwm enable <channel> - enable pwm channel\n");
  310. rt_kprintf("pwm disable <channel> - disable pwm channel\n");
  311. rt_kprintf("pwm get <channel> - get pwm channel info\n");
  312. rt_kprintf("pwm set <channel> <period> <pulse> - set pwm channel info\n");
  313. result = - RT_ERROR;
  314. }
  315. return RT_EOK;
  316. }
  317. MSH_CMD_EXPORT(pwm, pwm [option]);
  318. #endif /* RT_USING_FINSH */