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