app_pwm.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876
  1. /* Copyright (c) 2015 Nordic Semiconductor. All Rights Reserved.
  2. *
  3. * The information contained herein is property of Nordic Semiconductor ASA.
  4. * Terms and conditions of usage are described in detail in NORDIC
  5. * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
  6. *
  7. * Licensees are granted free, non-transferable use of the information. NO
  8. * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
  9. * the file.
  10. *
  11. */
  12. #include "app_pwm.h"
  13. #include "nrf_drv_timer.h"
  14. #include "nrf_drv_ppi.h"
  15. #include "nrf_drv_common.h"
  16. #include "nrf_drv_gpiote.h"
  17. #include "nrf_gpiote.h"
  18. #include "nrf_gpio.h"
  19. #include "app_util.h"
  20. #include "app_util_platform.h"
  21. #include "nrf_assert.h"
  22. #define APP_PWM_CHANNEL_INITIALIZED 1
  23. #define APP_PWM_CHANNEL_UNINITIALIZED 0
  24. #define APP_PWM_CHANNEL_ENABLED 1
  25. #define APP_PWM_CHANNEL_DISABLED 0
  26. #define TIMER_PRESCALER_MAX 9
  27. #define TIMER_MAX_PULSEWIDTH_US_ON_16M 4095
  28. #define APP_PWM_REQUIRED_PPI_CHANNELS_PER_INSTANCE 2
  29. #define APP_PWM_REQUIRED_PPI_CHANNELS_PER_CHANNEL 2
  30. #define UNALLOCATED 0xFFFFFFFFUL
  31. #define BUSY_STATE_CHANGING 0xFE
  32. #define BUSY_STATE_IDLE 0xFF
  33. #define PWM_MAIN_CC_CHANNEL 2
  34. #define PWM_SECONDARY_CC_CHANNEL 3
  35. #ifdef NRF52
  36. static bool m_use_ppi_delay_workaround;
  37. #endif
  38. /**
  39. * @brief PWM busy status
  40. *
  41. * Stores the number of a channel being currently updated.
  42. *
  43. */
  44. static volatile uint8_t m_pwm_busy[TIMER_COUNT];
  45. /**
  46. * @brief New duty cycle value
  47. *
  48. * When the channel duty cycle reaches this value, the update process is complete.
  49. */
  50. static volatile uint32_t m_pwm_target_value[TIMER_COUNT];
  51. /**
  52. * @brief PWM ready counter
  53. *
  54. * The value in this counter is decremented in every PWM cycle after initiating the update.
  55. * If an event handler function was specified by the user, it is being called
  56. * after two cycle events (at least one full PWM cycle).
  57. */
  58. volatile uint8_t m_pwm_ready_counter[TIMER_COUNT][APP_PWM_CHANNELS_PER_INSTANCE];
  59. /**
  60. * @brief Pointers to instances
  61. *
  62. * This array connects any active timer instance number with the pointer to the PWM instance.
  63. * It is used by the interrupt runtime.
  64. */
  65. static const app_pwm_t * m_instances[TIMER_COUNT];
  66. // Macros for getting the polarity of given instance/channel.
  67. #define POLARITY_ACTIVE(INST,CH) (( ((INST)->p_cb)->channels_cb[(CH)].polarity == \
  68. APP_PWM_POLARITY_ACTIVE_LOW)?(0):(1))
  69. #define POLARITY_INACTIVE(INST,CH) (( ((INST)->p_cb)->channels_cb[(CH)].polarity == \
  70. APP_PWM_POLARITY_ACTIVE_LOW)?(1):(0))
  71. //lint -save -e534
  72. /**
  73. * @brief Workaround for PAN-73.
  74. *
  75. * @param[in] timer Timer.
  76. * @param[in] enable Enable or disable.
  77. */
  78. static void pan73_workaround(NRF_TIMER_Type * p_timer, bool enable)
  79. {
  80. #ifdef NRF51
  81. if (p_timer == NRF_TIMER0)
  82. {
  83. *(uint32_t *)0x40008C0C = (enable ? 1 : 0);
  84. }
  85. else if (p_timer == NRF_TIMER1)
  86. {
  87. *(uint32_t *)0x40009C0C = (enable ? 1 : 0);
  88. }
  89. else if (p_timer == NRF_TIMER2)
  90. {
  91. *(uint32_t *)0x4000AC0C = (enable ? 1 : 0);
  92. }
  93. #endif
  94. return;
  95. }
  96. bool app_pwm_busy_check(app_pwm_t const * const p_instance)
  97. {
  98. uint8_t busy_state = (m_pwm_busy[p_instance->p_timer->instance_id]);
  99. bool busy = true;
  100. if (busy_state != BUSY_STATE_IDLE)
  101. {
  102. if (busy_state != BUSY_STATE_CHANGING)
  103. {
  104. if (nrf_drv_timer_capture_get(p_instance->p_timer, (nrf_timer_cc_channel_t) busy_state)
  105. == m_pwm_target_value[p_instance->p_timer->instance_id])
  106. {
  107. m_pwm_busy[p_instance->p_timer->instance_id] = BUSY_STATE_IDLE;
  108. busy = false;
  109. }
  110. }
  111. }
  112. else
  113. {
  114. busy = false;
  115. }
  116. return busy;
  117. }
  118. /**
  119. * @brief Function for enabling the IRQ for a given PWM instance.
  120. *
  121. * @param[in] p_instance PWM instance.
  122. */
  123. __STATIC_INLINE void pwm_irq_enable(app_pwm_t const * const p_instance)
  124. {
  125. nrf_drv_timer_compare_int_enable(p_instance->p_timer, PWM_MAIN_CC_CHANNEL);
  126. }
  127. /**
  128. * @brief Function for disabling the IRQ for a given PWM instance.
  129. *
  130. * @param[in] p_instance PWM instance.
  131. */
  132. __STATIC_INLINE void pwm_irq_disable(app_pwm_t const * const p_instance)
  133. {
  134. nrf_drv_timer_compare_int_disable(p_instance->p_timer, PWM_MAIN_CC_CHANNEL);
  135. }
  136. /**
  137. * @brief Function for disabling PWM channel PPI.
  138. *
  139. * @param[in] p_instance PWM instance.
  140. */
  141. __STATIC_INLINE void pwm_channel_ppi_disable(app_pwm_t const * const p_instance, uint8_t channel)
  142. {
  143. app_pwm_cb_t * p_cb = p_instance->p_cb;
  144. nrf_drv_ppi_channel_disable(p_cb->channels_cb[channel].ppi_channels[0]);
  145. nrf_drv_ppi_channel_disable(p_cb->channels_cb[channel].ppi_channels[1]);
  146. }
  147. /**
  148. * @brief Function for disabling PWM PPI.
  149. *
  150. * @param[in] p_instance PWM instance.
  151. */
  152. __STATIC_INLINE void pwm_ppi_disable(app_pwm_t const * const p_instance)
  153. {
  154. app_pwm_cb_t * p_cb = p_instance->p_cb;
  155. nrf_drv_ppi_channel_disable(p_cb->ppi_channels[0]);
  156. nrf_drv_ppi_channel_disable(p_cb->ppi_channels[1]);
  157. }
  158. /**
  159. * @brief This function is called on interrupt after duty set.
  160. *
  161. * @param[in] timer Timer used by PWM.
  162. * @param[in] timer_instance_id Timer index.
  163. */
  164. void pwm_ready_tick(nrf_timer_event_t event_type, void * p_context)
  165. {
  166. uint32_t timer_instance_id = (uint32_t)p_context;
  167. uint8_t disable = 1;
  168. for (uint8_t channel = 0; channel < APP_PWM_CHANNELS_PER_INSTANCE; ++channel)
  169. {
  170. if (m_pwm_ready_counter[timer_instance_id][channel])
  171. {
  172. --m_pwm_ready_counter[timer_instance_id][channel];
  173. if (!m_pwm_ready_counter[timer_instance_id][channel])
  174. {
  175. app_pwm_cb_t * p_cb = m_instances[timer_instance_id]->p_cb;
  176. p_cb->p_ready_callback(timer_instance_id);
  177. }
  178. else
  179. {
  180. disable = 0;
  181. }
  182. }
  183. }
  184. if (disable)
  185. {
  186. pwm_irq_disable(m_instances[timer_instance_id]);
  187. }
  188. }
  189. /**
  190. * @brief Function for resource de-allocation.
  191. *
  192. * @param[in] p_instance PWM instance.
  193. */
  194. //lint -e{650}
  195. static void pwm_dealloc(app_pwm_t const * const p_instance)
  196. {
  197. app_pwm_cb_t * p_cb = p_instance->p_cb;
  198. for (uint8_t i = 0; i < APP_PWM_REQUIRED_PPI_CHANNELS_PER_INSTANCE; ++i)
  199. {
  200. if (p_cb->ppi_channels[i] != (nrf_ppi_channel_t)(uint8_t)(UNALLOCATED))
  201. {
  202. nrf_drv_ppi_channel_free(p_cb->ppi_channels[i]);
  203. }
  204. }
  205. if (p_cb->ppi_group != (nrf_ppi_channel_group_t)UNALLOCATED)
  206. {
  207. nrf_drv_ppi_group_free(p_cb->ppi_group);
  208. }
  209. for (uint8_t ch = 0; ch < APP_PWM_CHANNELS_PER_INSTANCE; ++ch)
  210. {
  211. for (uint8_t i = 0; i < APP_PWM_REQUIRED_PPI_CHANNELS_PER_CHANNEL; ++i)
  212. {
  213. if (p_cb->channels_cb[ch].ppi_channels[i] != (nrf_ppi_channel_t)UNALLOCATED)
  214. {
  215. nrf_drv_ppi_channel_free(p_cb->channels_cb[ch].ppi_channels[i]);
  216. p_cb->channels_cb[ch].ppi_channels[i] = (nrf_ppi_channel_t)UNALLOCATED;
  217. }
  218. }
  219. if (p_cb->channels_cb[ch].gpio_pin != UNALLOCATED)
  220. {
  221. nrf_drv_gpiote_out_uninit(p_cb->channels_cb[ch].gpio_pin);
  222. p_cb->channels_cb[ch].gpio_pin = UNALLOCATED;
  223. }
  224. p_cb->channels_cb[ch].initialized = APP_PWM_CHANNEL_UNINITIALIZED;
  225. }
  226. nrf_drv_timer_uninit(p_instance->p_timer);
  227. return;
  228. }
  229. /**
  230. * @brief PWM state transition from (0%, 100%) to 0% or 100%.
  231. *
  232. * @param[in] p_instance PWM instance.
  233. * @param[in] channel PWM channel number.
  234. * @param[in] ticks Number of clock ticks.
  235. */
  236. static void pwm_transition_n_to_0or100(app_pwm_t const * const p_instance,
  237. uint8_t channel, uint16_t ticks)
  238. {
  239. app_pwm_cb_t * p_cb = p_instance->p_cb;
  240. app_pwm_channel_cb_t * p_ch_cb = &p_cb->channels_cb[channel];
  241. nrf_ppi_channel_group_t p_ppigrp = p_cb->ppi_group;
  242. pwm_ppi_disable(p_instance);
  243. nrf_drv_ppi_group_clear(p_ppigrp);
  244. nrf_drv_ppi_channels_include_in_group(
  245. nrf_drv_ppi_channel_to_mask(p_ch_cb->ppi_channels[0]) |
  246. nrf_drv_ppi_channel_to_mask(p_ch_cb->ppi_channels[1]),
  247. p_ppigrp);
  248. if (!ticks)
  249. {
  250. nrf_drv_ppi_channel_assign(p_cb->ppi_channels[0],
  251. nrf_drv_timer_compare_event_address_get(p_instance->p_timer, channel),
  252. nrf_drv_ppi_task_addr_group_disable_get(p_ppigrp));
  253. nrf_drv_timer_compare(p_instance->p_timer, (nrf_timer_cc_channel_t) PWM_SECONDARY_CC_CHANNEL, 0, false);
  254. m_pwm_target_value[p_instance->p_timer->instance_id] =
  255. nrf_drv_timer_capture_get(p_instance->p_timer, (nrf_timer_cc_channel_t) channel);
  256. nrf_drv_ppi_channel_assign(p_cb->ppi_channels[1],
  257. nrf_drv_timer_compare_event_address_get(p_instance->p_timer, channel),
  258. nrf_drv_timer_capture_task_address_get(p_instance->p_timer, PWM_SECONDARY_CC_CHANNEL));
  259. }
  260. else
  261. {
  262. ticks = p_cb->period;
  263. nrf_drv_ppi_channel_assign(p_cb->ppi_channels[0],
  264. nrf_drv_timer_compare_event_address_get(p_instance->p_timer, PWM_MAIN_CC_CHANNEL),
  265. nrf_drv_ppi_task_addr_group_disable_get(p_ppigrp));
  266. // Set secondary CC channel to non-zero value:
  267. nrf_drv_timer_compare(p_instance->p_timer, (nrf_timer_cc_channel_t) PWM_SECONDARY_CC_CHANNEL, 1, false);
  268. m_pwm_target_value[p_instance->p_timer->instance_id] = 0;
  269. // The captured value will be equal to 0, because timer clear on main PWM CC channel compare is enabled.
  270. nrf_drv_ppi_channel_assign(p_cb->ppi_channels[1],
  271. nrf_drv_timer_compare_event_address_get(p_instance->p_timer, PWM_MAIN_CC_CHANNEL),
  272. nrf_drv_timer_capture_task_address_get(p_instance->p_timer, PWM_SECONDARY_CC_CHANNEL));
  273. }
  274. nrf_drv_ppi_channel_enable(p_cb->ppi_channels[0]);
  275. nrf_drv_ppi_channel_enable(p_cb->ppi_channels[1]);
  276. p_ch_cb->pulsewidth = ticks;
  277. m_pwm_busy[p_instance->p_timer->instance_id] = PWM_SECONDARY_CC_CHANNEL;
  278. }
  279. /**
  280. * @brief PWM state transition from (0%, 100%) to (0%, 100%).
  281. *
  282. * @param[in] p_instance PWM instance.
  283. * @param[in] channel PWM channel number.
  284. * @param[in] ticks Number of clock ticks.
  285. */
  286. static void pwm_transition_n_to_m(app_pwm_t const * const p_instance,
  287. uint8_t channel, uint16_t ticks)
  288. {
  289. app_pwm_cb_t * p_cb = p_instance->p_cb;
  290. app_pwm_channel_cb_t * p_ch_cb = &p_cb->channels_cb[channel];
  291. nrf_ppi_channel_group_t p_ppigrp = p_cb->ppi_group;
  292. pwm_ppi_disable(p_instance);
  293. nrf_drv_ppi_group_clear(p_ppigrp);
  294. nrf_drv_ppi_channels_include_in_group(
  295. nrf_drv_ppi_channel_to_mask(p_cb->ppi_channels[0]) |
  296. nrf_drv_ppi_channel_to_mask(p_cb->ppi_channels[1]),
  297. p_ppigrp);
  298. nrf_drv_ppi_channel_assign(p_cb->ppi_channels[0],
  299. nrf_drv_timer_compare_event_address_get(p_instance->p_timer, PWM_SECONDARY_CC_CHANNEL),
  300. nrf_drv_timer_capture_task_address_get(p_instance->p_timer, channel));
  301. #ifdef NRF52
  302. if (ticks + ((nrf_timer_frequency_get(p_instance->p_timer->p_reg) ==
  303. (m_use_ppi_delay_workaround ? NRF_TIMER_FREQ_8MHz : NRF_TIMER_FREQ_16MHz) ) ? 1 : 0)
  304. < p_ch_cb->pulsewidth)
  305. #else
  306. if (ticks + ((nrf_timer_frequency_get(p_instance->p_timer->p_reg) == NRF_TIMER_FREQ_16MHz) ? 1 : 0)
  307. < p_ch_cb->pulsewidth)
  308. #endif
  309. {
  310. // For lower value, we need one more transition. Timer task delay is included.
  311. // If prescaler is disabled, one tick must be added because of 1 PCLK16M clock cycle delay.
  312. nrf_drv_ppi_channel_assign(p_cb->ppi_channels[1],
  313. nrf_drv_timer_compare_event_address_get(p_instance->p_timer, PWM_SECONDARY_CC_CHANNEL),
  314. nrf_drv_gpiote_out_task_addr_get(p_ch_cb->gpio_pin));
  315. }
  316. else
  317. {
  318. nrf_drv_ppi_channel_remove_from_group(p_cb->ppi_channels[1], p_ppigrp);
  319. }
  320. p_ch_cb->pulsewidth = ticks;
  321. nrf_drv_timer_compare(p_instance->p_timer, (nrf_timer_cc_channel_t) PWM_SECONDARY_CC_CHANNEL, ticks, false);
  322. nrf_drv_ppi_group_enable(p_ppigrp);
  323. m_pwm_target_value[p_instance->p_timer->instance_id] = ticks;
  324. m_pwm_busy[p_instance->p_timer->instance_id] = channel;
  325. }
  326. /**
  327. * @brief PWM state transition from 0% or 100% to (0%, 100%).
  328. *
  329. * @param[in] p_instance PWM instance.
  330. * @param[in] channel PWM channel number.
  331. * @param[in] ticks Number of clock ticks.
  332. */
  333. static void pwm_transition_0or100_to_n(app_pwm_t const * const p_instance,
  334. uint8_t channel, uint16_t ticks)
  335. {
  336. app_pwm_cb_t * p_cb = p_instance->p_cb;
  337. app_pwm_channel_cb_t * p_ch_cb = &p_cb->channels_cb[channel];
  338. nrf_ppi_channel_group_t p_ppigrp = p_cb->ppi_group;
  339. nrf_timer_cc_channel_t pwm_ch_cc = (nrf_timer_cc_channel_t)(channel);
  340. pwm_ppi_disable(p_instance);
  341. pwm_channel_ppi_disable(p_instance, channel);
  342. nrf_drv_timer_compare(p_instance->p_timer, pwm_ch_cc, ticks, false);
  343. nrf_drv_ppi_group_clear(p_ppigrp);
  344. nrf_drv_ppi_channels_include_in_group(
  345. nrf_drv_ppi_channel_to_mask(p_ch_cb->ppi_channels[0])|
  346. nrf_drv_ppi_channel_to_mask(p_ch_cb->ppi_channels[1]),
  347. p_ppigrp);
  348. if (!p_ch_cb->pulsewidth)
  349. {
  350. // Channel is at 0%.
  351. nrf_drv_ppi_channel_assign(p_cb->ppi_channels[0],
  352. nrf_drv_timer_compare_event_address_get(p_instance->p_timer, channel),
  353. nrf_drv_ppi_task_addr_group_enable_get(p_ppigrp));
  354. nrf_drv_timer_compare(p_instance->p_timer, (nrf_timer_cc_channel_t) PWM_SECONDARY_CC_CHANNEL, 0, false);
  355. m_pwm_target_value[p_instance->p_timer->instance_id] =
  356. nrf_drv_timer_capture_get(p_instance->p_timer, (nrf_timer_cc_channel_t) channel);
  357. nrf_drv_ppi_channel_assign(p_cb->ppi_channels[1],
  358. nrf_drv_timer_compare_event_address_get(p_instance->p_timer, channel),
  359. nrf_drv_timer_capture_task_address_get(p_instance->p_timer, PWM_SECONDARY_CC_CHANNEL));
  360. }
  361. else
  362. {
  363. // Channel is at 100%.
  364. nrf_drv_ppi_channel_assign(p_cb->ppi_channels[0],
  365. nrf_drv_timer_compare_event_address_get(p_instance->p_timer, PWM_MAIN_CC_CHANNEL),
  366. nrf_drv_ppi_task_addr_group_enable_get(p_ppigrp));
  367. // Set secondary CC channel to non-zero value:
  368. nrf_drv_timer_compare(p_instance->p_timer, (nrf_timer_cc_channel_t) PWM_SECONDARY_CC_CHANNEL, 1, false);
  369. m_pwm_target_value[p_instance->p_timer->instance_id] = 0;
  370. // The captured value will be equal to 0, because timer clear on main PWM CC channel compare is enabled.
  371. nrf_drv_ppi_channel_assign(p_cb->ppi_channels[1],
  372. nrf_drv_timer_compare_event_address_get(p_instance->p_timer, PWM_MAIN_CC_CHANNEL),
  373. nrf_drv_timer_capture_task_address_get(p_instance->p_timer, PWM_SECONDARY_CC_CHANNEL));
  374. }
  375. nrf_drv_ppi_channel_enable(p_cb->ppi_channels[0]);
  376. nrf_drv_ppi_channel_enable(p_cb->ppi_channels[1]);
  377. p_ch_cb->pulsewidth = ticks;
  378. m_pwm_busy[p_instance->p_timer->instance_id] = PWM_SECONDARY_CC_CHANNEL;
  379. }
  380. /**
  381. * @brief PWM state transition from 0% or 100% to 0% or 100%.
  382. *
  383. * @param[in] p_instance PWM instance.
  384. * @param[in] channel PWM channel number.
  385. * @param[in] ticks Number of clock ticks.
  386. */
  387. static void pwm_transition_0or100_to_0or100(app_pwm_t const * const p_instance,
  388. uint8_t channel, uint16_t ticks)
  389. {
  390. app_pwm_cb_t * p_cb = p_instance->p_cb;
  391. app_pwm_channel_cb_t * p_ch_cb = &p_cb->channels_cb[channel];
  392. nrf_timer_cc_channel_t pwm_ch_cc = (nrf_timer_cc_channel_t)(channel);
  393. pwm_ppi_disable(p_instance);
  394. pwm_channel_ppi_disable(p_instance, channel);
  395. if (!ticks)
  396. {
  397. // Set to 0%.
  398. nrf_drv_gpiote_out_task_force(p_ch_cb->gpio_pin, POLARITY_INACTIVE(p_instance, channel));
  399. }
  400. else if (ticks >= p_cb->period)
  401. {
  402. // Set to 100%.
  403. ticks = p_cb->period;
  404. nrf_drv_gpiote_out_task_force(p_ch_cb->gpio_pin, POLARITY_ACTIVE(p_instance, channel));
  405. }
  406. nrf_drv_timer_compare(p_instance->p_timer, pwm_ch_cc, ticks, false);
  407. p_ch_cb->pulsewidth = ticks;
  408. m_pwm_busy[p_instance->p_timer->instance_id] = BUSY_STATE_IDLE;
  409. return;
  410. }
  411. ret_code_t app_pwm_channel_duty_ticks_set(app_pwm_t const * const p_instance,
  412. uint8_t channel,
  413. uint16_t ticks)
  414. {
  415. app_pwm_cb_t * p_cb = p_instance->p_cb;
  416. app_pwm_channel_cb_t * p_ch_cb = &p_cb->channels_cb[channel];
  417. ASSERT(channel < APP_PWM_CHANNELS_PER_INSTANCE);
  418. ASSERT(p_ch_cb->initialized == APP_PWM_CHANNEL_INITIALIZED);
  419. if (p_cb->state != NRF_DRV_STATE_POWERED_ON)
  420. {
  421. return NRF_ERROR_INVALID_STATE;
  422. }
  423. if (ticks == p_ch_cb->pulsewidth)
  424. {
  425. if (p_cb->p_ready_callback)
  426. {
  427. p_cb->p_ready_callback(p_instance->p_timer->instance_id);
  428. }
  429. return NRF_SUCCESS; // No action required.
  430. }
  431. if (app_pwm_busy_check(p_instance))
  432. {
  433. return NRF_ERROR_BUSY; // PPI channels for synchronization are still in use.
  434. }
  435. m_pwm_busy[p_instance->p_timer->instance_id] = BUSY_STATE_CHANGING;
  436. // Pulse width change sequence:
  437. if (!p_ch_cb->pulsewidth || p_ch_cb->pulsewidth >= p_cb->period)
  438. {
  439. // Channel is disabled (0%) or at 100%.
  440. if (!ticks || ticks >= p_cb->period)
  441. {
  442. // Set to 0 or 100%.
  443. pwm_transition_0or100_to_0or100(p_instance, channel, ticks);
  444. }
  445. else
  446. {
  447. // Other value.
  448. pwm_transition_0or100_to_n(p_instance, channel, ticks);
  449. }
  450. }
  451. else
  452. {
  453. // Channel is at other value.
  454. if (!ticks || ticks >= p_cb->period)
  455. {
  456. // Disable channel (set to 0%) or set to 100%.
  457. pwm_transition_n_to_0or100(p_instance, channel, ticks);
  458. }
  459. else
  460. {
  461. // Set to any other value.
  462. pwm_transition_n_to_m(p_instance, channel, ticks);
  463. }
  464. }
  465. if (p_instance->p_cb->p_ready_callback)
  466. {
  467. //PWM ready interrupt handler will be called after one full period.
  468. m_pwm_ready_counter[p_instance->p_timer->instance_id][channel] = 2;
  469. pwm_irq_enable(p_instance);
  470. }
  471. return NRF_SUCCESS;
  472. }
  473. uint16_t app_pwm_channel_duty_ticks_get(app_pwm_t const * const p_instance, uint8_t channel)
  474. {
  475. app_pwm_cb_t * p_cb = p_instance->p_cb;
  476. app_pwm_channel_cb_t * p_ch_cb = &p_cb->channels_cb[channel];
  477. return p_ch_cb->pulsewidth;
  478. }
  479. uint16_t app_pwm_cycle_ticks_get(app_pwm_t const * const p_instance)
  480. {
  481. app_pwm_cb_t * p_cb = p_instance->p_cb;
  482. return (uint16_t)p_cb->period;
  483. }
  484. ret_code_t app_pwm_channel_duty_set(app_pwm_t const * const p_instance,
  485. uint8_t channel, app_pwm_duty_t duty)
  486. {
  487. uint32_t ticks = ((uint32_t)app_pwm_cycle_ticks_get(p_instance) * (uint32_t)duty) / 100UL;
  488. return app_pwm_channel_duty_ticks_set(p_instance, channel, ticks);
  489. }
  490. app_pwm_duty_t app_pwm_channel_duty_get(app_pwm_t const * const p_instance, uint8_t channel)
  491. {
  492. uint32_t value = ((uint32_t)app_pwm_channel_duty_ticks_get(p_instance, channel) * 100UL) \
  493. / (uint32_t)app_pwm_cycle_ticks_get(p_instance);
  494. return (app_pwm_duty_t)value;
  495. }
  496. /**
  497. * @brief Function for initializing the PWM channel.
  498. *
  499. * @param[in] p_instance PWM instance.
  500. * @param[in] channel Channel number.
  501. * @param[in] pin GPIO pin number.
  502. *
  503. * @retval NRF_SUCCESS If initialization was successful.
  504. * @retval NRF_ERROR_NO_MEM If there were not enough free resources.
  505. * @retval NRF_ERROR_INVALID_STATE If the timer is already in use or initialization failed.
  506. */
  507. static ret_code_t app_pwm_channel_init(app_pwm_t const * const p_instance, uint8_t channel,
  508. uint32_t pin, app_pwm_polarity_t polarity)
  509. {
  510. ASSERT(channel < APP_PWM_CHANNELS_PER_INSTANCE);
  511. app_pwm_cb_t * p_cb = p_instance->p_cb;
  512. app_pwm_channel_cb_t * p_channel_cb = &p_cb->channels_cb[channel];
  513. if (p_cb->state != NRF_DRV_STATE_UNINITIALIZED)
  514. {
  515. return NRF_ERROR_INVALID_STATE;
  516. }
  517. p_channel_cb->pulsewidth = 0;
  518. p_channel_cb->polarity = polarity;
  519. ret_code_t err_code;
  520. /* GPIOTE setup: */
  521. nrf_drv_gpiote_out_config_t out_cfg = GPIOTE_CONFIG_OUT_TASK_TOGGLE( POLARITY_INACTIVE(p_instance, channel) );
  522. err_code = nrf_drv_gpiote_out_init((nrf_drv_gpiote_pin_t)pin,&out_cfg);
  523. if (err_code != NRF_SUCCESS)
  524. {
  525. return NRF_ERROR_NO_MEM;
  526. }
  527. p_cb->channels_cb[channel].gpio_pin = pin;
  528. // Set output to inactive state.
  529. if (polarity)
  530. {
  531. nrf_gpio_pin_clear(pin);
  532. }
  533. else
  534. {
  535. nrf_gpio_pin_set(pin);
  536. }
  537. /* PPI setup: */
  538. for (uint8_t i = 0; i < APP_PWM_REQUIRED_PPI_CHANNELS_PER_CHANNEL; ++i)
  539. {
  540. if (nrf_drv_ppi_channel_alloc(&p_channel_cb->ppi_channels[i]) != NRF_SUCCESS)
  541. {
  542. return NRF_ERROR_NO_MEM; // Resource de-allocation is done by callee.
  543. }
  544. }
  545. nrf_drv_ppi_channel_disable(p_channel_cb->ppi_channels[0]);
  546. nrf_drv_ppi_channel_disable(p_channel_cb->ppi_channels[1]);
  547. nrf_drv_ppi_channel_assign(p_channel_cb->ppi_channels[0],
  548. nrf_drv_timer_compare_event_address_get(p_instance->p_timer, channel),
  549. nrf_drv_gpiote_out_task_addr_get(p_channel_cb->gpio_pin));
  550. nrf_drv_ppi_channel_assign(p_channel_cb->ppi_channels[1],
  551. nrf_drv_timer_compare_event_address_get(p_instance->p_timer, PWM_MAIN_CC_CHANNEL),
  552. nrf_drv_gpiote_out_task_addr_get(p_channel_cb->gpio_pin));
  553. p_channel_cb->initialized = APP_PWM_CHANNEL_INITIALIZED;
  554. m_pwm_ready_counter[p_instance->p_timer->instance_id][channel] = 0;
  555. return NRF_SUCCESS;
  556. }
  557. /**
  558. * @brief Function for calculating target timer frequency, which will allow to set given period length.
  559. *
  560. * @param[in] period_us Desired period in microseconds.
  561. *
  562. * @retval Timer frequency.
  563. */
  564. __STATIC_INLINE nrf_timer_frequency_t pwm_calculate_timer_frequency(uint32_t period_us)
  565. {
  566. uint32_t f = (uint32_t) NRF_TIMER_FREQ_16MHz;
  567. uint32_t min = (uint32_t) NRF_TIMER_FREQ_31250Hz;
  568. while ((period_us > TIMER_MAX_PULSEWIDTH_US_ON_16M) && (f < min))
  569. {
  570. period_us >>= 1;
  571. ++f;
  572. }
  573. #ifdef NRF52
  574. if ((m_use_ppi_delay_workaround) && (f == (uint32_t) NRF_TIMER_FREQ_16MHz))
  575. {
  576. f = (uint32_t) NRF_TIMER_FREQ_8MHz;
  577. }
  578. #endif
  579. return (nrf_timer_frequency_t) f;
  580. }
  581. ret_code_t app_pwm_init(app_pwm_t const * const p_instance, app_pwm_config_t const * const p_config,
  582. app_pwm_callback_t p_ready_callback)
  583. {
  584. ASSERT(p_instance);
  585. if (!p_config)
  586. {
  587. return NRF_ERROR_INVALID_DATA;
  588. }
  589. app_pwm_cb_t * p_cb = p_instance->p_cb;
  590. if (p_cb->state != NRF_DRV_STATE_UNINITIALIZED)
  591. {
  592. return NRF_ERROR_INVALID_STATE;
  593. }
  594. uint32_t err_code = nrf_drv_ppi_init();
  595. if ((err_code != NRF_SUCCESS) && (err_code != MODULE_ALREADY_INITIALIZED))
  596. {
  597. return NRF_ERROR_NO_MEM;
  598. }
  599. if (!nrf_drv_gpiote_is_init())
  600. {
  601. err_code = nrf_drv_gpiote_init();
  602. if (err_code != NRF_SUCCESS)
  603. {
  604. return NRF_ERROR_INTERNAL;
  605. }
  606. }
  607. #ifdef NRF52
  608. if (((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x30)
  609. {
  610. m_use_ppi_delay_workaround = false;
  611. }
  612. else
  613. {
  614. m_use_ppi_delay_workaround = true;
  615. }
  616. #endif
  617. // Innitialize resource status:
  618. p_cb->ppi_channels[0] = (nrf_ppi_channel_t)UNALLOCATED;
  619. p_cb->ppi_channels[1] = (nrf_ppi_channel_t)UNALLOCATED;
  620. p_cb->ppi_group = (nrf_ppi_channel_group_t)UNALLOCATED;
  621. for (uint8_t i = 0; i < APP_PWM_CHANNELS_PER_INSTANCE; ++i)
  622. {
  623. p_cb->channels_cb[i].initialized = APP_PWM_CHANNEL_UNINITIALIZED;
  624. p_cb->channels_cb[i].ppi_channels[0] = (nrf_ppi_channel_t)UNALLOCATED;
  625. p_cb->channels_cb[i].ppi_channels[1] = (nrf_ppi_channel_t)UNALLOCATED;
  626. p_cb->channels_cb[i].gpio_pin = UNALLOCATED;
  627. }
  628. // Allocate PPI channels and groups:
  629. for (uint8_t i = 0; i < APP_PWM_REQUIRED_PPI_CHANNELS_PER_INSTANCE; ++i)
  630. {
  631. if (nrf_drv_ppi_channel_alloc(&p_cb->ppi_channels[i]) != NRF_SUCCESS)
  632. {
  633. pwm_dealloc(p_instance);
  634. return NRF_ERROR_NO_MEM;
  635. }
  636. }
  637. if (nrf_drv_ppi_group_alloc(&p_cb->ppi_group) != NRF_SUCCESS)
  638. {
  639. pwm_dealloc(p_instance);
  640. return NRF_ERROR_NO_MEM;
  641. }
  642. // Initialize channels:
  643. for (uint8_t i = 0; i < APP_PWM_CHANNELS_PER_INSTANCE; ++i)
  644. {
  645. if (p_config->pins[i] != APP_PWM_NOPIN)
  646. {
  647. err_code = app_pwm_channel_init(p_instance, i, p_config->pins[i], p_config->pin_polarity[i]);
  648. if (err_code != NRF_SUCCESS)
  649. {
  650. pwm_dealloc(p_instance);
  651. return err_code;
  652. }
  653. app_pwm_channel_duty_ticks_set(p_instance, i, 0);
  654. }
  655. }
  656. // Initialize timer:
  657. nrf_timer_frequency_t timer_freq = pwm_calculate_timer_frequency(p_config->period_us);
  658. nrf_drv_timer_config_t timer_cfg = {
  659. .frequency = timer_freq,
  660. .mode = NRF_TIMER_MODE_TIMER,
  661. .bit_width = NRF_TIMER_BIT_WIDTH_16,
  662. .interrupt_priority = APP_IRQ_PRIORITY_LOW,
  663. .p_context = (void *) (uint32_t) p_instance->p_timer->instance_id
  664. };
  665. err_code = nrf_drv_timer_init(p_instance->p_timer, &timer_cfg,
  666. pwm_ready_tick);
  667. if (err_code != NRF_SUCCESS)
  668. {
  669. pwm_dealloc(p_instance);
  670. return err_code;
  671. }
  672. uint32_t ticks = nrf_drv_timer_us_to_ticks(p_instance->p_timer, p_config->period_us);
  673. p_cb->period = ticks;
  674. nrf_drv_timer_clear(p_instance->p_timer);
  675. nrf_drv_timer_extended_compare(p_instance->p_timer, (nrf_timer_cc_channel_t) PWM_MAIN_CC_CHANNEL,
  676. ticks, NRF_TIMER_SHORT_COMPARE2_CLEAR_MASK, true);
  677. nrf_drv_timer_compare_int_disable(p_instance->p_timer, PWM_MAIN_CC_CHANNEL);
  678. p_cb->p_ready_callback = p_ready_callback;
  679. m_instances[p_instance->p_timer->instance_id] = p_instance;
  680. m_pwm_busy[p_instance->p_timer->instance_id] = BUSY_STATE_IDLE;
  681. p_cb->state = NRF_DRV_STATE_INITIALIZED;
  682. return NRF_SUCCESS;
  683. }
  684. void app_pwm_enable(app_pwm_t const * const p_instance)
  685. {
  686. app_pwm_cb_t * p_cb = p_instance->p_cb;
  687. ASSERT(p_cb->state != NRF_DRV_STATE_UNINITIALIZED);
  688. for (uint32_t channel = 0; channel < APP_PWM_CHANNELS_PER_INSTANCE; ++channel)
  689. {
  690. app_pwm_channel_cb_t * p_ch_cb = &p_cb->channels_cb[channel];
  691. m_pwm_ready_counter[p_instance->p_timer->instance_id][channel] = 0;
  692. if (p_ch_cb->initialized)
  693. {
  694. nrf_drv_gpiote_out_task_force(p_ch_cb->gpio_pin, POLARITY_INACTIVE(p_instance, channel));
  695. nrf_drv_gpiote_out_task_enable(p_ch_cb->gpio_pin);
  696. p_ch_cb->pulsewidth = 0;
  697. }
  698. }
  699. m_pwm_busy[p_instance->p_timer->instance_id] = BUSY_STATE_IDLE;
  700. pan73_workaround(p_instance->p_timer->p_reg, true);
  701. nrf_drv_timer_clear(p_instance->p_timer);
  702. nrf_drv_timer_enable(p_instance->p_timer);
  703. p_cb->state = NRF_DRV_STATE_POWERED_ON;
  704. return;
  705. }
  706. void app_pwm_disable(app_pwm_t const * const p_instance)
  707. {
  708. app_pwm_cb_t * p_cb = p_instance->p_cb;
  709. ASSERT(p_cb->state != NRF_DRV_STATE_UNINITIALIZED);
  710. nrf_drv_timer_disable(p_instance->p_timer);
  711. pwm_irq_disable(p_instance);
  712. for (uint8_t ppi_channel = 0; ppi_channel < APP_PWM_REQUIRED_PPI_CHANNELS_PER_INSTANCE; ++ppi_channel)
  713. {
  714. nrf_drv_ppi_channel_disable(p_cb->ppi_channels[ppi_channel]);
  715. }
  716. for (uint8_t channel = 0; channel < APP_PWM_CHANNELS_PER_INSTANCE; ++channel)
  717. {
  718. app_pwm_channel_cb_t * p_ch_cb = &p_cb->channels_cb[channel];
  719. if (p_ch_cb->initialized)
  720. {
  721. uint8_t polarity = POLARITY_INACTIVE(p_instance, channel);
  722. if (polarity)
  723. {
  724. nrf_gpio_pin_set(p_ch_cb->gpio_pin);
  725. }
  726. else
  727. {
  728. nrf_gpio_pin_clear(p_ch_cb->gpio_pin);
  729. }
  730. nrf_drv_gpiote_out_task_disable(p_ch_cb->gpio_pin);
  731. nrf_drv_ppi_channel_disable(p_ch_cb->ppi_channels[0]);
  732. nrf_drv_ppi_channel_disable(p_ch_cb->ppi_channels[1]);
  733. }
  734. }
  735. pan73_workaround(p_instance->p_timer->p_reg, false);
  736. p_cb->state = NRF_DRV_STATE_INITIALIZED;
  737. return;
  738. }
  739. ret_code_t app_pwm_uninit(app_pwm_t const * const p_instance)
  740. {
  741. app_pwm_cb_t * p_cb = p_instance->p_cb;
  742. if (p_cb->state == NRF_DRV_STATE_POWERED_ON)
  743. {
  744. app_pwm_disable(p_instance);
  745. }
  746. else if (p_cb->state == NRF_DRV_STATE_UNINITIALIZED)
  747. {
  748. return NRF_ERROR_INVALID_STATE;
  749. }
  750. pwm_dealloc(p_instance);
  751. p_cb->state = NRF_DRV_STATE_UNINITIALIZED;
  752. return NRF_SUCCESS;
  753. }
  754. //lint -restore