app_pwm.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  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. /** @file
  13. *
  14. * @defgroup app_pwm Pulse-width modulation (PWM)
  15. * @{
  16. * @ingroup app_common
  17. *
  18. * @brief Module for generating a pulse-width modulated output signal.
  19. *
  20. * @details This module provides a PWM implementation using timers, GPIOTE, and PPI.
  21. *
  22. * Resource usage:
  23. * - 2 PPI channels per instance + 2 PPI channels per PWM channel.
  24. * - 1 PPI group per instance.
  25. * - 1 GPIOTE channel per PWM channel.
  26. *
  27. * For example, a PWM instance with two channels will consume 2+4 PPI channels, 1 PPI group, and 2 GPIOTE channels.
  28. *
  29. * The maximum number of PWM channels per instance is 2.
  30. */
  31. #ifndef APP_PWM_H__
  32. #define APP_PWM_H__
  33. #include <stdint.h>
  34. #include "sdk_errors.h"
  35. #include "nrf_drv_timer.h"
  36. #include "nrf_drv_common.h"
  37. #include "nrf_drv_ppi.h"
  38. #define APP_PWM_NOPIN 0xFFFFFFFF
  39. /** @brief Number of channels for one timer instance (fixed to 2 due to timer properties).*/
  40. #define APP_PWM_CHANNELS_PER_INSTANCE 2
  41. /**@brief Macro for creating a PWM instance. */
  42. #define APP_PWM_INSTANCE(name, num) \
  43. const nrf_drv_timer_t m_pwm_##name##_timer = NRF_DRV_TIMER_INSTANCE(num); \
  44. app_pwm_cb_t m_pwm_##name##_cb; \
  45. /*lint -e{545}*/ \
  46. const app_pwm_t name = { \
  47. .p_cb = &m_pwm_##name##_cb, \
  48. .p_timer = &m_pwm_##name##_timer, \
  49. }
  50. /**@brief PWM instance default configuration (1 channel). */
  51. #define APP_PWM_DEFAULT_CONFIG_1CH(period_in_us, pin) \
  52. { \
  53. .pins = {pin, APP_PWM_NOPIN}, \
  54. .pin_polarity = {APP_PWM_POLARITY_ACTIVE_LOW, APP_PWM_POLARITY_ACTIVE_LOW}, \
  55. .num_of_channels = 1, \
  56. .period_us = period_in_us \
  57. }
  58. /**@brief PWM instance default configuration (2 channels). */
  59. #define APP_PWM_DEFAULT_CONFIG_2CH(period_in_us, pin0, pin1) \
  60. { \
  61. .pins = {pin0, pin1}, \
  62. .pin_polarity = {APP_PWM_POLARITY_ACTIVE_LOW, APP_PWM_POLARITY_ACTIVE_LOW}, \
  63. .num_of_channels = 2, \
  64. .period_us = period_in_us \
  65. }
  66. typedef uint16_t app_pwm_duty_t;
  67. /**
  68. * @brief PWM callback that is executed when a PWM duty change has been completed.
  69. *
  70. * @param[in] pwm_id PWM instance ID.
  71. */
  72. typedef void (* app_pwm_callback_t)(uint32_t);
  73. /**
  74. * @brief Channel polarity.
  75. */
  76. typedef enum
  77. {
  78. APP_PWM_POLARITY_ACTIVE_LOW = 0,
  79. APP_PWM_POLARITY_ACTIVE_HIGH = 1
  80. } app_pwm_polarity_t;
  81. /**@brief PWM configuration structure used for initialization. */
  82. typedef struct
  83. {
  84. uint32_t pins[APP_PWM_CHANNELS_PER_INSTANCE]; //!< Pins configured as PWM output.
  85. app_pwm_polarity_t pin_polarity[APP_PWM_CHANNELS_PER_INSTANCE]; //!< Polarity of active state on pin.
  86. uint32_t num_of_channels; //!< Number of channels that can be used.
  87. uint32_t period_us; //!< PWM signal output period to configure (in microseconds).
  88. } app_pwm_config_t;
  89. /**
  90. * @cond (NODOX)
  91. * @defgroup app_pwm_internal Auxiliary internal types declarations
  92. * @{
  93. * @internal
  94. *
  95. * @brief Module for internal usage inside the library only
  96. *
  97. * There are some definitions that must be included in the header file because
  98. * of the way the library is set up. In this way, the are accessible to the user.
  99. * However, any functions and variables defined here may change at any time
  100. * without a warning, so you should not access them directly.
  101. */
  102. /**
  103. * @brief PWM channel instance
  104. *
  105. * This structure holds all data needed by a single PWM channel.
  106. */
  107. typedef struct
  108. {
  109. uint32_t gpio_pin; //!< Pin that is used by this PWM channel.
  110. uint32_t pulsewidth; //!< The copy of duty currently set (in ticks).
  111. nrf_ppi_channel_t ppi_channels[2]; //!< PPI channels used by the PWM channel to clear and set the output.
  112. app_pwm_polarity_t polarity; //!< The active state of the pin.
  113. uint8_t initialized; //!< The internal information if the selected channel was initialized.
  114. } app_pwm_channel_cb_t;
  115. /**
  116. * @brief Variable part of PWM instance
  117. *
  118. * This structure holds instance data that may change.
  119. */
  120. typedef struct
  121. {
  122. app_pwm_channel_cb_t channels_cb[APP_PWM_CHANNELS_PER_INSTANCE]; //!< Channels data
  123. uint32_t period; //!< Selected period in ticks
  124. app_pwm_callback_t p_ready_callback; //!< Callback function called on PWM readiness
  125. nrf_ppi_channel_t ppi_channels[2]; //!< PPI channels used temporary while changing duty
  126. nrf_ppi_channel_group_t ppi_group; //!< PPI group used to synchronize changes on channels
  127. nrf_drv_state_t state; //!< Current driver status
  128. } app_pwm_cb_t;
  129. /** @}
  130. * @endcond
  131. */
  132. /**@brief PWM instance structure. */
  133. typedef struct
  134. {
  135. app_pwm_cb_t *p_cb; //!< Pointer to control block internals.
  136. nrf_drv_timer_t const * const p_timer; //!< Timer used by this PWM instance.
  137. } app_pwm_t;
  138. /**
  139. * @brief Function for checking if the PWM instance is busy updating the duty cycle.
  140. *
  141. * @param[in] p_instance PWM instance.
  142. *
  143. * @retval True If the PWM instance is ready for duty cycle changes.
  144. * @retval False If a change operation is in progress.
  145. */
  146. bool app_pwm_busy_check(app_pwm_t const * const p_instance);
  147. /**
  148. * @brief Function for initializing a PWM instance.
  149. *
  150. * @param[in] p_instance PWM instance.
  151. * @param[in] p_config Initial configuration.
  152. * @param[in] p_ready_callback Pointer to ready callback function (or NULL to disable).
  153. *
  154. * @retval NRF_SUCCESS If initialization was successful.
  155. * @retval NRF_ERROR_NO_MEM If there were not enough free resources.
  156. * @retval NRF_ERROR_INVALID_PARAM If an invalid configuration structure was passed.
  157. * @retval NRF_ERROR_INVALID_STATE If the timer/PWM is already in use or if initialization failed.
  158. */
  159. ret_code_t app_pwm_init(app_pwm_t const * const p_instance, app_pwm_config_t const * const p_config,
  160. app_pwm_callback_t p_ready_callback);
  161. /**
  162. * @brief Function for uninitializing a PWM instance and releasing the allocated resources.
  163. *
  164. * @param[in] p_instance PWM instance.
  165. *
  166. * @retval NRF_SUCCESS If uninitialization was successful.
  167. * @retval NRF_ERROR_INVALID_STATE If the given instance was not initialized.
  168. */
  169. ret_code_t app_pwm_uninit(app_pwm_t const * const p_instance);
  170. /**
  171. * @brief Function for enabling a PWM instance after initialization.
  172. *
  173. * @param[in] p_instance PWM instance.
  174. */
  175. void app_pwm_enable(app_pwm_t const * const p_instance);
  176. /**
  177. * @brief Function for disabling a PWM instance after initialization.
  178. *
  179. * @param[in] p_instance PWM instance.
  180. */
  181. void app_pwm_disable(app_pwm_t const * const p_instance);
  182. /**
  183. * @brief Function for setting the PWM channel duty cycle in percents.
  184. *
  185. * A duty cycle change requires one full PWM clock period to finish.
  186. * If another change is attempted for any channel of given instance before
  187. * the current change is complete, the new attempt will result in the error
  188. * NRF_ERROR_BUSY.
  189. *
  190. * @param[in] p_instance PWM instance.
  191. * @param[in] channel Channel number.
  192. * @param[in] duty Duty cycle (0 - 100).
  193. *
  194. * @retval NRF_SUCCESS If the operation was successful.
  195. * @retval NRF_ERROR_BUSY If the PWM is not ready yet.
  196. * @retval NRF_ERROR_INVALID_STATE If the given instance was not initialized.
  197. *
  198. */
  199. ret_code_t app_pwm_channel_duty_set(app_pwm_t const * const p_instance,
  200. uint8_t channel, app_pwm_duty_t duty);
  201. /**
  202. * @brief Function for retrieving the PWM channel duty cycle in percents.
  203. *
  204. * @param[in] p_instance PWM instance.
  205. * @param[in] channel Channel number.
  206. *
  207. * @return Duty cycle value.
  208. */
  209. app_pwm_duty_t app_pwm_channel_duty_get(app_pwm_t const * const p_instance, uint8_t channel);
  210. /**
  211. * @name Functions accessing values in ticks
  212. *
  213. * Auxiliary functions that allow to get values in actual timer ticks.
  214. * @{
  215. */
  216. /**
  217. * @brief Function for setting PWM channel duty cycle in clock ticks.
  218. *
  219. * @note Duty cycle changes require one full PWM clock period to finish.
  220. * Until that, the next change attempt (for any channel of given instance)
  221. * will result in an NRF_ERROR_BUSY error.
  222. *
  223. * @param[in] p_instance PWM instance.
  224. * @param[in] channel Channel number.
  225. * @param[in] ticks Number of PWM clock ticks.
  226. *
  227. * @retval NRF_SUCCESS If the operation was successful.
  228. * @retval NRF_ERROR_BUSY If PWM is not ready yet.
  229. * @retval NRF_ERROR_INVALID_STATE If the given instance was not initialized.
  230. */
  231. ret_code_t app_pwm_channel_duty_ticks_set(app_pwm_t const * const p_instance,
  232. uint8_t channel,
  233. uint16_t ticks);
  234. /**
  235. * @brief Function for retrieving the PWM channel duty cycle in ticks.
  236. *
  237. * This function retrieves the real, currently set duty cycle in ticks.
  238. * For one full PWM cycle the value might be different than the value set by the last
  239. * @ref app_pwm_channel_duty_ticks_set function call.
  240. *
  241. * @param[in] p_instance PWM instance.
  242. * @param[in] channel Channel number.
  243. *
  244. * @return Number of ticks set for selected channel.
  245. *
  246. */
  247. uint16_t app_pwm_channel_duty_ticks_get(app_pwm_t const * const p_instance, uint8_t channel);
  248. /**
  249. * @brief Function for returning the number of ticks in a whole cycle.
  250. *
  251. * @param[in] p_instance PWM instance.
  252. *
  253. * @return Number of ticks that corresponds to 100% of the duty cycle.
  254. */
  255. uint16_t app_pwm_cycle_ticks_get(app_pwm_t const * const p_instance);
  256. /** @} */
  257. #endif
  258. /** @} */