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