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