drv_pwm.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. /*
  2. * Copyright (c) 2006-2022, Synwit Technology Co.,Ltd.
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2021-07-01 lik first version
  9. */
  10. #include "drv_pwm.h"
  11. #ifdef RT_USING_PWM
  12. #ifdef BSP_USING_PWM
  13. //#define DRV_DEBUG
  14. #define LOG_TAG "drv.pwm"
  15. #include <drv_log.h>
  16. #if !defined(BSP_USING_PWM0) && !defined(BSP_USING_PWM1) && !defined(BSP_USING_PWM2) && !defined(BSP_USING_PWM3) && !defined(BSP_USING_PWM4)
  17. #error "Please define at least one BSP_USING_PWMx"
  18. /* this driver can be disabled at menuconfig ? RT-Thread Components ? Device Drivers */
  19. #endif
  20. #define MIN_PERIOD 2
  21. #define MIN_PULSE 1
  22. #ifdef BSP_USING_PWM0
  23. #ifndef PWM0_CFG
  24. #define PWM0_CFG \
  25. { \
  26. .name = "pwm0", \
  27. .PWMx = PWM0, \
  28. .pwm_initstruct.Mode = PWM_CENTER_ALIGNED, \
  29. .pwm_initstruct.Clkdiv = 15, \
  30. .pwm_initstruct.Period = 10000, \
  31. .pwm_initstruct.HdutyA = 5000, \
  32. .pwm_initstruct.DeadzoneA = 0, \
  33. .pwm_initstruct.IdleLevelA = 0, \
  34. .pwm_initstruct.IdleLevelAN = 0, \
  35. .pwm_initstruct.OutputInvA = 0, \
  36. .pwm_initstruct.OutputInvAN = 1, \
  37. .pwm_initstruct.HdutyB = 5000, \
  38. .pwm_initstruct.DeadzoneB = 0, \
  39. .pwm_initstruct.IdleLevelB = 0, \
  40. .pwm_initstruct.IdleLevelBN = 0, \
  41. .pwm_initstruct.OutputInvB = 0, \
  42. .pwm_initstruct.OutputInvBN = 1, \
  43. .pwm_initstruct.UpOvfIE = 0, \
  44. .pwm_initstruct.DownOvfIE = 0, \
  45. .pwm_initstruct.UpCmpAIE = 0, \
  46. .pwm_initstruct.DownCmpAIE = 0, \
  47. .pwm_initstruct.UpCmpBIE = 0, \
  48. .pwm_initstruct.DownCmpBIE = 0, \
  49. .pwm_mask = PWM0_MSK, \
  50. }
  51. #endif /* PWM0_CFG */
  52. #endif /* BSP_USING_PWM0 */
  53. #ifdef BSP_USING_PWM1
  54. #ifndef PWM1_CFG
  55. #define PWM1_CFG \
  56. { \
  57. .name = "pwm1", \
  58. .PWMx = PWM1, \
  59. .pwm_initstruct.Mode = PWM_CENTER_ALIGNED, \
  60. .pwm_initstruct.Clkdiv = 15, \
  61. .pwm_initstruct.Period = 10000, \
  62. .pwm_initstruct.HdutyA = 5000, \
  63. .pwm_initstruct.DeadzoneA = 0, \
  64. .pwm_initstruct.IdleLevelA = 0, \
  65. .pwm_initstruct.IdleLevelAN = 0, \
  66. .pwm_initstruct.OutputInvA = 0, \
  67. .pwm_initstruct.OutputInvAN = 1, \
  68. .pwm_initstruct.HdutyB = 5000, \
  69. .pwm_initstruct.DeadzoneB = 0, \
  70. .pwm_initstruct.IdleLevelB = 0, \
  71. .pwm_initstruct.IdleLevelBN = 0, \
  72. .pwm_initstruct.OutputInvB = 0, \
  73. .pwm_initstruct.OutputInvBN = 1, \
  74. .pwm_initstruct.UpOvfIE = 0, \
  75. .pwm_initstruct.DownOvfIE = 0, \
  76. .pwm_initstruct.UpCmpAIE = 0, \
  77. .pwm_initstruct.DownCmpAIE = 0, \
  78. .pwm_initstruct.UpCmpBIE = 0, \
  79. .pwm_initstruct.DownCmpBIE = 0, \
  80. .pwm_mask = PWM1_MSK, \
  81. }
  82. #endif /* PWM1_CFG */
  83. #endif /* BSP_USING_PWM1 */
  84. #ifdef BSP_USING_PWM2
  85. #ifndef PWM2_CFG
  86. #define PWM2_CFG \
  87. { \
  88. .name = "pwm2", \
  89. .PWMx = PWM2, \
  90. .pwm_initstruct.Mode = PWM_CENTER_ALIGNED, \
  91. .pwm_initstruct.Clkdiv = 15, \
  92. .pwm_initstruct.Period = 10000, \
  93. .pwm_initstruct.HdutyA = 5000, \
  94. .pwm_initstruct.DeadzoneA = 0, \
  95. .pwm_initstruct.IdleLevelA = 0, \
  96. .pwm_initstruct.IdleLevelAN = 0, \
  97. .pwm_initstruct.OutputInvA = 0, \
  98. .pwm_initstruct.OutputInvAN = 1, \
  99. .pwm_initstruct.HdutyB = 5000, \
  100. .pwm_initstruct.DeadzoneB = 0, \
  101. .pwm_initstruct.IdleLevelB = 0, \
  102. .pwm_initstruct.IdleLevelBN = 0, \
  103. .pwm_initstruct.OutputInvB = 0, \
  104. .pwm_initstruct.OutputInvBN = 1, \
  105. .pwm_initstruct.UpOvfIE = 0, \
  106. .pwm_initstruct.DownOvfIE = 0, \
  107. .pwm_initstruct.UpCmpAIE = 0, \
  108. .pwm_initstruct.DownCmpAIE = 0, \
  109. .pwm_initstruct.UpCmpBIE = 0, \
  110. .pwm_initstruct.DownCmpBIE = 0, \
  111. .pwm_mask = PWM2_MSK, \
  112. }
  113. #endif /* PWM2_CFG */
  114. #endif /* BSP_USING_PWM2 */
  115. #ifdef BSP_USING_PWM3
  116. #ifndef PWM3_CFG
  117. #define PWM3_CFG \
  118. { \
  119. .name = "pwm3", \
  120. .PWMx = PWM3, \
  121. .pwm_initstruct.Mode = PWM_CENTER_ALIGNED, \
  122. .pwm_initstruct.Clkdiv = 15, \
  123. .pwm_initstruct.Period = 10000, \
  124. .pwm_initstruct.HdutyA = 5000, \
  125. .pwm_initstruct.DeadzoneA = 0, \
  126. .pwm_initstruct.IdleLevelA = 0, \
  127. .pwm_initstruct.IdleLevelAN = 0, \
  128. .pwm_initstruct.OutputInvA = 0, \
  129. .pwm_initstruct.OutputInvAN = 1, \
  130. .pwm_initstruct.HdutyB = 5000, \
  131. .pwm_initstruct.DeadzoneB = 0, \
  132. .pwm_initstruct.IdleLevelB = 0, \
  133. .pwm_initstruct.IdleLevelBN = 0, \
  134. .pwm_initstruct.OutputInvB = 0, \
  135. .pwm_initstruct.OutputInvBN = 1, \
  136. .pwm_initstruct.UpOvfIE = 0, \
  137. .pwm_initstruct.DownOvfIE = 0, \
  138. .pwm_initstruct.UpCmpAIE = 0, \
  139. .pwm_initstruct.DownCmpAIE = 0, \
  140. .pwm_initstruct.UpCmpBIE = 0, \
  141. .pwm_initstruct.DownCmpBIE = 0, \
  142. .pwm_mask = PWM3_MSK, \
  143. }
  144. #endif /* PWM3_CFG */
  145. #endif /* BSP_USING_PWM3 */
  146. #ifdef BSP_USING_PWM4
  147. #ifndef PWM4_CFG
  148. #define PWM4_CFG \
  149. { \
  150. .name = "pwm4", \
  151. .PWMx = PWM4, \
  152. .pwm_initstruct.Mode = PWM_CENTER_ALIGNED, \
  153. .pwm_initstruct.Clkdiv = 15, \
  154. .pwm_initstruct.Period = 10000, \
  155. .pwm_initstruct.HdutyA = 5000, \
  156. .pwm_initstruct.DeadzoneA = 0, \
  157. .pwm_initstruct.IdleLevelA = 0, \
  158. .pwm_initstruct.IdleLevelAN = 0, \
  159. .pwm_initstruct.OutputInvA = 0, \
  160. .pwm_initstruct.OutputInvAN = 1, \
  161. .pwm_initstruct.HdutyB = 5000, \
  162. .pwm_initstruct.DeadzoneB = 0, \
  163. .pwm_initstruct.IdleLevelB = 0, \
  164. .pwm_initstruct.IdleLevelBN = 0, \
  165. .pwm_initstruct.OutputInvB = 0, \
  166. .pwm_initstruct.OutputInvBN = 1, \
  167. .pwm_initstruct.UpOvfIE = 0, \
  168. .pwm_initstruct.DownOvfIE = 0, \
  169. .pwm_initstruct.UpCmpAIE = 0, \
  170. .pwm_initstruct.DownCmpAIE = 0, \
  171. .pwm_initstruct.UpCmpBIE = 0, \
  172. .pwm_initstruct.DownCmpBIE = 0, \
  173. .pwm_mask = PWM4_MSK, \
  174. }
  175. #endif /* PWM4_CFG */
  176. #endif /* BSP_USING_PWM4 */
  177. struct swm_pwm_cfg
  178. {
  179. const char *name;
  180. PWM_TypeDef *PWMx;
  181. PWM_InitStructure pwm_initstruct;
  182. uint32_t pwm_mask;
  183. };
  184. struct swm_pwm_device
  185. {
  186. struct swm_pwm_cfg *pwm_cfg;
  187. struct rt_device_pwm pwm_device;
  188. };
  189. static struct swm_pwm_cfg swm_pwm_cfg[] =
  190. {
  191. #ifdef BSP_USING_PWM0
  192. PWM0_CFG,
  193. #endif
  194. #ifdef BSP_USING_PWM1
  195. PWM1_CFG,
  196. #endif
  197. #ifdef BSP_USING_PWM2
  198. PWM2_CFG,
  199. #endif
  200. #ifdef BSP_USING_PWM3
  201. PWM3_CFG,
  202. #endif
  203. #ifdef BSP_USING_PWM4
  204. PWM4_CFG,
  205. #endif
  206. };
  207. static struct swm_pwm_device pwm_obj[sizeof(swm_pwm_cfg) / sizeof(swm_pwm_cfg[0])] = {0};
  208. static rt_err_t swm_pwm_enable(struct rt_device_pwm *pwm_device, struct rt_pwm_configuration *configuration, rt_bool_t enable)
  209. {
  210. struct swm_pwm_cfg *pwm_cfg = RT_NULL;
  211. RT_ASSERT(pwm_device != RT_NULL);
  212. pwm_cfg = pwm_device->parent.user_data;
  213. if (!enable)
  214. {
  215. PWM_Stop(pwm_cfg->pwm_mask);
  216. }
  217. else
  218. {
  219. PWM_Start(pwm_cfg->pwm_mask);
  220. }
  221. return RT_EOK;
  222. }
  223. static rt_err_t swm_pwm_get(struct rt_device_pwm *pwm_device, struct rt_pwm_configuration *configuration)
  224. {
  225. rt_uint64_t tim_clock;
  226. struct swm_pwm_cfg *pwm_cfg = RT_NULL;
  227. RT_ASSERT(pwm_device != RT_NULL);
  228. pwm_cfg = pwm_device->parent.user_data;
  229. configuration->period = PWM_GetPeriod(pwm_cfg->PWMx) * 1000UL; //中心对称模式下频率降低一半
  230. configuration->pulse = PWM_GetHDuty(pwm_cfg->PWMx, configuration->channel) * 1000UL;
  231. return RT_EOK;
  232. }
  233. static rt_err_t swm_pwm_set(struct rt_device_pwm *pwm_device, struct rt_pwm_configuration *configuration)
  234. {
  235. rt_uint32_t period, pulse;
  236. rt_uint64_t tim_clock;
  237. struct swm_pwm_cfg *pwm_cfg = RT_NULL;
  238. RT_ASSERT(pwm_device != RT_NULL);
  239. pwm_cfg = pwm_device->parent.user_data;
  240. period = (unsigned long long)configuration->period / 1000UL; //中心对称模式下频率降低一半
  241. pulse = (unsigned long long)configuration->pulse / 1000UL;
  242. if (period < MIN_PERIOD)
  243. {
  244. period = MIN_PERIOD;
  245. }
  246. if (pulse < MIN_PULSE)
  247. {
  248. pulse = MIN_PULSE;
  249. }
  250. PWM_SetPeriod(pwm_cfg->PWMx, period);
  251. PWM_SetHDuty(pwm_cfg->PWMx, PWM_CH_A, pulse);
  252. PWM_SetHDuty(pwm_cfg->PWMx, PWM_CH_B, pulse);
  253. return RT_EOK;
  254. }
  255. static rt_err_t swm_pwm_control(struct rt_device_pwm *pwm_device, int cmd, void *arg)
  256. {
  257. RT_ASSERT(pwm_device != RT_NULL);
  258. struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)arg;
  259. switch (cmd)
  260. {
  261. case PWM_CMD_ENABLE:
  262. return swm_pwm_enable(pwm_device, configuration, RT_TRUE);
  263. case PWM_CMD_DISABLE:
  264. return swm_pwm_enable(pwm_device, configuration, RT_FALSE);
  265. case PWM_CMD_SET:
  266. return swm_pwm_set(pwm_device, configuration);
  267. case PWM_CMD_GET:
  268. return swm_pwm_get(pwm_device, configuration);
  269. default:
  270. return -RT_EINVAL;
  271. }
  272. }
  273. static const struct rt_pwm_ops pwm_ops =
  274. {
  275. .control = swm_pwm_control};
  276. int swm_pwm_init(void)
  277. {
  278. int i = 0;
  279. int result = RT_EOK;
  280. for (i = 0; i < sizeof(swm_pwm_cfg) / sizeof(swm_pwm_cfg[0]); i++)
  281. {
  282. pwm_obj[i].pwm_cfg = &swm_pwm_cfg[i];
  283. if (pwm_obj[i].pwm_cfg->PWMx == PWM0)
  284. {
  285. #ifdef BSP_USING_PWM0A
  286. PORT_Init(PORTM, PIN1, PORTM_PIN1_PWM0A, 0);
  287. #endif
  288. #ifdef BSP_USING_PWM0AN
  289. PORT_Init(PORTM, PIN4, PORTM_PIN4_PWM0AN, 0);
  290. #endif
  291. #ifdef BSP_USING_PWM0B
  292. PORT_Init(PORTM, PIN2, PORTM_PIN2_PWM0B, 0);
  293. #endif
  294. #ifdef BSP_USING_PWM0BN
  295. PORT_Init(PORTM, PIN5, PORTM_PIN5_PWM0BN, 0);
  296. #endif
  297. }
  298. else if (pwm_obj[i].pwm_cfg->PWMx == PWM1)
  299. {
  300. #ifdef BSP_USING_PWM1A
  301. PORT_Init(PORTM, PIN3, PORTM_PIN3_PWM1A, 0);
  302. #endif
  303. #ifdef BSP_USING_PWM1AN
  304. PORT_Init(PORTM, PIN6, PORTM_PIN6_PWM1AN, 0);
  305. #endif
  306. #ifdef BSP_USING_PWM1B
  307. PORT_Init(PORTD, PIN9, PORTD_PIN9_PWM1B, 0);
  308. #endif
  309. #ifdef BSP_USING_PWM1BN
  310. PORT_Init(PORTD, PIN8, PORTD_PIN8_PWM1BN, 0);
  311. #endif
  312. }
  313. else if (pwm_obj[i].pwm_cfg->PWMx == PWM2)
  314. {
  315. #ifdef BSP_USING_PWM2A
  316. PORT_Init(PORTM, PIN12, PORTM_PIN12_PWM2A, 0);
  317. #endif
  318. #ifdef BSP_USING_PWM2AN
  319. PORT_Init(PORTM, PIN9, PORTM_PIN9_PWM2AN, 0);
  320. #endif
  321. #ifdef BSP_USING_PWM2B
  322. PORT_Init(PORTM, PIN11, PORTM_PIN11_PWM2B, 0);
  323. #endif
  324. #ifdef BSP_USING_PWM2BN
  325. PORT_Init(PORTM, PIN8, PORTM_PIN8_PWM2BN, 0);
  326. #endif
  327. }
  328. else if (pwm_obj[i].pwm_cfg->PWMx == PWM3)
  329. {
  330. #ifdef BSP_USING_PWM3A
  331. PORT_Init(PORTC, PIN2, PORTC_PIN2_PWM3A, 0);
  332. #endif
  333. #ifdef BSP_USING_PWM3AN
  334. PORT_Init(PORTC, PIN3, PORTC_PIN3_PWM3AN, 0);
  335. #endif
  336. #ifdef BSP_USING_PWM3B
  337. PORT_Init(PORTB, PIN1, PORTB_PIN1_PWM3B, 0);
  338. #endif
  339. #ifdef BSP_USING_PWM3BN
  340. PORT_Init(PORTB, PIN0, PORTB_PIN0_PWM3BN, 0);
  341. #endif
  342. }
  343. else if (pwm_obj[i].pwm_cfg->PWMx == PWM4)
  344. {
  345. #ifdef BSP_USING_PWM4A
  346. PORT_Init(PORTB, PIN15, PORTB_PIN15_PWM4A, 0);
  347. #endif
  348. #ifdef BSP_USING_PWM4AN
  349. // PORT_Init(PORTB, PIN14, PORTB_PIN14_PWM4AN, 0); //SWDIO
  350. #endif
  351. #ifdef BSP_USING_PWM4B
  352. PORT_Init(PORTB, PIN13, PORTB_PIN13_PWM4B, 0);
  353. #endif
  354. #ifdef BSP_USING_PWM4BN
  355. // PORT_Init(PORTB, PIN12, PORTB_PIN12_PWM4BN, 0); //SWDCK
  356. #endif
  357. }
  358. pwm_obj[i].pwm_cfg->pwm_initstruct.Clkdiv = SystemCoreClock / 1000000UL / 2; //中心对称模式下频率降低一半
  359. PWM_Init(pwm_obj[i].pwm_cfg->PWMx, &(pwm_obj[i].pwm_cfg->pwm_initstruct));
  360. result = rt_device_pwm_register(&pwm_obj[i].pwm_device, pwm_obj[i].pwm_cfg->name, &pwm_ops, pwm_obj[i].pwm_cfg);
  361. if(result != RT_EOK)
  362. {
  363. LOG_E("%s register fail.", pwm_obj[i].pwm_cfg->name);
  364. }
  365. else
  366. {
  367. LOG_D("%s register success.", pwm_obj[i].pwm_cfg->name);
  368. }
  369. }
  370. return result;
  371. }
  372. INIT_DEVICE_EXPORT(swm_pwm_init);
  373. #endif /* BSP_USING_PWM */
  374. #endif /* RT_USING_PWM */