rt_drv_pwm.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. /*
  2. * Copyright (c) 2006-2023, 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. * 2022-09-24 qiyu Add dead-time and phase configuration
  13. * 2023-12-23 1ridic Add second-level command completion
  14. */
  15. #include <rtdevice.h>
  16. static rt_err_t _pwm_control(rt_device_t dev, int cmd, void *args)
  17. {
  18. rt_err_t result = RT_EOK;
  19. struct rt_device_pwm *pwm = (struct rt_device_pwm *)dev;
  20. struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)args;
  21. switch (cmd)
  22. {
  23. case PWMN_CMD_ENABLE:
  24. configuration->complementary = RT_TRUE;
  25. break;
  26. case PWMN_CMD_DISABLE:
  27. configuration->complementary = RT_FALSE;
  28. break;
  29. default:
  30. if (pwm->ops->control)
  31. result = pwm->ops->control(pwm, cmd, args);
  32. break;
  33. }
  34. return result;
  35. }
  36. /*
  37. pos: channel
  38. void *buffer: rt_uint32_t pulse[size]
  39. size : number of pulse, only set to sizeof(rt_uint32_t).
  40. */
  41. static rt_ssize_t _pwm_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
  42. {
  43. rt_err_t result = RT_EOK;
  44. struct rt_device_pwm *pwm = (struct rt_device_pwm *)dev;
  45. rt_uint32_t *pulse = (rt_uint32_t *)buffer;
  46. struct rt_pwm_configuration configuration = {0};
  47. configuration.channel = (pos > 0) ? (pos) : (-pos);
  48. if (pwm->ops->control)
  49. {
  50. result = pwm->ops->control(pwm, PWM_CMD_GET, &configuration);
  51. if (result != RT_EOK)
  52. {
  53. return 0;
  54. }
  55. *pulse = configuration.pulse;
  56. }
  57. return size;
  58. }
  59. /*
  60. pos: channel
  61. void *buffer: rt_uint32_t pulse[size]
  62. size : number of pulse, only set to sizeof(rt_uint32_t).
  63. */
  64. static rt_ssize_t _pwm_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
  65. {
  66. rt_err_t result = RT_EOK;
  67. struct rt_device_pwm *pwm = (struct rt_device_pwm *)dev;
  68. rt_uint32_t *pulse = (rt_uint32_t *)buffer;
  69. struct rt_pwm_configuration configuration = {0};
  70. configuration.channel = (pos > 0) ? (pos) : (-pos);
  71. if (pwm->ops->control)
  72. {
  73. result = pwm->ops->control(pwm, PWM_CMD_GET, &configuration);
  74. if (result != RT_EOK)
  75. {
  76. return 0;
  77. }
  78. configuration.pulse = *pulse;
  79. result = pwm->ops->control(pwm, PWM_CMD_SET, &configuration);
  80. if (result != RT_EOK)
  81. {
  82. return 0;
  83. }
  84. }
  85. return size;
  86. }
  87. #ifdef RT_USING_DEVICE_OPS
  88. static const struct rt_device_ops pwm_device_ops =
  89. {
  90. RT_NULL,
  91. RT_NULL,
  92. RT_NULL,
  93. _pwm_read,
  94. _pwm_write,
  95. _pwm_control
  96. };
  97. #endif /* RT_USING_DEVICE_OPS */
  98. 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)
  99. {
  100. rt_err_t result = RT_EOK;
  101. rt_memset(device, 0, sizeof(struct rt_device_pwm));
  102. #ifdef RT_USING_DEVICE_OPS
  103. device->parent.ops = &pwm_device_ops;
  104. #else
  105. device->parent.init = RT_NULL;
  106. device->parent.open = RT_NULL;
  107. device->parent.close = RT_NULL;
  108. device->parent.read = _pwm_read;
  109. device->parent.write = _pwm_write;
  110. device->parent.control = _pwm_control;
  111. #endif /* RT_USING_DEVICE_OPS */
  112. device->parent.type = RT_Device_Class_PWM;
  113. device->ops = ops;
  114. device->parent.user_data = (void *)user_data;
  115. result = rt_device_register(&device->parent, name, RT_DEVICE_FLAG_RDWR);
  116. return result;
  117. }
  118. rt_err_t rt_pwm_enable(struct rt_device_pwm *device, int channel)
  119. {
  120. rt_err_t result = RT_EOK;
  121. struct rt_pwm_configuration configuration = {0};
  122. if (!device)
  123. {
  124. return -RT_EIO;
  125. }
  126. /* Make it is positive num forever */
  127. configuration.channel = (channel > 0) ? (channel) : (-channel);
  128. /* If channel is a positive number (0 ~ n), it means using normal output pin.
  129. * If channel is a negative number (0 ~ -n), it means using complementary output pin. */
  130. if (channel > 0)
  131. {
  132. result = rt_device_control(&device->parent, PWMN_CMD_DISABLE, &configuration);
  133. }
  134. else
  135. {
  136. result = rt_device_control(&device->parent, PWMN_CMD_ENABLE, &configuration);
  137. }
  138. result = rt_device_control(&device->parent, PWM_CMD_ENABLE, &configuration);
  139. return result;
  140. }
  141. rt_err_t rt_pwm_disable(struct rt_device_pwm *device, int channel)
  142. {
  143. rt_err_t result = RT_EOK;
  144. struct rt_pwm_configuration configuration = {0};
  145. if (!device)
  146. {
  147. return -RT_EIO;
  148. }
  149. /* Make it is positive num forever */
  150. configuration.channel = (channel > 0) ? (channel) : (-channel);
  151. /* If channel is a positive number (0 ~ n), it means using normal output pin.
  152. * If channel is a negative number (0 ~ -n), it means using complementary output pin. */
  153. if (channel > 0)
  154. {
  155. result = rt_device_control(&device->parent, PWMN_CMD_DISABLE, &configuration);
  156. }
  157. else
  158. {
  159. result = rt_device_control(&device->parent, PWMN_CMD_ENABLE, &configuration);
  160. }
  161. result = rt_device_control(&device->parent, PWM_CMD_DISABLE, &configuration);
  162. return result;
  163. }
  164. rt_err_t rt_pwm_set(struct rt_device_pwm *device, int channel, rt_uint32_t period, rt_uint32_t pulse)
  165. {
  166. rt_err_t result = RT_EOK;
  167. struct rt_pwm_configuration configuration = {0};
  168. if (!device)
  169. {
  170. return -RT_EIO;
  171. }
  172. configuration.channel = (channel > 0) ? (channel) : (-channel);
  173. configuration.period = period;
  174. configuration.pulse = pulse;
  175. result = rt_device_control(&device->parent, PWM_CMD_SET, &configuration);
  176. return result;
  177. }
  178. rt_err_t rt_pwm_set_period(struct rt_device_pwm *device, int channel, rt_uint32_t period)
  179. {
  180. rt_err_t result = RT_EOK;
  181. struct rt_pwm_configuration configuration = {0};
  182. if (!device)
  183. {
  184. return -RT_EIO;
  185. }
  186. configuration.channel = (channel > 0) ? (channel) : (-channel);
  187. configuration.period = period;
  188. result = rt_device_control(&device->parent, PWM_CMD_SET_PERIOD, &configuration);
  189. return result;
  190. }
  191. rt_err_t rt_pwm_set_pulse(struct rt_device_pwm *device, int channel, rt_uint32_t pulse)
  192. {
  193. rt_err_t result = RT_EOK;
  194. struct rt_pwm_configuration configuration = {0};
  195. if (!device)
  196. {
  197. return -RT_EIO;
  198. }
  199. configuration.channel = (channel > 0) ? (channel) : (-channel);
  200. configuration.pulse = pulse;
  201. result = rt_device_control(&device->parent, PWM_CMD_SET_PULSE, &configuration);
  202. return result;
  203. }
  204. rt_err_t rt_pwm_set_dead_time(struct rt_device_pwm *device, int channel, rt_uint32_t dead_time)
  205. {
  206. rt_err_t result = RT_EOK;
  207. struct rt_pwm_configuration configuration = {0};
  208. if (!device)
  209. {
  210. return -RT_EIO;
  211. }
  212. configuration.channel = (channel > 0) ? (channel) : (-channel);
  213. configuration.dead_time = dead_time;
  214. result = rt_device_control(&device->parent, PWM_CMD_SET_DEAD_TIME, &configuration);
  215. return result;
  216. }
  217. rt_err_t rt_pwm_set_phase(struct rt_device_pwm *device, int channel, rt_uint32_t phase)
  218. {
  219. rt_err_t result = RT_EOK;
  220. struct rt_pwm_configuration configuration = {0};
  221. if (!device)
  222. {
  223. return -RT_EIO;
  224. }
  225. configuration.channel = (channel > 0) ? (channel) : (-channel);
  226. configuration.phase = phase;
  227. result = rt_device_control(&device->parent, PWM_CMD_SET_PHASE, &configuration);
  228. return result;
  229. }
  230. rt_err_t rt_pwm_get(struct rt_device_pwm *device, struct rt_pwm_configuration *cfg)
  231. {
  232. rt_err_t result = RT_EOK;
  233. if (!device)
  234. {
  235. return -RT_EIO;
  236. }
  237. result = rt_device_control(&device->parent, PWM_CMD_GET, cfg);
  238. return result;
  239. }
  240. #ifdef RT_USING_FINSH
  241. #include <stdlib.h>
  242. #include <string.h>
  243. #include <finsh.h>
  244. static enum pwm_list_parameters
  245. {
  246. PWM_LIST_PROBE = 1,
  247. PWM_LIST_ENABLE,
  248. PWM_LIST_DISABLE,
  249. PWM_LIST_GET,
  250. PWM_LIST_SET,
  251. PWM_LIST_PHASE,
  252. PWM_LIST_DEAD_TIME,
  253. } pwm_list_parameters;
  254. CMD_OPTIONS_STATEMENT(pwm_list)
  255. int pwm_list(int argc, char **argv)
  256. {
  257. rt_err_t result = -RT_ERROR;
  258. char *result_str;
  259. static struct rt_device_pwm *pwm_device = RT_NULL;
  260. struct rt_pwm_configuration cfg = {0};
  261. if (argc > 1)
  262. {
  263. if (MSH_OPT_ID_GET(pwm_list) == PWM_LIST_PROBE)
  264. {
  265. if (argc == 3)
  266. {
  267. pwm_device = (struct rt_device_pwm *)rt_device_find(argv[2]);
  268. result_str = (pwm_device == RT_NULL) ? "failure" : "success";
  269. rt_kprintf("probe %s %s\n", argv[2], result_str);
  270. }
  271. else
  272. {
  273. rt_kprintf("pwm probe <device name> - probe pwm by name\n");
  274. }
  275. }
  276. else if (pwm_device == RT_NULL)
  277. {
  278. rt_kprintf("Please using 'pwm probe <device name>' first.\n");
  279. return -RT_ERROR;
  280. }
  281. switch (MSH_OPT_ID_GET(pwm_list))
  282. {
  283. case PWM_LIST_ENABLE:
  284. if (argc == 3)
  285. {
  286. result = rt_pwm_enable(pwm_device, atoi(argv[2]));
  287. result_str = (result == RT_EOK) ? "success" : "failure";
  288. rt_kprintf("%s channel %d is enabled %s \n", pwm_device->parent.parent.name, atoi(argv[2]), result_str);
  289. }
  290. else
  291. {
  292. rt_kprintf("pwm enable <channel> - enable pwm channel\n");
  293. rt_kprintf(" e.g. MSH >pwm enable 1 - PWM_CH1 nomal\n");
  294. rt_kprintf(" e.g. MSH >pwm enable -1 - PWM_CH1N complememtary\n");
  295. }
  296. break;
  297. case PWM_LIST_DISABLE:
  298. if (argc == 3)
  299. {
  300. result = rt_pwm_disable(pwm_device, atoi(argv[2]));
  301. }
  302. else
  303. {
  304. rt_kprintf("pwm disable <channel> - disable pwm channel\n");
  305. }
  306. break;
  307. case PWM_LIST_GET:
  308. cfg.channel = atoi(argv[2]);
  309. result = rt_pwm_get(pwm_device, &cfg);
  310. if (result == RT_EOK)
  311. {
  312. rt_kprintf("Info of device [%s] channel [%d]:\n", pwm_device, atoi(argv[2]));
  313. rt_kprintf("period : %d\n", cfg.period);
  314. rt_kprintf("pulse : %d\n", cfg.pulse);
  315. rt_kprintf("Duty cycle : %d%%\n", (int)(((double)(cfg.pulse) / (cfg.period)) * 100));
  316. }
  317. else
  318. {
  319. rt_kprintf("Get info of device: [%s] error.\n", pwm_device);
  320. }
  321. break;
  322. case PWM_LIST_SET:
  323. if (argc == 5)
  324. {
  325. result = rt_pwm_set(pwm_device, atoi(argv[2]), atoi(argv[3]), atoi(argv[4]));
  326. rt_kprintf("pwm info set on %s at channel %d\n", pwm_device, (rt_base_t)atoi(argv[2]));
  327. }
  328. else
  329. {
  330. rt_kprintf("Set info of device: [%s] error\n", pwm_device);
  331. rt_kprintf("Usage: pwm set <channel> <period> <pulse>\n");
  332. }
  333. break;
  334. case PWM_LIST_PHASE:
  335. if (argc == 4)
  336. {
  337. result = rt_pwm_set_phase(pwm_device, atoi(argv[2]), atoi(argv[3]));
  338. result_str = (result == RT_EOK) ? "success" : "failure";
  339. rt_kprintf("%s phase is set %d \n", pwm_device->parent.parent.name, (rt_base_t)atoi(argv[3]));
  340. }
  341. break;
  342. case PWM_LIST_DEAD_TIME:
  343. if (argc == 4)
  344. {
  345. result = rt_pwm_set_dead_time(pwm_device, atoi(argv[2]), atoi(argv[3]));
  346. result_str = (result == RT_EOK) ? "success" : "failure";
  347. rt_kprintf("%s dead_time is set %d \n", pwm_device->parent.parent.name, (rt_base_t)atoi(argv[3]));
  348. }
  349. break;
  350. default:
  351. goto _usage;
  352. break;
  353. }
  354. }
  355. else
  356. {
  357. goto _usage;
  358. }
  359. return result;
  360. _usage:
  361. rt_kprintf("Usage: \n");
  362. rt_kprintf("pwm probe <device name> - probe pwm by name\n");
  363. rt_kprintf("pwm enable <channel> - enable pwm channel\n");
  364. rt_kprintf("pwm disable <channel> - disable pwm channel\n");
  365. rt_kprintf("pwm get <channel> - get pwm channel info\n");
  366. rt_kprintf("pwm set <channel> <period> <pulse> - set pwm channel info\n");
  367. rt_kprintf("pwm phase <channel> <phase> - set pwm phase\n");
  368. rt_kprintf("pwm dead_time <channel> <dead_time> - set pwm dead time\n");
  369. result = -RT_ERROR;
  370. return result;
  371. }
  372. CMD_OPTIONS_NODE_START(pwm_list)
  373. CMD_OPTIONS_NODE(PWM_LIST_PROBE, probe, probe pwm by name)
  374. CMD_OPTIONS_NODE(PWM_LIST_ENABLE, enable, enable pwm channel)
  375. CMD_OPTIONS_NODE(PWM_LIST_DISABLE, disable, disable pwm channel)
  376. CMD_OPTIONS_NODE(PWM_LIST_GET, get, get pwm channel info)
  377. CMD_OPTIONS_NODE(PWM_LIST_SET, set, set pwm channel info)
  378. CMD_OPTIONS_NODE(PWM_LIST_PHASE, phase, set pwm phase)
  379. CMD_OPTIONS_NODE(PWM_LIST_DEAD_TIME, dead_time, set pwm dead time)
  380. CMD_OPTIONS_NODE_END
  381. MSH_CMD_EXPORT_ALIAS(pwm_list, pwm, control pwm device, optenable);
  382. #endif /* RT_USING_FINSH */