Merge branch 'driver_merge_tmp/merge_pcnt' into 'master'

driver: PCNT

1. add PCNT module in periph_ctrl.c/.h
2. add description of PCNT status in pcnt_struct.h
3. add PCNT driver code
4. add PCNT example code.

See merge request !229
This commit is contained in:
Wang Jia Lin 2016-11-25 00:41:16 +08:00
commit 35ae2cd1a5
12 changed files with 998 additions and 1 deletions

View file

@ -0,0 +1,359 @@
#ifndef __PCNT_H__
#define __PCNT_H__
#include <esp_types.h>
#include "esp_intr.h"
#include "esp_err.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/xtensa_api.h"
#include "soc/soc.h"
#include "soc/pcnt_reg.h"
#include "soc/pcnt_struct.h"
#include "soc/gpio_sig_map.h"
#include "driver/gpio.h"
#ifdef __cplusplus
extern "C" {
#endif
#define PCNT_PIN_NOT_USED (-1) /*!< Pin are not used */
typedef enum {
PCNT_MODE_KEEP = 0, /*!< Control mode: won't change counter mode*/
PCNT_MODE_REVERSE = 1, /*!< Control mode: invert counter mode(increase -> decrease, decrease -> increase);*/
PCNT_MODE_DISABLE = 2, /*!< Control mode: Inhibit counter(counter value will not change in this condition)*/
PCNT_MODE_MAX
} pcnt_ctrl_mode_t;
typedef enum {
PCNT_COUNT_DIS = 0, /*!< Counter mode: Decrease counter value*/
PCNT_COUNT_INC = 1, /*!< Counter mode: Increase counter value*/
PCNT_COUNT_DEC = 2, /*!< Counter mode: Inhibit counter(counter value will not change in this condition)*/
PCNT_COUNT_MAX
} pcnt_count_mode_t;
typedef enum {
PCNT_UNIT_0 = 0, /*!< PCNT unit0 */
PCNT_UNIT_1 = 1, /*!< PCNT unit1 */
PCNT_UNIT_2 = 2, /*!< PCNT unit2 */
PCNT_UNIT_3 = 3, /*!< PCNT unit3 */
PCNT_UNIT_4 = 4, /*!< PCNT unit4 */
PCNT_UNIT_5 = 5, /*!< PCNT unit5 */
PCNT_UNIT_6 = 6, /*!< PCNT unit6 */
PCNT_UNIT_7 = 7, /*!< PCNT unit7 */
PCNT_UNIT_MAX,
} pcnt_unit_t;
typedef enum{
PCNT_CHANNEL_0 = 0x00, /*!< PCNT channel0 */
PCNT_CHANNEL_1 = 0x01, /*!< PCNT channel1 */
PCNT_CHANNEL_MAX,
} pcnt_channel_t;
typedef enum {
PCNT_EVT_L_LIM = 0, /*!< PCNT watch point event: Minimum counter value */
PCNT_EVT_H_LIM = 1, /*!< PCNT watch point event: Maximum counter value*/
PCNT_EVT_THRES_0 = 2, /*!< PCNT watch point event: threshold0 value event*/
PCNT_EVT_THRES_1 = 3, /*!< PCNT watch point event: threshold1 value event*/
PCNT_EVT_ZERO = 4, /*!< PCNT watch point event: counter value zero event*/
PCNT_EVT_MAX
} pcnt_evt_type_t;
/**
* @brief Pulse Counter configure struct
*/
typedef struct {
int pulse_gpio_num; /*!< Pulse input gpio_num, if you want to use gpio16, pulse_gpio_num = 16, a negative value will be ignored */
int ctrl_gpio_num; /*!< Contol signal input gpio_num, 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
*
* @param pcnt_config Pointer of Pulse Counter unit configure parameter
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t pcnt_unit_config(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_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_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_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_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_ARG Parameter error
*/
esp_err_t pcnt_intr_enable(pcnt_unit_t pcnt_unit);
/**
* @brief Disable PCNT interrupt for PCNT uint
*
* @param pcnt_unit PCNT unit number
*
* @return
* - ESP_OK Success
* - 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_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_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_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_ARG Parameter error
*/
esp_err_t pcnt_get_event_value(pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16_t *value);
/**
* @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.
* @note
* Users should know that which CPU is running and then pick a INUM that is not used by system.
* We can find the information of INUM and interrupt level in soc.h.
*
* @param pcnt_intr_num PCNT interrupt number, check the info in soc.h, and please see the core-isa.h for more details
* @param fn Interrupt handler function.
* @note
* Note that the handler function MUST be defined with attribution of "IRAM_ATTR".
* @param arg Parameter for handler function
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Function pointer error.
*/
esp_err_t pcnt_isr_register(uint32_t pcnt_intr_num, void (*fn)(void*), void * arg);
/**
* @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
* @note
* Set to PCNT_PIN_NOT_USED if unused.
* @param ctrl_io Control signal input GPIO
* @note
* Set to PCNT_PIN_NOT_USED if unused.
*
* @return
* - ESP_OK Success
* - 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_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_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_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_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_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);
/**
* @addtogroup pcnt-examples
*
* @{
*
* EXAMPLE OF PCNT CONFIGURATION
* ==============================
* @code{c}
* //1. Config PCNT unit
* pcnt_config_t pcnt_config = {
* .pulse_gpio_num = 4, //set gpio4 as pulse input gpio
* .ctrl_gpio_num = 5, //set gpio5 as control gpio
* .channel = PCNT_CHANNEL_0, //use unit 0 channel 0
* .lctrl_mode = PCNT_MODE_REVERSE, //when control signal is low ,reverse the primary counter mode(inc->dec/dec->inc)
* .hctrl_mode = PCNT_MODE_KEEP, //when control signal is high,keep the primary counter mode
* .pos_mode = PCNT_COUNT_INC, //increment the counter
* .neg_mode = PCNT_COUNT_DIS, //keep the counter value
* .counter_h_lim = 10,
* .counter_l_lim = -10,
* };
* pcnt_unit_config(&pcnt_config); //init unit
* @endcode
*
* EXAMPLE OF PCNT EVENT SETTING
* ==============================
* @code{c}
* //2. Configure PCNT watchpoint event.
* pcnt_set_event_value(PCNT_UNIT_0, PCNT_EVT_THRES_1, 5); //set thres1 value
* pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_THRES_1); //enable thres1 event
* @endcode
*
* For more examples please refer to PCNT example code in IDF_PATH/examples
*
* @}
*/
#ifdef __cplusplus
}
#endif
#endif

View file

@ -40,6 +40,7 @@ typedef enum {
PERIPH_UHCI0_MODULE,
PERIPH_UHCI1_MODULE,
PERIPH_RMT_MODULE,
PERIPH_PCNT_MODULE,
} periph_module_t;
/**

View file

@ -191,6 +191,7 @@ esp_err_t ledc_channel_config(ledc_channel_config_t* ledc_conf)
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
LEDC_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(gpio_num), "ledc GPIO output number error", ESP_ERR_INVALID_ARG);
LEDC_CHECK(timer_select <= LEDC_TIMER_3, "ledc timer error", ESP_ERR_INVALID_ARG);
periph_module_enable(PERIPH_LEDC_MODULE);
esp_err_t ret = ESP_OK;
/*set channel parameters*/
/* channel parameters decide how the waveform looks like in one period*/

278
components/driver/pcnt.c Normal file
View file

@ -0,0 +1,278 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "esp_log.h"
#include "driver/pcnt.h"
#include "driver/periph_ctrl.h"
#define PCNT_CHANNEL_ERR_STR "PCNT CHANNEL ERROR"
#define PCNT_UNIT_ERR_STR "PCNT UNIT ERROR"
#define PCNT_GPIO_ERR_STR "PCNT GPIO NUM ERROR"
#define PCNT_ADDRESS_ERR_STR "PCNT ADDRESS ERROR"
#define PCNT_PARAM_ERR_STR "PCNT PARAM ERROR"
#define PCNT_COUNT_MODE_ERR_STR "PCNT COUNTER MODE ERROR"
#define PCNT_CTRL_MODE_ERR_STR "PCNT CTRL MODE ERROR"
#define PCNT_EVT_TYPE_ERR_STR "PCNT value type error"
#define PCNT_CHECK(a,str,ret_val) if(!(a)) { \
ESP_LOGE(PCNT_TAG,"%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str); \
return (ret_val); \
}
static const char* PCNT_TAG = "PCNT";
static portMUX_TYPE pcnt_spinlock = portMUX_INITIALIZER_UNLOCKED;
#define PCNT_ENTER_CRITICAL(mux) portENTER_CRITICAL(mux)
#define PCNT_EXIT_CRITICAL(mux) portEXIT_CRITICAL(mux)
#define PCNT_ENTER_CRITICAL_ISR(mux) portENTER_CRITICAL_ISR(mux)
#define PCNT_EXIT_CRITICAL_ISR(mux) portEXIT_CRITICAL_ISR(mux)
esp_err_t pcnt_unit_config(pcnt_config_t *pcnt_config)
{
uint8_t unit = pcnt_config->channel;
uint8_t channel = pcnt_config->unit;
int input_io = pcnt_config->pulse_gpio_num;
int ctrl_io = pcnt_config->ctrl_gpio_num;
PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
PCNT_CHECK(channel < PCNT_CHANNEL_MAX, PCNT_CHANNEL_ERR_STR, ESP_ERR_INVALID_ARG);
PCNT_CHECK(input_io < 0 || (GPIO_IS_VALID_GPIO(input_io) && (input_io != ctrl_io)), "PCNT pluse input io error", ESP_ERR_INVALID_ARG);
PCNT_CHECK(ctrl_io < 0 || GPIO_IS_VALID_GPIO(ctrl_io), "PCNT ctrl io error", ESP_ERR_INVALID_ARG);
PCNT_CHECK((pcnt_config->pos_mode < PCNT_COUNT_MAX) && (pcnt_config->neg_mode < PCNT_COUNT_MAX), PCNT_COUNT_MODE_ERR_STR, ESP_ERR_INVALID_ARG);
PCNT_CHECK((pcnt_config->hctrl_mode < PCNT_MODE_MAX) && (pcnt_config->lctrl_mode < PCNT_MODE_MAX), PCNT_CTRL_MODE_ERR_STR, ESP_ERR_INVALID_ARG);
/*Enalbe hardware module*/
periph_module_enable(PERIPH_PCNT_MODULE);
/*Set counter range*/
pcnt_set_event_value(unit, PCNT_EVT_H_LIM, pcnt_config->counter_h_lim);
pcnt_set_event_value(unit, PCNT_EVT_L_LIM, pcnt_config->counter_l_lim);
/*Default value after reboot is positive, we disable these events like others*/
pcnt_event_disable(unit, PCNT_EVT_H_LIM);
pcnt_event_disable(unit, PCNT_EVT_L_LIM);
pcnt_event_disable(unit, PCNT_EVT_ZERO);
pcnt_filter_disable(unit);
/*set pulse input and control mode*/
pcnt_set_mode(unit, channel, pcnt_config->pos_mode, pcnt_config->neg_mode, pcnt_config->hctrl_mode, pcnt_config->lctrl_mode);
/*Set pulse input and control pins*/
pcnt_set_pin(unit, channel, input_io, ctrl_io);
return ESP_OK;
}
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)
{
PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
PCNT_CHECK(channel < PCNT_CHANNEL_MAX, PCNT_CHANNEL_ERR_STR, ESP_ERR_INVALID_ARG);
PCNT_CHECK((pos_mode < PCNT_COUNT_MAX) && (neg_mode < PCNT_COUNT_MAX), PCNT_COUNT_MODE_ERR_STR, ESP_ERR_INVALID_ARG);
PCNT_CHECK((hctrl_mode < PCNT_MODE_MAX) && (lctrl_mode < PCNT_MODE_MAX), PCNT_CTRL_MODE_ERR_STR, ESP_ERR_INVALID_ARG);
if(channel == 0) {
PCNT.conf_unit[unit].conf0.ch0_pos_mode = pos_mode;
PCNT.conf_unit[unit].conf0.ch0_neg_mode = neg_mode;
PCNT.conf_unit[unit].conf0.ch0_hctrl_mode = hctrl_mode;
PCNT.conf_unit[unit].conf0.ch0_lctrl_mode = lctrl_mode;
} else {
PCNT.conf_unit[unit].conf0.ch1_pos_mode = pos_mode;
PCNT.conf_unit[unit].conf0.ch1_neg_mode = neg_mode;
PCNT.conf_unit[unit].conf0.ch1_hctrl_mode = hctrl_mode;
PCNT.conf_unit[unit].conf0.ch1_lctrl_mode = lctrl_mode;
}
return ESP_OK;
}
esp_err_t pcnt_set_pin(pcnt_unit_t unit, pcnt_channel_t channel, int pulse_io, int ctrl_io)
{
PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
PCNT_CHECK(channel < PCNT_CHANNEL_MAX, PCNT_CHANNEL_ERR_STR, ESP_ERR_INVALID_ARG);
PCNT_CHECK(GPIO_IS_VALID_GPIO(pulse_io) || pulse_io < 0, PCNT_GPIO_ERR_STR, ESP_ERR_INVALID_ARG);
PCNT_CHECK(GPIO_IS_VALID_GPIO(ctrl_io) || ctrl_io < 0, PCNT_GPIO_ERR_STR, ESP_ERR_INVALID_ARG);
int input_sig_index = (channel == 0 ? PCNT_SIG_CH0_IN0_IDX + 4 * unit : PCNT_SIG_CH1_IN0_IDX + 4 * unit);
int ctrl_sig_index = (channel == 0 ? PCNT_CTRL_CH0_IN0_IDX + 4 * unit : PCNT_CTRL_CH1_IN0_IDX + 4 * unit);
if(pulse_io >= 0) {
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[pulse_io], PIN_FUNC_GPIO);
gpio_set_direction(pulse_io, GPIO_MODE_INPUT);
gpio_set_pull_mode(pulse_io, GPIO_PULLUP_ONLY);
gpio_matrix_in(pulse_io, input_sig_index, 0);
}
if(ctrl_io >= 0) {
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[ctrl_io], PIN_FUNC_GPIO);
gpio_set_direction(ctrl_io, GPIO_MODE_INPUT);
gpio_set_pull_mode(ctrl_io, GPIO_PULLUP_ONLY);
gpio_matrix_in(ctrl_io, ctrl_sig_index, 0);
}
return ESP_OK;
}
esp_err_t pcnt_get_counter_value(pcnt_unit_t pcnt_unit, int16_t* count)
{
PCNT_CHECK(pcnt_unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
PCNT_CHECK(count != NULL, PCNT_ADDRESS_ERR_STR, ESP_ERR_INVALID_ARG);
*count = (int16_t) PCNT.cnt_unit[pcnt_unit].cnt_val;
return ESP_OK;
}
esp_err_t pcnt_counter_pause(pcnt_unit_t pcnt_unit)
{
PCNT_CHECK(pcnt_unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
PCNT_ENTER_CRITICAL(&pcnt_spinlock);
PCNT.ctrl.val |= BIT(PCNT_CNT_PAUSE_U0_S + (pcnt_unit * 2));
PCNT_EXIT_CRITICAL(&pcnt_spinlock);
return ESP_OK;
}
esp_err_t pcnt_counter_resume(pcnt_unit_t pcnt_unit)
{
PCNT_CHECK(pcnt_unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
PCNT_ENTER_CRITICAL(&pcnt_spinlock);
PCNT.ctrl.val &= (~(BIT(PCNT_CNT_PAUSE_U0_S + (pcnt_unit * 2))));
PCNT_EXIT_CRITICAL(&pcnt_spinlock);
return ESP_OK;
}
esp_err_t pcnt_counter_clear(pcnt_unit_t pcnt_unit)
{
PCNT_CHECK(pcnt_unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
PCNT_ENTER_CRITICAL(&pcnt_spinlock);
PCNT.ctrl.val &= (~(BIT(PCNT_PLUS_CNT_RST_U0_S + (pcnt_unit * 2))));
PCNT_EXIT_CRITICAL(&pcnt_spinlock);
return ESP_OK;
}
esp_err_t pcnt_intr_enable(pcnt_unit_t pcnt_unit)
{
PCNT_CHECK(pcnt_unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
PCNT_ENTER_CRITICAL(&pcnt_spinlock);
PCNT.int_ena.val |= BIT(PCNT_CNT_THR_EVENT_U0_INT_ENA_S + pcnt_unit);
PCNT_EXIT_CRITICAL(&pcnt_spinlock);
return ESP_OK;
}
esp_err_t pcnt_intr_disable(pcnt_unit_t pcnt_unit)
{
PCNT_CHECK(pcnt_unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
PCNT_ENTER_CRITICAL(&pcnt_spinlock);
PCNT.int_ena.val &= (~(BIT(PCNT_CNT_THR_EVENT_U0_INT_ENA_S + pcnt_unit)));
PCNT_EXIT_CRITICAL(&pcnt_spinlock);
return ESP_OK;
}
esp_err_t pcnt_event_enable(pcnt_unit_t unit, pcnt_evt_type_t evt_type)
{
PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
PCNT_CHECK(evt_type < PCNT_EVT_MAX, PCNT_EVT_TYPE_ERR_STR, ESP_ERR_INVALID_ARG);
if(evt_type == PCNT_EVT_L_LIM) {
PCNT.conf_unit[unit].conf0.thr_l_lim_en = 1;
} else if(evt_type == PCNT_EVT_H_LIM) {
PCNT.conf_unit[unit].conf0.thr_h_lim_en = 1;
} else if(evt_type == PCNT_EVT_THRES_0) {
PCNT.conf_unit[unit].conf0.thr_thres0_en = 1;
} else if(evt_type == PCNT_EVT_THRES_1) {
PCNT.conf_unit[unit].conf0.thr_thres1_en = 1;
} else if(evt_type == PCNT_EVT_ZERO) {
PCNT.conf_unit[unit].conf0.thr_zero_en = 1;
}
return ESP_OK;
}
esp_err_t pcnt_event_disable(pcnt_unit_t unit, pcnt_evt_type_t evt_type)
{
PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
PCNT_CHECK(evt_type < PCNT_EVT_MAX, PCNT_EVT_TYPE_ERR_STR, ESP_ERR_INVALID_ARG);
if(evt_type == PCNT_EVT_L_LIM) {
PCNT.conf_unit[unit].conf0.thr_l_lim_en = 0;
} else if(evt_type == PCNT_EVT_H_LIM) {
PCNT.conf_unit[unit].conf0.thr_h_lim_en = 0;
} else if(evt_type == PCNT_EVT_THRES_0) {
PCNT.conf_unit[unit].conf0.thr_thres0_en = 0;
} else if(evt_type == PCNT_EVT_THRES_1) {
PCNT.conf_unit[unit].conf0.thr_thres1_en = 0;
} else if(evt_type == PCNT_EVT_ZERO) {
PCNT.conf_unit[unit].conf0.thr_zero_en = 0;
}
return ESP_OK;
}
esp_err_t pcnt_set_event_value(pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16_t value)
{
PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
PCNT_CHECK(evt_type < PCNT_EVT_MAX, PCNT_EVT_TYPE_ERR_STR, ESP_ERR_INVALID_ARG);
if(evt_type == PCNT_EVT_L_LIM) {
PCNT.conf_unit[unit].conf2.cnt_l_lim = value;
} else if(evt_type == PCNT_EVT_H_LIM) {
PCNT.conf_unit[unit].conf2.cnt_h_lim = value;
} else if(evt_type == PCNT_EVT_THRES_0) {
PCNT.conf_unit[unit].conf1.cnt_thres0 = value;
} else if(evt_type == PCNT_EVT_THRES_1) {
PCNT.conf_unit[unit].conf1.cnt_thres1 = value;
}
return ESP_OK;
}
esp_err_t pcnt_get_event_value(pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16_t *value)
{
PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
PCNT_CHECK(evt_type < PCNT_EVT_MAX, PCNT_EVT_TYPE_ERR_STR, ESP_ERR_INVALID_ARG);
PCNT_CHECK(value != NULL, PCNT_ADDRESS_ERR_STR, ESP_ERR_INVALID_ARG);
if(evt_type == PCNT_EVT_L_LIM) {
*value = (int16_t) PCNT.conf_unit[unit].conf2.cnt_l_lim;
} else if(evt_type == PCNT_EVT_H_LIM) {
*value = (int16_t) PCNT.conf_unit[unit].conf2.cnt_h_lim;
} else if(evt_type == PCNT_EVT_THRES_0) {
*value = (int16_t) PCNT.conf_unit[unit].conf1.cnt_thres0;
} else if(evt_type == PCNT_EVT_THRES_1) {
*value = (int16_t) PCNT.conf_unit[unit].conf1.cnt_thres1;
} else {
*value = 0;
}
return ESP_OK;
}
esp_err_t pcnt_set_filter_value(pcnt_unit_t unit, uint16_t filter_val)
{
PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
PCNT_CHECK(filter_val < 1024, PCNT_PARAM_ERR_STR, ESP_ERR_INVALID_ARG);
PCNT.conf_unit[unit].conf0.filter_thres = filter_val;
return ESP_OK;
}
esp_err_t pcnt_get_filter_value(pcnt_unit_t unit, uint16_t *filter_val)
{
PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
PCNT_CHECK(filter_val != NULL, PCNT_ADDRESS_ERR_STR, ESP_ERR_INVALID_ARG);
*filter_val = PCNT.conf_unit[unit].conf0.filter_thres;
return ESP_OK;
}
esp_err_t pcnt_filter_enable(pcnt_unit_t unit)
{
PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
PCNT.conf_unit[unit].conf0.filter_en = 1;
return ESP_OK;
}
esp_err_t pcnt_filter_disable(pcnt_unit_t unit)
{
PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
PCNT.conf_unit[unit].conf0.filter_en = 0;
return ESP_OK;
}
esp_err_t pcnt_isr_register(uint32_t pcnt_intr_num, void (*fun)(void*), void * arg)
{
PCNT_CHECK(fun != NULL, PCNT_ADDRESS_ERR_STR, ESP_ERR_INVALID_ARG);
ESP_INTR_DISABLE(pcnt_intr_num);
intr_matrix_set(xPortGetCoreID(), ETS_PCNT_INTR_SOURCE, pcnt_intr_num);
xt_set_interrupt_handler(pcnt_intr_num, fun, arg);
ESP_INTR_ENABLE(pcnt_intr_num);
return ESP_OK;
}

View file

@ -93,6 +93,10 @@ void periph_module_enable(periph_module_t periph)
SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UHCI1_CLK_EN);
CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UHCI1_RST);
break;
case PERIPH_PCNT_MODULE:
SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_PCNT_CLK_EN);
CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_PCNT_RST);
break;
default:
break;
}
@ -103,6 +107,10 @@ void periph_module_disable(periph_module_t periph)
{
portENTER_CRITICAL(&periph_spinlock);
switch(periph) {
case PERIPH_RMT_MODULE:
CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_RMT_CLK_EN);
SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_RMT_RST);
break;
case PERIPH_LEDC_MODULE:
CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_LEDC_CLK_EN);
SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_LEDC_RST);
@ -167,6 +175,10 @@ void periph_module_disable(periph_module_t periph)
CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UHCI1_CLK_EN);
SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UHCI1_RST);
break;
case PERIPH_PCNT_MODULE:
CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_PCNT_CLK_EN);
SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_PCNT_RST);
break;
default:
break;
}

