drv_pwm.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  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. * 2020-07-26 supperthomas first version
  9. *
  10. */
  11. #include <board.h>
  12. #include "rtdevice.h"
  13. #include "rtservice.h"
  14. #ifdef RT_USING_PWM
  15. #include <nrfx_pwm.h>
  16. struct mcu_pwm
  17. {
  18. struct rt_device_pwm pwm_device;
  19. nrfx_pwm_t *pwm_handle;
  20. nrf_pwm_values_individual_t m_demo1_seq_values;
  21. nrf_pwm_sequence_t m_demo1_seq;
  22. rt_uint8_t channel;
  23. char *name;
  24. rt_uint64_t pwm_src_clk;
  25. uint8_t channel_0_pin;
  26. uint8_t channel_1_pin;
  27. uint8_t channel_2_pin;
  28. uint8_t channel_3_pin;
  29. };
  30. enum
  31. {
  32. #ifdef BSP_USING_PWM0
  33. PWM0_INDEX,
  34. #endif
  35. #ifdef BSP_USING_PWM1
  36. PWM1_INDEX,
  37. #endif
  38. #ifdef BSP_USING_PWM2
  39. PWM2_INDEX,
  40. #endif
  41. #ifdef BSP_USING_PWM3
  42. PWM3_INDEX,
  43. #endif
  44. };
  45. #ifdef BSP_USING_PWM0
  46. static nrfx_pwm_t m_pwm0 = NRFX_PWM_INSTANCE(0);
  47. #define PWM0_CONFIG \
  48. { \
  49. .pwm_handle = &m_pwm0, \
  50. .name = "pwm0", \
  51. .pwm_src_clk = 1000000, \
  52. }
  53. #endif
  54. #ifdef BSP_USING_PWM1
  55. static nrfx_pwm_t m_pwm1 = NRFX_PWM_INSTANCE(1);
  56. #define PWM1_CONFIG \
  57. { \
  58. .pwm_handle = &m_pwm1, \
  59. .name = "pwm1", \
  60. .pwm_src_clk = 1000000, \
  61. }
  62. #endif
  63. #ifdef BSP_USING_PWM2
  64. static nrfx_pwm_t m_pwm2 = NRFX_PWM_INSTANCE(2);
  65. #define PWM2_CONFIG \
  66. { \
  67. .pwm_handle = &m_pwm2, \
  68. .name = "pwm2", \
  69. .pwm_src_clk = 1000000, \
  70. }
  71. #endif
  72. #ifdef BSP_USING_PWM3
  73. static nrfx_pwm_t m_pwm3 = NRFX_PWM_INSTANCE(3);
  74. #define PWM3_CONFIG \
  75. { \
  76. .pwm_handle = &m_pwm3, \
  77. .name = "pwm3", \
  78. .pwm_src_clk = 1000000, \
  79. }
  80. #endif
  81. static struct mcu_pwm mcu_pwm_obj[] =
  82. {
  83. #ifdef BSP_USING_PWM0
  84. PWM0_CONFIG,
  85. #endif
  86. #ifdef BSP_USING_PWM1
  87. PWM1_CONFIG,
  88. #endif
  89. #ifdef BSP_USING_PWM2
  90. PWM2_CONFIG,
  91. #endif
  92. #ifdef BSP_USING_PWM3
  93. PWM3_CONFIG,
  94. #endif
  95. };
  96. static rt_err_t drv_pwm_control(struct rt_device_pwm *device, int cmd, void *arg);
  97. static struct rt_pwm_ops drv_ops =
  98. {
  99. drv_pwm_control
  100. };
  101. static rt_err_t drv_pwm_enable(struct mcu_pwm *p_mcu, struct rt_pwm_configuration *configuration, rt_bool_t enable)
  102. {
  103. if (!enable)
  104. {
  105. nrfx_pwm_stop(p_mcu->pwm_handle, true);
  106. }
  107. else
  108. {
  109. (void)nrfx_pwm_simple_playback(p_mcu->pwm_handle, &p_mcu->m_demo1_seq, 1, NRFX_PWM_FLAG_LOOP);
  110. }
  111. return RT_EOK;
  112. }
  113. uint8_t mcu_get_channel_number(uint8_t channel)
  114. {
  115. if (channel & 0x01)
  116. {
  117. return 0;
  118. }
  119. else if (channel & 0x02)
  120. {
  121. return 1;
  122. }
  123. else if (channel & 0x04)
  124. {
  125. return 2;
  126. }
  127. else if (channel & 0x08)
  128. {
  129. return 3;
  130. }
  131. return 0;
  132. }
  133. static rt_err_t drv_pwm_get(struct mcu_pwm *pwm_handle, struct rt_pwm_configuration *configuration)
  134. {
  135. rt_uint8_t channel_number = mcu_get_channel_number(configuration->channel);
  136. uint8_t tick_pscond;
  137. tick_pscond = pwm_handle->pwm_src_clk / 1000000UL;
  138. configuration->period = pwm_handle->pwm_handle->p_registers->COUNTERTOP * 1000UL / tick_pscond;
  139. configuration->pulse = pwm_handle->pwm_handle->p_registers->SEQ[channel_number].PTR / tick_pscond;
  140. return RT_EOK;
  141. }
  142. static void nrfx_set_prioid(nrfx_pwm_t *pwm_handle, uint32_t perioid)
  143. {
  144. pwm_handle->p_registers->COUNTERTOP = perioid;
  145. }
  146. static rt_err_t drv_pwm_set(struct mcu_pwm *p_mcu, struct rt_pwm_configuration *configuration)
  147. {
  148. rt_uint32_t period, pulse;
  149. uint8_t tick_pscond;
  150. tick_pscond = p_mcu->pwm_src_clk / 1000000UL;
  151. p_mcu->pwm_handle->p_registers->COUNTERTOP = (unsigned long long)configuration->period * tick_pscond;
  152. if (configuration->channel & 0x01)
  153. {
  154. p_mcu->m_demo1_seq_values.channel_0 = configuration->pulse;
  155. }
  156. if (configuration->channel & 0x02)
  157. {
  158. p_mcu->m_demo1_seq_values.channel_1 = configuration->pulse;
  159. }
  160. if (configuration->channel & 0x04)
  161. {
  162. p_mcu->m_demo1_seq_values.channel_2 = configuration->pulse;
  163. }
  164. if (configuration->channel & 0x08)
  165. {
  166. p_mcu->m_demo1_seq_values.channel_3 = configuration->pulse;
  167. }
  168. return RT_EOK;
  169. }
  170. static rt_err_t drv_pwm_control(struct rt_device_pwm *device, int cmd, void *arg)
  171. {
  172. struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)arg;
  173. void *pwm_handle = (void *)device->parent.user_data;
  174. nrfx_pwm_t *p_handle = (nrfx_pwm_t *)pwm_handle;
  175. struct mcu_pwm *p_mcu = rt_container_of(p_handle, struct mcu_pwm, pwm_handle);
  176. switch (cmd)
  177. {
  178. case PWM_CMD_ENABLE:
  179. return drv_pwm_enable(p_mcu, configuration, RT_TRUE);
  180. case PWM_CMD_DISABLE:
  181. return drv_pwm_enable(p_mcu, configuration, RT_FALSE);
  182. case PWM_CMD_SET:
  183. return drv_pwm_set(p_mcu, configuration);
  184. case PWM_CMD_GET:
  185. return drv_pwm_get(p_mcu, configuration);
  186. default:
  187. return -RT_EINVAL;
  188. }
  189. }
  190. static rt_err_t mcu_hw_pwm_init(struct mcu_pwm *device)
  191. {
  192. #define NRFX_PWM_PIN_INVERTED 0x80
  193. #define _PRIO_APP_LOWEST 7
  194. nrfx_pwm_config_t config0 =
  195. {
  196. .irq_priority = _PRIO_APP_LOWEST,
  197. .base_clock = NRF_PWM_CLK_1MHz, //default value
  198. .count_mode = NRF_PWM_MODE_UP,
  199. .top_value = 5000, //default vaule
  200. .load_mode = NRF_PWM_LOAD_INDIVIDUAL,
  201. .step_mode = NRF_PWM_STEP_AUTO
  202. };
  203. rt_err_t result = RT_EOK;
  204. if (device->pwm_src_clk == 1000000)
  205. {
  206. config0.base_clock = NRF_PWM_CLK_1MHz;
  207. }
  208. else if (device->pwm_src_clk == 2000000)
  209. {
  210. config0.base_clock = NRF_PWM_CLK_2MHz;
  211. }
  212. else if (device->pwm_src_clk == 8000000)
  213. {
  214. config0.base_clock = NRF_PWM_CLK_8MHz;
  215. }
  216. else
  217. {
  218. config0.base_clock = NRF_PWM_CLK_1MHz;
  219. }
  220. if (device->channel & 0x01)
  221. {
  222. config0.output_pins[0] = device->channel_0_pin | NRFX_PWM_PIN_INVERTED;
  223. }
  224. if (device->channel & 0x02)
  225. {
  226. config0.output_pins[1] = device->channel_1_pin | NRFX_PWM_PIN_INVERTED;
  227. }
  228. if (device->channel & 0x04)
  229. {
  230. config0.output_pins[2] = device->channel_2_pin | NRFX_PWM_PIN_INVERTED;
  231. }
  232. if (device->channel & 0x08)
  233. {
  234. config0.output_pins[3] = device->channel_3_pin | NRFX_PWM_PIN_INVERTED;
  235. }
  236. device->m_demo1_seq.values.p_individual = &device->m_demo1_seq_values;
  237. device->m_demo1_seq.length = NRF_PWM_VALUES_LENGTH(device->m_demo1_seq_values),
  238. nrfx_pwm_init(device->pwm_handle, &config0, NULL, NULL);
  239. return result;
  240. }
  241. static void pwm_get_channel(void)
  242. {
  243. #ifdef BSP_USING_PWM0_CH0
  244. mcu_pwm_obj[PWM0_INDEX].channel |= 1 << 0;
  245. mcu_pwm_obj[PWM0_INDEX].channel_0_pin = BSP_USING_PWM0_CH0;
  246. #endif
  247. #ifdef BSP_USING_PWM0_CH1
  248. mcu_pwm_obj[PWM0_INDEX].channel |= 1 << 1;
  249. mcu_pwm_obj[PWM0_INDEX].channel_1_pin = BSP_USING_PWM0_CH1;
  250. #endif
  251. #ifdef BSP_USING_PWM0_CH2
  252. mcu_pwm_obj[PWM0_INDEX].channel |= 1 << 2;
  253. mcu_pwm_obj[PWM0_INDEX].channel_2_pin = BSP_USING_PWM0_CH2;
  254. #endif
  255. #ifdef BSP_USING_PWM0_CH3
  256. mcu_pwm_obj[PWM0_INDEX].channel |= 1 << 3;
  257. mcu_pwm_obj[PWM0_INDEX].channel_3_pin = BSP_USING_PWM0_CH3;
  258. #endif
  259. #ifdef BSP_USING_PWM1_CH0
  260. mcu_pwm_obj[PWM1_INDEX].channel |= 1 << 0;
  261. mcu_pwm_obj[PWM1_INDEX].channel_0_pin = BSP_USING_PWM1_CH0;
  262. #endif
  263. #ifdef BSP_USING_PWM1_CH1
  264. mcu_pwm_obj[PWM1_INDEX].channel |= 1 << 1;
  265. mcu_pwm_obj[PWM1_INDEX].channel_1_pin = BSP_USING_PWM1_CH1;
  266. #endif
  267. #ifdef BSP_USING_PWM1_CH2
  268. mcu_pwm_obj[PWM1_INDEX].channel |= 1 << 2;
  269. mcu_pwm_obj[PWM1_INDEX].channel_2_pin = BSP_USING_PWM1_CH2;
  270. #endif
  271. #ifdef BSP_USING_PWM1_CH3
  272. mcu_pwm_obj[PWM1_INDEX].channel |= 1 << 3;
  273. mcu_pwm_obj[PWM1_INDEX].channel_3_pin = BSP_USING_PWM1_CH3;
  274. #endif
  275. #ifdef BSP_USING_PWM2_CH0
  276. mcu_pwm_obj[PWM2_INDEX].channel |= 1 << 0;
  277. mcu_pwm_obj[PWM2_INDEX].channel_0_pin = BSP_USING_PWM2_CH0;
  278. #endif
  279. #ifdef BSP_USING_PWM2_CH1
  280. mcu_pwm_obj[PWM2_INDEX].channel |= 1 << 1;
  281. mcu_pwm_obj[PWM2_INDEX].channel_1_pin = BSP_USING_PWM2_CH1;
  282. #endif
  283. #ifdef BSP_USING_PWM2_CH2
  284. mcu_pwm_obj[PWM2_INDEX].channel |= 1 << 2;
  285. mcu_pwm_obj[PWM2_INDEX].channel_2_pin = BSP_USING_PWM2_CH2;
  286. #endif
  287. #ifdef BSP_USING_PWM2_CH3
  288. mcu_pwm_obj[PWM2_INDEX].channel |= 1 << 3;
  289. mcu_pwm_obj[PWM2_INDEX].channel_3_pin = BSP_USING_PWM2_CH3;
  290. #endif
  291. #ifdef BSP_USING_PWM3_CH0
  292. mcu_pwm_obj[PWM3_INDEX].channel |= 1 << 0;
  293. mcu_pwm_obj[PWM3_INDEX].channel_0_pin = BSP_USING_PWM3_CH0;
  294. #endif
  295. #ifdef BSP_USING_PWM3_CH1
  296. mcu_pwm_obj[PWM3_INDEX].channel |= 1 << 1;
  297. mcu_pwm_obj[PWM3_INDEX].channel_1_pin = BSP_USING_PWM3_CH1;
  298. #endif
  299. #ifdef BSP_USING_PWM3_CH2
  300. mcu_pwm_obj[PWM3_INDEX].channel |= 1 << 2;
  301. mcu_pwm_obj[PWM3_INDEX].channel_2_pin = BSP_USING_PWM3_CH2;
  302. #endif
  303. #ifdef BSP_USING_PWM3_CH3
  304. mcu_pwm_obj[PWM3_INDEX].channel |= 1 << 3;
  305. mcu_pwm_obj[PWM3_INDEX].channel_3_pin = BSP_USING_PWM3_CH3;
  306. #endif
  307. }
  308. static int mcu_pwm_init(void)
  309. {
  310. int i = 0;
  311. int result = RT_EOK;
  312. pwm_get_channel();
  313. for (i = 0; i < sizeof(mcu_pwm_obj) / sizeof(mcu_pwm_obj[0]); i++)
  314. {
  315. /* pwm init */
  316. if (mcu_hw_pwm_init(&mcu_pwm_obj[i]) != RT_EOK)
  317. {
  318. rt_kprintf("\r\n %s init failed", mcu_pwm_obj[i].name);
  319. result = -RT_ERROR;
  320. goto __exit;
  321. }
  322. else
  323. {
  324. rt_kprintf("\r\n %s init success", mcu_pwm_obj[i].name);
  325. /* register pwm device */
  326. if (rt_device_pwm_register(&mcu_pwm_obj[i].pwm_device, mcu_pwm_obj[i].name, &drv_ops, &mcu_pwm_obj[i].pwm_handle) == RT_EOK)
  327. {
  328. rt_kprintf("\r\n %s register success", mcu_pwm_obj[i].name);
  329. }
  330. else
  331. {
  332. rt_kprintf("\r\n %s register failed", mcu_pwm_obj[i].name);
  333. result = -RT_ERROR;
  334. }
  335. }
  336. }
  337. __exit:
  338. return result;
  339. }
  340. INIT_DEVICE_EXPORT(mcu_pwm_init);
  341. /* test example */
  342. #define PWM_DEV_NAME "pwm0" /* PWM name*/
  343. #define PWM_DEV_CHANNEL 15 /* PWM channel */
  344. struct rt_device_pwm *pwm_dev;
  345. static int pwm_led_sample(int argc, char *argv[])
  346. {
  347. rt_uint32_t period, pulse, dir;
  348. period = 50000; /* 50ms*/
  349. dir = 1;
  350. pulse = 0;
  351. pwm_dev = (struct rt_device_pwm *)rt_device_find(PWM_DEV_NAME);
  352. if (pwm_dev == RT_NULL)
  353. {
  354. rt_kprintf("pwm sample run failed! can't find %s device!\n", PWM_DEV_NAME);
  355. return -RT_ERROR;
  356. }
  357. rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, period, pulse);
  358. rt_pwm_enable(pwm_dev, PWM_DEV_CHANNEL);
  359. while (1)
  360. {
  361. rt_thread_mdelay(50);
  362. if (dir)
  363. {
  364. pulse += 500;
  365. }
  366. else
  367. {
  368. pulse -= 500;
  369. }
  370. if (pulse >= period)
  371. {
  372. dir = 0;
  373. }
  374. if (0 == pulse)
  375. {
  376. dir = 1;
  377. }
  378. rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, period, pulse);
  379. }
  380. }
  381. MSH_CMD_EXPORT(pwm_led_sample, pwm sample);
  382. #endif