• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #pragma once
16 
17 #include "esp_types.h"
18 #include "esp_err.h"
19 #include "esp_intr_alloc.h"
20 #include "esp_osal/esp_osal.h"
21 #include "driver/gpio.h"
22 #include "hal/pcnt_types.h"
23 #include "soc/pcnt_periph.h"
24 
25 #ifdef __cplusplus
26 extern "C" {
27 #endif
28 
29 typedef intr_handle_t pcnt_isr_handle_t;
30 
31 /**
32  * @brief Configure Pulse Counter unit
33  *        @note
34  *        This function will disable three events: PCNT_EVT_L_LIM, PCNT_EVT_H_LIM, PCNT_EVT_ZERO.
35  *
36  * @param pcnt_config Pointer of Pulse Counter unit configure parameter
37  *
38  * @return
39  *     - ESP_OK Success
40  *     - ESP_ERR_INVALID_STATE pcnt driver already initialized
41  *     - ESP_ERR_INVALID_ARG Parameter error
42  */
43 esp_err_t pcnt_unit_config(const pcnt_config_t *pcnt_config);
44 
45 /**
46  * @brief Get pulse counter value
47  *
48  * @param pcnt_unit  Pulse Counter unit number
49  * @param count Pointer to accept counter value
50  *
51  * @return
52  *     - ESP_OK Success
53  *     - ESP_ERR_INVALID_STATE pcnt driver has not been initialized
54  *     - ESP_ERR_INVALID_ARG Parameter error
55  */
56 esp_err_t pcnt_get_counter_value(pcnt_unit_t pcnt_unit, int16_t *count);
57 
58 /**
59  * @brief Pause PCNT counter of PCNT unit
60  *
61  * @param pcnt_unit PCNT unit number
62  *
63  * @return
64  *     - ESP_OK Success
65  *     - ESP_ERR_INVALID_STATE pcnt driver has not been initialized
66  *     - ESP_ERR_INVALID_ARG Parameter error
67  */
68 esp_err_t pcnt_counter_pause(pcnt_unit_t pcnt_unit);
69 
70 /**
71  * @brief Resume counting for PCNT counter
72  *
73  * @param pcnt_unit PCNT unit number, select from pcnt_unit_t
74  *
75  * @return
76  *     - ESP_OK Success
77  *     - ESP_ERR_INVALID_STATE pcnt driver has not been initialized
78  *     - ESP_ERR_INVALID_ARG Parameter error
79  */
80 esp_err_t pcnt_counter_resume(pcnt_unit_t pcnt_unit);
81 
82 /**
83  * @brief Clear and reset PCNT counter value to zero
84  *
85  * @param  pcnt_unit PCNT unit number, select from pcnt_unit_t
86  *
87  * @return
88  *     - ESP_OK Success
89  *     - ESP_ERR_INVALID_STATE pcnt driver has not been initialized
90  *     - ESP_ERR_INVALID_ARG Parameter error
91  */
92 esp_err_t pcnt_counter_clear(pcnt_unit_t pcnt_unit);
93 
94 /**
95  * @brief Enable PCNT interrupt for PCNT unit
96  *        @note
97  *        Each Pulse counter unit has five watch point events that share the same interrupt.
98  *        Configure events with pcnt_event_enable() and pcnt_event_disable()
99  *
100  * @param pcnt_unit PCNT unit number
101  *
102  * @return
103  *     - ESP_OK Success
104  *     - ESP_ERR_INVALID_STATE pcnt driver has not been initialized
105  *     - ESP_ERR_INVALID_ARG Parameter error
106  */
107 esp_err_t pcnt_intr_enable(pcnt_unit_t pcnt_unit);
108 
109 /**
110  * @brief Disable PCNT interrupt for PCNT unit
111  *
112  * @param pcnt_unit PCNT unit number
113  *
114  * @return
115  *     - ESP_OK Success
116  *     - ESP_ERR_INVALID_STATE pcnt driver has not been initialized
117  *     - ESP_ERR_INVALID_ARG Parameter error
118  */
119 esp_err_t pcnt_intr_disable(pcnt_unit_t pcnt_unit);
120 
121 /**
122  * @brief Enable PCNT event of PCNT unit
123  *
124  * @param unit PCNT unit number
125  * @param evt_type Watch point event type.
126  *                 All enabled events share the same interrupt (one interrupt per pulse counter unit).
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_event_enable(pcnt_unit_t unit, pcnt_evt_type_t evt_type);
133 
134 /**
135  * @brief Disable PCNT event of PCNT unit
136  *
137  * @param unit PCNT unit number
138  * @param evt_type Watch point event type.
139  *                 All enabled events share the same interrupt (one interrupt per pulse counter unit).
140  * @return
141  *     - ESP_OK Success
142  *     - ESP_ERR_INVALID_STATE pcnt driver has not been initialized
143  *     - ESP_ERR_INVALID_ARG Parameter error
144  */
145 esp_err_t pcnt_event_disable(pcnt_unit_t unit, pcnt_evt_type_t evt_type);
146 
147 /**
148  * @brief Set PCNT event value of PCNT unit
149  *
150  * @param unit PCNT unit number
151  * @param evt_type Watch point event type.
152  *                 All enabled events share the same interrupt (one interrupt per pulse counter unit).
153  *
154  * @param value Counter value for PCNT event
155  *
156  * @return
157  *     - ESP_OK Success
158  *     - ESP_ERR_INVALID_STATE pcnt driver has not been initialized
159  *     - ESP_ERR_INVALID_ARG Parameter error
160  */
161 esp_err_t pcnt_set_event_value(pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16_t value);
162 
163 /**
164  * @brief Get PCNT event value of PCNT unit
165  *
166  * @param unit PCNT unit number
167  * @param evt_type Watch point event type.
168  *                 All enabled events share the same interrupt (one interrupt per pulse counter unit).
169  * @param value Pointer to accept counter value for PCNT event
170  *
171  * @return
172  *     - ESP_OK Success
173  *     - ESP_ERR_INVALID_STATE pcnt driver has not been initialized
174  *     - ESP_ERR_INVALID_ARG Parameter error
175  */
176 esp_err_t pcnt_get_event_value(pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16_t *value);
177 
178 /**
179  * @brief Get PCNT event status of PCNT unit
180  *
181  * @param unit PCNT unit number
182  * @param status Pointer to accept event status word
183  * @return
184  *
185  *      - ESP_OK Success
186  *      - ESP_ERR_INVALID_STATE pcnt driver has not been initialized
187  *      - ESP_ERR_INVALID_ARG Parameter error
188  */
189 esp_err_t pcnt_get_event_status(pcnt_unit_t unit, uint32_t *status);
190 
191 /**
192  * @brief Unregister PCNT interrupt handler (registered by pcnt_isr_register), the handler is an ISR.
193  *        The handler will be attached to the same CPU core that this function is running on.
194  *        If the interrupt service is registered by pcnt_isr_service_install, please call pcnt_isr_service_uninstall instead
195  *
196  * @param handle handle to unregister the ISR service.
197  *
198  * @return
199  *     - ESP_OK Success
200  *     - ESP_ERR_NOT_FOUND Can not find the interrupt that matches the flags.
201  *     - ESP_ERR_INVALID_ARG Function pointer error.
202  */
203 esp_err_t pcnt_isr_unregister(pcnt_isr_handle_t handle);
204 
205 /**
206  * @brief Register PCNT interrupt handler, the handler is an ISR.
207  *        The handler will be attached to the same CPU core that this function is running on.
208  *        Please do not use pcnt_isr_service_install if this function was called.
209  *
210  * @param fn Interrupt handler function.
211  * @param arg Parameter for handler function
212  * @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred)
213  *        ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info.
214  * @param handle Pointer to return handle. If non-NULL, a handle for the interrupt will
215  *        be returned here. Calling pcnt_isr_unregister to unregister this ISR service if needed,
216  *        but only if the handle is not NULL.
217  *
218  * @return
219  *     - ESP_OK Success
220  *     - ESP_ERR_NOT_FOUND Can not find the interrupt that matches the flags.
221  *     - ESP_ERR_INVALID_ARG Function pointer error.
222  */
223 esp_err_t pcnt_isr_register(void (*fn)(void *), void *arg, int intr_alloc_flags, pcnt_isr_handle_t *handle);
224 
225 /**
226  * @brief Configure PCNT pulse signal input pin and control input pin
227  *
228  * @param unit PCNT unit number
229  * @param channel PCNT channel number
230  * @param pulse_io Pulse signal input GPIO
231  * @param ctrl_io Control signal input GPIO
232  *
233  * @note  Set the signal input to PCNT_PIN_NOT_USED if unused.
234  *
235  * @return
236  *     - ESP_OK Success
237  *     - ESP_ERR_INVALID_STATE pcnt driver has not been initialized
238  *     - ESP_ERR_INVALID_ARG Parameter error
239  */
240 esp_err_t pcnt_set_pin(pcnt_unit_t unit, pcnt_channel_t channel, int pulse_io, int ctrl_io);
241 
242 /**
243  * @brief Enable PCNT input filter
244  *
245  * @param unit PCNT unit number
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_filter_enable(pcnt_unit_t unit);
253 
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_STATE pcnt driver has not been initialized
262  *     - ESP_ERR_INVALID_ARG Parameter error
263  */
264 esp_err_t pcnt_filter_disable(pcnt_unit_t unit);
265 
266 /**
267  * @brief Set PCNT filter value
268  *
269  * @param unit PCNT unit number
270  * @param filter_val PCNT signal filter value, counter in APB_CLK cycles.
271  *        Any pulses lasting shorter than this will be ignored when the filter is enabled.
272  *        @note
273  *        filter_val is a 10-bit value, so the maximum filter_val should be limited to 1023.
274  *
275  * @return
276  *     - ESP_OK Success
277  *     - ESP_ERR_INVALID_STATE pcnt driver has not been initialized
278  *     - ESP_ERR_INVALID_ARG Parameter error
279  */
280 esp_err_t pcnt_set_filter_value(pcnt_unit_t unit, uint16_t filter_val);
281 
282 /**
283  * @brief Get PCNT filter value
284  *
285  * @param unit PCNT unit number
286  * @param filter_val Pointer to accept PCNT filter value.
287  *
288  * @return
289  *     - ESP_OK Success
290  *     - ESP_ERR_INVALID_STATE pcnt driver has not been initialized
291  *     - ESP_ERR_INVALID_ARG Parameter error
292  */
293 esp_err_t pcnt_get_filter_value(pcnt_unit_t unit, uint16_t *filter_val);
294 
295 /**
296  * @brief Set PCNT counter mode
297  *
298  * @param unit PCNT unit number
299  * @param channel PCNT channel number
300  * @param pos_mode Counter mode when detecting positive edge
301  * @param neg_mode Counter mode when detecting negative edge
302  * @param hctrl_mode Counter mode when control signal is high level
303  * @param lctrl_mode Counter mode when control signal is low level
304  *
305  * @return
306  *     - ESP_OK Success
307  *     - ESP_ERR_INVALID_STATE pcnt driver has not been initialized
308  *     - ESP_ERR_INVALID_ARG Parameter error
309  */
310 esp_err_t pcnt_set_mode(pcnt_unit_t unit, pcnt_channel_t channel,
311                         pcnt_count_mode_t pos_mode, pcnt_count_mode_t neg_mode,
312                         pcnt_ctrl_mode_t hctrl_mode, pcnt_ctrl_mode_t lctrl_mode);
313 
314 /**
315  * @brief Add ISR handler for specified unit.
316  *
317  * Call this function after using pcnt_isr_service_install() to
318  * install the PCNT driver's ISR handler service.
319  *
320  * The ISR handlers do not need to be declared with IRAM_ATTR,
321  * unless you pass the ESP_INTR_FLAG_IRAM flag when allocating the
322  * ISR in pcnt_isr_service_install().
323  *
324  * This ISR handler will be called from an ISR. So there is a stack
325  * size limit (configurable as "ISR stack size" in menuconfig). This
326  * limit is smaller compared to a global PCNT interrupt handler due
327  * to the additional level of indirection.
328  *
329  * @param unit PCNT unit number
330  * @param isr_handler Interrupt handler function.
331  * @param args Parameter for handler function
332  *
333  * @return
334  *     - ESP_OK Success
335  *     - ESP_ERR_INVALID_STATE pcnt driver has not been initialized
336  *     - ESP_ERR_INVALID_ARG Parameter error
337  */
338 esp_err_t pcnt_isr_handler_add(pcnt_unit_t unit, void(*isr_handler)(void *), void *args);
339 
340 /**
341  * @brief Install PCNT ISR service.
342  * @note We can manage different interrupt service for each unit.
343  *       This function will use the default ISR handle service, Calling pcnt_isr_service_uninstall to
344  *       uninstall the default service if needed. Please do not use pcnt_isr_register if this function was called.
345  *
346  * @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred)
347  *        ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info.
348  *
349  * @return
350  *     - ESP_OK Success
351  *     - ESP_ERR_INVALID_STATE pcnt driver has not been initialized
352  *     - ESP_ERR_NO_MEM No memory to install this service
353  *     - ESP_ERR_INVALID_STATE ISR service already installed
354  */
355 esp_err_t pcnt_isr_service_install(int intr_alloc_flags);
356 
357 /**
358  * @brief Uninstall PCNT ISR service, freeing related resources.
359  */
360 void pcnt_isr_service_uninstall(void);
361 
362 /**
363  * @brief Delete ISR handler for specified unit.
364  *
365  * @param unit PCNT unit number
366  *
367  * @return
368  *     - ESP_OK Success
369  *     - ESP_ERR_INVALID_STATE pcnt driver has not been initialized
370  *     - ESP_ERR_INVALID_ARG Parameter error
371  */
372 esp_err_t pcnt_isr_handler_remove(pcnt_unit_t unit);
373 
374 /**
375  * @addtogroup pcnt-examples
376  *
377  * @{
378  *
379  * EXAMPLE OF PCNT CONFIGURATION
380  * ==============================
381  * @code{c}
382  * //1. Config PCNT unit
383  * pcnt_config_t pcnt_config = {
384  *     .pulse_gpio_num = 4,         //set gpio4 as pulse input gpio
385  *     .ctrl_gpio_num = 5,          //set gpio5 as control gpio
386  *     .channel = PCNT_CHANNEL_0,         //use unit 0 channel 0
387  *     .lctrl_mode = PCNT_MODE_REVERSE,   //when control signal is low, reverse the primary counter mode(inc->dec/dec->inc)
388  *     .hctrl_mode = PCNT_MODE_KEEP,      //when control signal is high, keep the primary counter mode
389  *     .pos_mode = PCNT_COUNT_INC,        //increment the counter
390  *     .neg_mode = PCNT_COUNT_DIS,        //keep the counter value
391  *     .counter_h_lim = 10,
392  *     .counter_l_lim = -10,
393  * };
394  * pcnt_unit_config(&pcnt_config);        //init unit
395  * @endcode
396  *
397  * EXAMPLE OF PCNT EVENT SETTING
398  * ==============================
399  * @code{c}
400  * //2. Configure PCNT watchpoint event.
401  * pcnt_set_event_value(PCNT_UNIT_0, PCNT_EVT_THRES_1, 5);   //set thres1 value
402  * pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_THRES_1);         //enable thres1 event
403  * @endcode
404  *
405  * For more examples please refer to PCNT example code in IDF_PATH/examples
406  *
407  * @}
408  */
409 
410 #ifdef __cplusplus
411 }
412 #endif
413