View file

@ -1319,6 +1319,36 @@
#define PCNT_CORE_STATUS_U0_M ((PCNT_CORE_STATUS_U0_V)<<(PCNT_CORE_STATUS_U0_S))
#define PCNT_CORE_STATUS_U0_V 0xFFFFFFFF
#define PCNT_CORE_STATUS_U0_S 0
/*0: positive value to zero; 1: negative value to zero; 2: counter value negative ; 3: counter value positive*/
#define PCNT_STATUS_CNT_MODE 0x3
#define PCNT_STATUS_CNT_MODE_M ((PCNT_STATUS_CNT_MODE_V)<<(PCNT_STATUS_CNT_MODE_S))
#define PCNT_STATUS_CNT_MODE_V 0x3
#define PCNT_STATUS_CNT_MODE_S 0
/* counter value equals to thresh1*/
#define PCNT_STATUS_THRES1 BIT(2)
#define PCNT_STATUS_THRES1_M BIT(2)
#define PCNT_STATUS_THRES1_V 0x1
#define PCNT_STATUS_THRES1_S 2
/* counter value equals to thresh0*/
#define PCNT_STATUS_THRES0 BIT(3)
#define PCNT_STATUS_THRES0_M BIT(3)
#define PCNT_STATUS_THRES0_V 0x1
#define PCNT_STATUS_THRES0_S 3
/* counter value reaches h_lim*/
#define PCNT_STATUS_L_LIM BIT(4)
#define PCNT_STATUS_L_LIM_M BIT(4)
#define PCNT_STATUS_L_LIM_V 0x1
#define PCNT_STATUS_L_LIM_S 4
/* counter value reaches l_lim*/
#define PCNT_STATUS_H_LIM BIT(5)
#define PCNT_STATUS_H_LIM_M BIT(5)
#define PCNT_STATUS_H_LIM_V 0x1
#define PCNT_STATUS_H_LIM_S 5
/* counter value equals to zero*/
#define PCNT_STATUS_ZERO BIT(6)
#define PCNT_STATUS_ZERO_M BIT(6)
#define PCNT_STATUS_ZERO_V 0x1
#define PCNT_STATUS_ZERO_S 6
#define PCNT_U1_STATUS_REG (DR_REG_PCNT_BASE + 0x0094)
/* PCNT_CORE_STATUS_U1 : RO ;bitpos:[31:0] ;default: 32'h0 ; */

