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