pcnt.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. #ifndef __PCNT_H__
  2. #define __PCNT_H__
  3. #include <esp_types.h>
  4. #include "esp_intr_alloc.h"
  5. #include "esp_err.h"
  6. #include "freertos/FreeRTOS.h"
  7. #include "freertos/semphr.h"
  8. #include "freertos/xtensa_api.h"
  9. #include "soc/soc.h"
  10. #include "soc/pcnt_periph.h"
  11. #include "driver/gpio.h"
  12. #ifdef __cplusplus
  13. extern "C" {
  14. #endif
  15. #define PCNT_PIN_NOT_USED (-1) /*!< When selected for a pin, this pin will not be used */
  16. /**
  17. * @brief Selection of available modes that determine the counter's action depending on the state of the control signal's input GPIO
  18. * @note Configuration covers two actions, one for high, and one for low level on the control input
  19. */
  20. typedef enum {
  21. PCNT_MODE_KEEP = 0, /*!< Control mode: won't change counter mode*/
  22. PCNT_MODE_REVERSE = 1, /*!< Control mode: invert counter mode(increase -> decrease, decrease -> increase) */
  23. PCNT_MODE_DISABLE = 2, /*!< Control mode: Inhibit counter(counter value will not change in this condition) */
  24. PCNT_MODE_MAX
  25. } pcnt_ctrl_mode_t;
  26. /**
  27. * @brief Selection of available modes that determine the counter's action on the edge of the pulse signal's input GPIO
  28. * @note Configuration covers two actions, one for positive, and one for negative edge on the pulse input
  29. */
  30. typedef enum {
  31. PCNT_COUNT_DIS = 0, /*!< Counter mode: Inhibit counter(counter value will not change in this condition) */
  32. PCNT_COUNT_INC = 1, /*!< Counter mode: Increase counter value */
  33. PCNT_COUNT_DEC = 2, /*!< Counter mode: Decrease counter value */
  34. PCNT_COUNT_MAX
  35. } pcnt_count_mode_t;
  36. /**
  37. * @brief Selection of all available PCNT units
  38. */
  39. typedef enum {
  40. PCNT_UNIT_0 = 0, /*!< PCNT unit 0 */
  41. PCNT_UNIT_1 = 1, /*!< PCNT unit 1 */
  42. PCNT_UNIT_2 = 2, /*!< PCNT unit 2 */
  43. PCNT_UNIT_3 = 3, /*!< PCNT unit 3 */
  44. PCNT_UNIT_4 = 4, /*!< PCNT unit 4 */
  45. PCNT_UNIT_5 = 5, /*!< PCNT unit 5 */
  46. PCNT_UNIT_6 = 6, /*!< PCNT unit 6 */
  47. PCNT_UNIT_7 = 7, /*!< PCNT unit 7 */
  48. PCNT_UNIT_MAX,
  49. } pcnt_unit_t;
  50. /**
  51. * @brief Selection of channels available for a single PCNT unit
  52. */
  53. typedef enum {
  54. PCNT_CHANNEL_0 = 0x00, /*!< PCNT channel 0 */
  55. PCNT_CHANNEL_1 = 0x01, /*!< PCNT channel 1 */
  56. PCNT_CHANNEL_MAX,
  57. } pcnt_channel_t;
  58. /**
  59. * @brief Selection of counter's events the may trigger an interrupt
  60. */
  61. typedef enum {
  62. PCNT_EVT_L_LIM = 0, /*!< PCNT watch point event: Minimum counter value */
  63. PCNT_EVT_H_LIM = 1, /*!< PCNT watch point event: Maximum counter value */
  64. PCNT_EVT_THRES_0 = 2, /*!< PCNT watch point event: threshold0 value event */
  65. PCNT_EVT_THRES_1 = 3, /*!< PCNT watch point event: threshold1 value event */
  66. PCNT_EVT_ZERO = 4, /*!< PCNT watch point event: counter value zero event */
  67. PCNT_EVT_MAX
  68. } pcnt_evt_type_t;
  69. /**
  70. * @brief Pulse Counter configuration for a single channel
  71. */
  72. typedef struct {
  73. int pulse_gpio_num; /*!< Pulse input GPIO number, if you want to use GPIO16, enter pulse_gpio_num = 16, a negative value will be ignored */
  74. int ctrl_gpio_num; /*!< Control signal input GPIO number, a negative value will be ignored */
  75. pcnt_ctrl_mode_t lctrl_mode; /*!< PCNT low control mode */
  76. pcnt_ctrl_mode_t hctrl_mode; /*!< PCNT high control mode */
  77. pcnt_count_mode_t pos_mode; /*!< PCNT positive edge count mode */
  78. pcnt_count_mode_t neg_mode; /*!< PCNT negative edge count mode */
  79. int16_t counter_h_lim; /*!< Maximum counter value */
  80. int16_t counter_l_lim; /*!< Minimum counter value */
  81. pcnt_unit_t unit; /*!< PCNT unit number */
  82. pcnt_channel_t channel; /*!< the PCNT channel */
  83. } pcnt_config_t;
  84. typedef intr_handle_t pcnt_isr_handle_t;
  85. /**
  86. * @brief Configure Pulse Counter unit
  87. * @note
  88. * This function will disable three events: PCNT_EVT_L_LIM, PCNT_EVT_H_LIM, PCNT_EVT_ZERO.
  89. *
  90. * @param pcnt_config Pointer of Pulse Counter unit configure parameter
  91. *
  92. * @return
  93. * - ESP_OK Success
  94. * - ESP_ERR_INVALID_ARG Parameter error
  95. */
  96. esp_err_t pcnt_unit_config(const pcnt_config_t *pcnt_config);
  97. /**
  98. * @brief Get pulse counter value
  99. *
  100. * @param pcnt_unit Pulse Counter unit number
  101. * @param count Pointer to accept counter value
  102. *
  103. * @return
  104. * - ESP_OK Success
  105. * - ESP_ERR_INVALID_ARG Parameter error
  106. */
  107. esp_err_t pcnt_get_counter_value(pcnt_unit_t pcnt_unit, int16_t* count);
  108. /**
  109. * @brief Pause PCNT counter of PCNT unit
  110. *
  111. * @param pcnt_unit PCNT unit number
  112. *
  113. * @return
  114. * - ESP_OK Success
  115. * - ESP_ERR_INVALID_ARG Parameter error
  116. */
  117. esp_err_t pcnt_counter_pause(pcnt_unit_t pcnt_unit);
  118. /**
  119. * @brief Resume counting for PCNT counter
  120. *
  121. * @param pcnt_unit PCNT unit number, select from pcnt_unit_t
  122. *
  123. * @return
  124. * - ESP_OK Success
  125. * - ESP_ERR_INVALID_ARG Parameter error
  126. */
  127. esp_err_t pcnt_counter_resume(pcnt_unit_t pcnt_unit);
  128. /**
  129. * @brief Clear and reset PCNT counter value to zero
  130. *
  131. * @param pcnt_unit PCNT unit number, select from pcnt_unit_t
  132. *
  133. * @return
  134. * - ESP_OK Success
  135. * - ESP_ERR_INVALID_ARG Parameter error
  136. */
  137. esp_err_t pcnt_counter_clear(pcnt_unit_t pcnt_unit);
  138. /**
  139. * @brief Enable PCNT interrupt for PCNT unit
  140. * @note
  141. * Each Pulse counter unit has five watch point events that share the same interrupt.
  142. * Configure events with pcnt_event_enable() and pcnt_event_disable()
  143. *
  144. * @param pcnt_unit PCNT unit number
  145. *
  146. * @return
  147. * - ESP_OK Success
  148. * - ESP_ERR_INVALID_ARG Parameter error
  149. */
  150. esp_err_t pcnt_intr_enable(pcnt_unit_t pcnt_unit);
  151. /**
  152. * @brief Disable PCNT interrupt for PCNT unit
  153. *
  154. * @param pcnt_unit PCNT unit number
  155. *
  156. * @return
  157. * - ESP_OK Success
  158. * - ESP_ERR_INVALID_ARG Parameter error
  159. */
  160. esp_err_t pcnt_intr_disable(pcnt_unit_t pcnt_unit);
  161. /**
  162. * @brief Enable PCNT event of PCNT unit
  163. *
  164. * @param unit PCNT unit number
  165. * @param evt_type Watch point event type.
  166. * All enabled events share the same interrupt (one interrupt per pulse counter unit).
  167. * @return
  168. * - ESP_OK Success
  169. * - ESP_ERR_INVALID_ARG Parameter error
  170. */
  171. esp_err_t pcnt_event_enable(pcnt_unit_t unit, pcnt_evt_type_t evt_type);
  172. /**
  173. * @brief Disable PCNT event of PCNT unit
  174. *
  175. * @param unit PCNT unit number
  176. * @param evt_type Watch point event type.
  177. * All enabled events share the same interrupt (one interrupt per pulse counter unit).
  178. * @return
  179. * - ESP_OK Success
  180. * - ESP_ERR_INVALID_ARG Parameter error
  181. */
  182. esp_err_t pcnt_event_disable(pcnt_unit_t unit, pcnt_evt_type_t evt_type);
  183. /**
  184. * @brief Set PCNT event value of PCNT unit
  185. *
  186. * @param unit PCNT unit number
  187. * @param evt_type Watch point event type.
  188. * All enabled events share the same interrupt (one interrupt per pulse counter unit).
  189. *
  190. * @param value Counter value for PCNT event
  191. *
  192. * @return
  193. * - ESP_OK Success
  194. * - ESP_ERR_INVALID_ARG Parameter error
  195. */
  196. esp_err_t pcnt_set_event_value(pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16_t value);
  197. /**
  198. * @brief Get PCNT event value of PCNT unit
  199. *
  200. * @param unit PCNT unit number
  201. * @param evt_type Watch point event type.
  202. * All enabled events share the same interrupt (one interrupt per pulse counter unit).
  203. * @param value Pointer to accept counter value for PCNT event
  204. *
  205. * @return
  206. * - ESP_OK Success
  207. * - ESP_ERR_INVALID_ARG Parameter error
  208. */
  209. esp_err_t pcnt_get_event_value(pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16_t *value);
  210. /**
  211. * @brief Register PCNT interrupt handler, the handler is an ISR.
  212. * The handler will be attached to the same CPU core that this function is running on.
  213. * Please do not use pcnt_isr_service_install if this function was called.
  214. *
  215. * @param fn Interrupt handler function.
  216. * @param arg Parameter for handler function
  217. * @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred)
  218. * ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info.
  219. * @param handle Pointer to return handle. If non-NULL, a handle for the interrupt will
  220. * be returned here. Calling esp_intr_free to unregister this ISR service if needed,
  221. * but only if the handle is not NULL.
  222. *
  223. * @return
  224. * - ESP_OK Success
  225. * - ESP_ERR_NOT_FOUND Can not find the interrupt that matches the flags.
  226. * - ESP_ERR_INVALID_ARG Function pointer error.
  227. */
  228. esp_err_t pcnt_isr_register(void (*fn)(void*), void * arg, int intr_alloc_flags, pcnt_isr_handle_t *handle);
  229. /**
  230. * @brief Configure PCNT pulse signal input pin and control input pin
  231. *
  232. * @param unit PCNT unit number
  233. * @param channel PCNT channel number
  234. * @param pulse_io Pulse signal input GPIO
  235. * @param ctrl_io Control signal input GPIO
  236. *
  237. * @note Set the signal input to PCNT_PIN_NOT_USED if unused.
  238. *
  239. * @return
  240. * - ESP_OK Success
  241. * - ESP_ERR_INVALID_ARG Parameter error
  242. */
  243. esp_err_t pcnt_set_pin(pcnt_unit_t unit, pcnt_channel_t channel, int pulse_io, int ctrl_io);
  244. /**
  245. * @brief Enable PCNT input filter
  246. *
  247. * @param unit PCNT unit number
  248. *
  249. * @return
  250. * - ESP_OK Success
  251. * - ESP_ERR_INVALID_ARG Parameter error
  252. */
  253. esp_err_t pcnt_filter_enable(pcnt_unit_t unit);
  254. /**
  255. * @brief Disable PCNT input filter
  256. *
  257. * @param unit PCNT unit number
  258. *
  259. * @return
  260. * - ESP_OK Success
  261. * - ESP_ERR_INVALID_ARG Parameter error
  262. */
  263. esp_err_t pcnt_filter_disable(pcnt_unit_t unit);
  264. /**
  265. * @brief Set PCNT filter value
  266. *
  267. * @param unit PCNT unit number
  268. * @param filter_val PCNT signal filter value, counter in APB_CLK cycles.
  269. * Any pulses lasting shorter than this will be ignored when the filter is enabled.
  270. * @note
  271. * filter_val is a 10-bit value, so the maximum filter_val should be limited to 1023.
  272. *
  273. * @return
  274. * - ESP_OK Success
  275. * - ESP_ERR_INVALID_ARG Parameter error
  276. */
  277. esp_err_t pcnt_set_filter_value(pcnt_unit_t unit, uint16_t filter_val);
  278. /**
  279. * @brief Get PCNT filter value
  280. *
  281. * @param unit PCNT unit number
  282. * @param filter_val Pointer to accept PCNT filter value.
  283. *
  284. * @return
  285. * - ESP_OK Success
  286. * - ESP_ERR_INVALID_ARG Parameter error
  287. */
  288. esp_err_t pcnt_get_filter_value(pcnt_unit_t unit, uint16_t *filter_val);
  289. /**
  290. * @brief Set PCNT counter mode
  291. *
  292. * @param unit PCNT unit number
  293. * @param channel PCNT channel number
  294. * @param pos_mode Counter mode when detecting positive edge
  295. * @param neg_mode Counter mode when detecting negative edge
  296. * @param hctrl_mode Counter mode when control signal is high level
  297. * @param lctrl_mode Counter mode when control signal is low level
  298. *
  299. * @return
  300. * - ESP_OK Success
  301. * - ESP_ERR_INVALID_ARG Parameter error
  302. */
  303. esp_err_t pcnt_set_mode(pcnt_unit_t unit, pcnt_channel_t channel,
  304. pcnt_count_mode_t pos_mode, pcnt_count_mode_t neg_mode,
  305. pcnt_ctrl_mode_t hctrl_mode, pcnt_ctrl_mode_t lctrl_mode);
  306. /**
  307. * @brief Add ISR handler for specified unit.
  308. *
  309. * Call this function after using pcnt_isr_service_install() to
  310. * install the PCNT driver's ISR handler service.
  311. *
  312. * The ISR handlers do not need to be declared with IRAM_ATTR,
  313. * unless you pass the ESP_INTR_FLAG_IRAM flag when allocating the
  314. * ISR in pcnt_isr_service_install().
  315. *
  316. * This ISR handler will be called from an ISR. So there is a stack
  317. * size limit (configurable as "ISR stack size" in menuconfig). This
  318. * limit is smaller compared to a global PCNT interrupt handler due
  319. * to the additional level of indirection.
  320. *
  321. * @param unit PCNT unit number
  322. * @param isr_handler Interrupt handler function.
  323. * @param args Parameter for handler function
  324. *
  325. * @return
  326. * - ESP_OK Success
  327. * - ESP_ERR_INVALID_ARG Parameter error
  328. */
  329. esp_err_t pcnt_isr_handler_add(pcnt_unit_t unit, void(*isr_handler)(void *), void *args);
  330. /**
  331. * @brief Install PCNT ISR service.
  332. * @note We can manage different interrupt service for each unit.
  333. * This function will use the default ISR handle service, Calling pcnt_isr_service_uninstall to
  334. * uninstall the default service if needed. Please do not use pcnt_isr_register if this function was called.
  335. *
  336. * @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred)
  337. * ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info.
  338. *
  339. * @return
  340. * - ESP_OK Success
  341. * - ESP_ERR_NO_MEM No memory to install this service
  342. * - ESP_ERR_INVALID_STATE ISR service already installed
  343. */
  344. esp_err_t pcnt_isr_service_install(int intr_alloc_flags);
  345. /**
  346. * @brief Uninstall PCNT ISR service, freeing related resources.
  347. */
  348. void pcnt_isr_service_uninstall(void);
  349. /**
  350. * @brief Delete ISR handler for specified unit.
  351. *
  352. * @param unit PCNT unit number
  353. *
  354. * @return
  355. * - ESP_OK Success
  356. * - ESP_ERR_INVALID_ARG Parameter error
  357. */
  358. esp_err_t pcnt_isr_handler_remove(pcnt_unit_t unit);
  359. /**
  360. * @addtogroup pcnt-examples
  361. *
  362. * @{
  363. *
  364. * EXAMPLE OF PCNT CONFIGURATION
  365. * ==============================
  366. * @code{c}
  367. * //1. Config PCNT unit
  368. * pcnt_config_t pcnt_config = {
  369. * .pulse_gpio_num = 4, //set gpio4 as pulse input gpio
  370. * .ctrl_gpio_num = 5, //set gpio5 as control gpio
  371. * .channel = PCNT_CHANNEL_0, //use unit 0 channel 0
  372. * .lctrl_mode = PCNT_MODE_REVERSE, //when control signal is low, reverse the primary counter mode(inc->dec/dec->inc)
  373. * .hctrl_mode = PCNT_MODE_KEEP, //when control signal is high, keep the primary counter mode
  374. * .pos_mode = PCNT_COUNT_INC, //increment the counter
  375. * .neg_mode = PCNT_COUNT_DIS, //keep the counter value
  376. * .counter_h_lim = 10,
  377. * .counter_l_lim = -10,
  378. * };
  379. * pcnt_unit_config(&pcnt_config); //init unit
  380. * @endcode
  381. *
  382. * EXAMPLE OF PCNT EVENT SETTING
  383. * ==============================
  384. * @code{c}
  385. * //2. Configure PCNT watchpoint event.
  386. * pcnt_set_event_value(PCNT_UNIT_0, PCNT_EVT_THRES_1, 5); //set thres1 value
  387. * pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_THRES_1); //enable thres1 event
  388. * @endcode
  389. *
  390. * For more examples please refer to PCNT example code in IDF_PATH/examples
  391. *
  392. * @}
  393. */
  394. #ifdef __cplusplus
  395. }
  396. #endif
  397. #endif