View file

@ -113,7 +113,18 @@ typedef volatile struct {
};
uint32_t val;
} int_clr;
uint32_t status_unit[8];
union {
struct {
uint32_t cnt_mode:2; /*0: positive value to zero; 1: negative value to zero; 2: counter value negative ; 3: counter value positive*/
uint32_t thres1_lat:1; /* counter value equals to thresh1*/
uint32_t thres0_lat:1; /* counter value equals to thresh0*/
uint32_t l_lim_lat:1; /* counter value reaches h_lim*/
uint32_t h_lim_lat:1; /* counter value reaches l_lim*/
uint32_t zero_lat:1; /* counter value equals zero*/
uint32_t reserved7:25;
};
uint32_t val;
} status_unit[8];
union {
struct {
uint32_t cnt_rst_u0: 1; /*Set this bit to clear unit0's counter.*/

66
docs/api/pcnt.rst Normal file
View file

@ -0,0 +1,66 @@
Pulse Counter
========
Overview
--------
The PCNT (Pulse Counter) module is designed to count the number of rising and/or falling edges of an input signal. Each pulse counter unit has a 16-bit signed counter register and two channels that can be configured to either increment or decrement the counter. Each channel has a signal input that accepts signal edges to be detected, as well as a control input that can be used to enable or disable the signal input. The inputs have optional filters that can be used to discard unwanted glitches in the signal.
Application Example
-------------------
Pulse counter with control signal and event interrupt example: `examples/12_pcnt <https://github.com/espressif/esp-idf/tree/master/examples/12_pcnt>`_.
API Reference
-------------
Header Files
^^^^^^^^^^^^
* `driver/pcnt.h <https://github.com/espressif/esp-idf/blob/master/components/driver/include/driver/pcnt.h>`_
Macros
^^^^^^
Type Definitions
^^^^^^^^^^^^^^^^
Enumerations
^^^^^^^^^^^^
.. doxygenenum:: pcnt_ctrl_mode_t
.. doxygenenum:: pcnt_count_mode_t
.. doxygenenum:: pcnt_unit_t
.. doxygenenum:: pcnt_channel_t
.. doxygenenum:: pcnt_evt_type_t
Structures
^^^^^^^^^^
.. doxygenstruct:: pcnt_config_t
Functions
^^^^^^^^^
.. doxygenfunction:: pcnt_unit_config
.. doxygenfunction:: pcnt_get_counter_value
.. doxygenfunction:: pcnt_counter_pause
.. doxygenfunction:: pcnt_counter_resume
.. doxygenfunction:: pcnt_counter_clear
.. doxygenfunction:: pcnt_intr_enable
.. doxygenfunction:: pcnt_intr_disable
.. doxygenfunction:: pcnt_event_enable
.. doxygenfunction:: pcnt_event_disable
.. doxygenfunction:: pcnt_set_event_value
.. doxygenfunction:: pcnt_get_event_value
.. doxygenfunction:: pcnt_isr_register
.. doxygenfunction:: pcnt_set_pin
.. doxygenfunction:: pcnt_filter_enable
.. doxygenfunction:: pcnt_filter_disable
.. doxygenfunction:: pcnt_set_filter_value
.. doxygenfunction:: pcnt_get_filter_value
.. doxygenfunction:: pcnt_set_mode

View file

@ -102,6 +102,7 @@ Contents:
api/uart
api/ledc
api/rmt
Pulse Counter <api/pcnt>
SPI Flash and Partition APIs <api/spi_flash>
Logging <api/log>
Non-Volatile Storage <api/nvs_flash>

View file

@ -0,0 +1,9 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := pcnt
include $(IDF_PATH)/make/project.mk

View file

@ -0,0 +1,3 @@
#
# Main Makefile. This is basically the same as a component makefile.
#

View file

@ -0,0 +1,226 @@
/* Pulse counter module - Example
For other examples please check:
https://github.com/espressif/esp-idf/tree/master/examples
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/portmacro.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/periph_ctrl.h"
#include "driver/ledc.h"
#include "driver/gpio.h"
#include "driver/pcnt.h"
#include "esp_attr.h"
#include "esp_log.h"
#include "soc/gpio_sig_map.h"
/**
* TEST CODE BRIEF
* Use PCNT module to count rising edges generated by LEDC module.
* GPIO18 is used as output pin, GPIO4 is used as pulse input pin and GPIO5 is used as control input pin
*
* Open serial port to view the message printed on your screen
*
* To do this test, you should connect GPIO18 with GPIO4
* GPIO5 is the control signal, you can leave it floating with internal pulled up, or connect it to ground.
* If you connect gpio5 to GND ,you will found the count value decreasing.
*
* When counter value reaches thresh1 or thresh0 value, it will trigger interrupt.
* When counter value reaches l_lim value or h_lim value, counter value will be reset to zero and trigger interrupt.
*/
static const char* TAG = "PCNT_TEST";
#define PCNT_TEST_UNIT PCNT_UNIT_0
#define PCNT_H_LIM_VAL (10)
#define PCNT_L_LIM_VAL (-10)
#define PCNT_THRESH1_VAL (5)
#define PCNT_THRESH0_VAL (-5)
#define PCNT_INTR_NUM (18)
#define PCNT_INPUT_SIG_IO (4)
#define PCNT_INPUT_CTRL_IO (5)
#define LEDC_OUPUT_IO (18)
xQueueHandle pcnt_evt_queue; /*A queue to handle pulse counter event*/
typedef struct {
int unit; /*pulse counter unit*/
uint32_t status; /*pulse counter internal status*/
} pcnt_evt_t;
void IRAM_ATTR pcnt_intr_handler(void* arg)
{
uint32_t intr_status = PCNT.int_st.val;
int i;
pcnt_evt_t evt;
portBASE_TYPE HPTaskAwoken = pdFALSE;
for(i = 0; i < PCNT_UNIT_MAX; i++) {
if(intr_status & (BIT(i))) {
evt.unit = i;
evt.status = PCNT.status_unit[i].val;
PCNT.int_clr.val = BIT(i);
/*H LIM EVT*/
if(PCNT.status_unit[i].h_lim_lat) {
//do something
}
/*L LIM EVT*/
if(PCNT.status_unit[i].l_lim_lat) {
//do something
}
/*THRES0 EVT*/
if(PCNT.status_unit[i].thres0_lat) {
//do something
}
/*THRES1 EVT*/
if(PCNT.status_unit[i].thres1_lat) {
//do something
}
/*ZERO EVT*/
if(PCNT.status_unit[i].zero_lat) {
//do something
}
xQueueSendFromISR(pcnt_evt_queue, &evt, &HPTaskAwoken);
if(HPTaskAwoken == pdTRUE) {
portYIELD_FROM_ISR();
}
}
}
}
static void ledc_init(void)
{
ledc_channel_config_t ledc_channel;
/*use GPIO18 as output pin*/
ledc_channel.gpio_num = LEDC_OUPUT_IO;
/*LEDC high speed mode */
ledc_channel.speed_mode = LEDC_HIGH_SPEED_MODE;
/*use LEDC channel 1*/
ledc_channel.channel = LEDC_CHANNEL_1;
/*Disable LEDC interrupt*/
ledc_channel.intr_type = LEDC_INTR_DISABLE;
/*Select LEDC timer 1 */
ledc_channel.timer_sel = LEDC_TIMER_1;
/*Set duty 100 */
ledc_channel.duty = 100;
ledc_channel_config(&ledc_channel); //ledc config
ledc_timer_config_t ledc_timer;
/*LEDC timer high speed mode*/
ledc_timer.speed_mode = LEDC_HIGH_SPEED_MODE;
/*10 bit PWM*/
ledc_timer.bit_num = LEDC_TIMER_10_BIT;
/*Select timer 1*/
ledc_timer.timer_num = LEDC_TIMER_1;
/*Set frequency 1 Hz */
ledc_timer.freq_hz = 1;
ledc_timer_config(&ledc_timer);
}
static void pcnt_init(void)
{
pcnt_config_t pcnt_config = {
/*Set GPIO4 as pulse input gpio */
.pulse_gpio_num = PCNT_INPUT_SIG_IO,
/*set gpio5 as control gpio */
.ctrl_gpio_num = PCNT_INPUT_CTRL_IO,
/*Choose channel 0 */
.channel = PCNT_CHANNEL_0,
/*Choose unit 0 */
.unit = PCNT_TEST_UNIT,
/*Set counter and control mode*/
/*Counter increase for positive edge on pulse input GPIO*/
.pos_mode = PCNT_COUNT_INC,
/*Counter decrease for negative edge on pulse input GPIO*/
.neg_mode = PCNT_COUNT_DIS, //keep the counter value
/*Counter mode reverse when control input is low level*/
.lctrl_mode = PCNT_MODE_REVERSE,
/*Counter mode does not change when control input is high level*/
.hctrl_mode = PCNT_MODE_KEEP, //when control signal is high,keep the primary counter mode
/*Set maximum value for increasing counter*/
.counter_h_lim = PCNT_H_LIM_VAL,
/*Set minimum value for decreasing counter*/
.counter_l_lim = PCNT_L_LIM_VAL,
};
/*Initialize PCNT unit */
pcnt_unit_config(&pcnt_config);
/*Configure input filter value*/
pcnt_set_filter_value(PCNT_TEST_UNIT, 100);
/*Enable input filter*/
pcnt_filter_enable(PCNT_TEST_UNIT);
/*Set value for watch point thresh1*/
pcnt_set_event_value(PCNT_TEST_UNIT, PCNT_EVT_THRES_1, PCNT_THRESH1_VAL);
/*Enable watch point event of thresh1*/
pcnt_event_enable(PCNT_TEST_UNIT, PCNT_EVT_THRES_1);
/*Set value for watch point thresh0*/
pcnt_set_event_value(PCNT_TEST_UNIT, PCNT_EVT_THRES_0, PCNT_THRESH0_VAL);
/*Enable watch point event of thresh0*/
pcnt_event_enable(PCNT_TEST_UNIT, PCNT_EVT_THRES_0);
/*Enable watch point event of h_lim*/
pcnt_event_enable(PCNT_TEST_UNIT, PCNT_EVT_H_LIM);
/*Enable watch point event of l_lim*/
pcnt_event_enable(PCNT_TEST_UNIT, PCNT_EVT_L_LIM);
/*Enable watch point event of zero*/
pcnt_event_enable(PCNT_TEST_UNIT, PCNT_EVT_ZERO);
/*Pause counter*/
pcnt_counter_pause(PCNT_TEST_UNIT);
/*Reset counter value*/
pcnt_counter_clear(PCNT_TEST_UNIT);
/*Register ISR handler*/
pcnt_isr_register(PCNT_INTR_NUM, pcnt_intr_handler, NULL);
/*Enable interrupt for PCNT unit*/
pcnt_intr_enable(PCNT_TEST_UNIT);
/*Resume counting*/
pcnt_counter_resume(PCNT_TEST_UNIT);
}
void app_main()
{
/*Init LEDC for pulse input signal */
ledc_init();
/*Init PCNT event queue */
pcnt_evt_queue = xQueueCreate(10, sizeof(pcnt_evt_t));
/*Init PCNT functions*/
pcnt_init();
int16_t count = 0;
pcnt_evt_t evt;
portBASE_TYPE res;
while(1)
{
res = xQueueReceive(pcnt_evt_queue, &evt, 1000 / portTICK_RATE_MS);
if(res == pdTRUE) {
pcnt_get_counter_value(PCNT_TEST_UNIT, &count);
printf("Event PCNT unit[%d]; cnt: %d\n", evt.unit, count);
if(evt.status & PCNT_STATUS_THRES1_M) {
printf("THRES1 EVT\n");
}
if(evt.status & PCNT_STATUS_THRES0_M) {
printf("THRES0 EVT\n");
}
if(evt.status & PCNT_STATUS_L_LIM_M) {
printf("L_LIM EVT\n");
}
if(evt.status & PCNT_STATUS_H_LIM_M) {
printf("H_LIM EVT\n");
}
if(evt.status & PCNT_STATUS_ZERO_M) {
printf("ZERO EVT\n");
}
} else {
pcnt_get_counter_value(PCNT_TEST_UNIT, &count);
printf("Current counter value :%d\n", count);
}
}
}