pcnt: deprecated as legacy driver

This commit is contained in:
morris 2022-01-17 14:44:55 +08:00
parent ec8defaa96
commit 04b3f8b210
17 changed files with 231 additions and 398 deletions

View File

@ -1,109 +1,23 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "freertos/FreeRTOS.h"
#include "esp_types.h"
#include "sdkconfig.h"
#include "esp_err.h"
#include "esp_intr_alloc.h"
#include "driver/gpio.h"
#include "soc/soc_caps.h"
#include "hal/pcnt_types.h"
#include "driver/pcnt_types_legacy.h"
#if !CONFIG_PCNT_SUPPRESS_DEPRECATE_WARN
#warning "legacy pcnt driver is deprecated, please migrate to use driver/pulse_cnt.h"
#endif
#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

View File

@ -0,0 +1,108 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_intr_alloc.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 */
/**
* @brief PCNT interrupt handle
*/
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;
#ifdef __cplusplus
}
#endif

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -8,7 +8,8 @@
#include "esp_check.h"
#include "soc/soc_caps.h"
#include "esp_private/periph_ctrl.h"
#include "driver/pcnt.h"
#include "driver/pcnt_types_legacy.h"
#include "driver/gpio.h"
#include "hal/pcnt_hal.h"
#include "hal/pcnt_ll.h"
#include "hal/gpio_hal.h"
@ -54,6 +55,9 @@ static pcnt_isr_func_t *pcnt_isr_func = NULL;
static pcnt_isr_handle_t pcnt_isr_service = NULL;
static portMUX_TYPE pcnt_spinlock = portMUX_INITIALIZER_UNLOCKED;
esp_err_t pcnt_isr_register(void (*fun)(void *), void *arg, int intr_alloc_flags, pcnt_isr_handle_t *handle);
esp_err_t pcnt_isr_unregister(pcnt_isr_handle_t handle);
static inline esp_err_t _pcnt_set_mode(pcnt_port_t pcnt_port, 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_OBJ_CHECK(pcnt_port);
@ -537,7 +541,22 @@ esp_err_t pcnt_isr_service_install(int intr_alloc_flags)
return _pcnt_isr_service_install(PCNT_PORT_0, intr_alloc_flags);
}
void pcnt_isr_service_uninstall()
void pcnt_isr_service_uninstall(void)
{
_pcnt_isr_service_uninstall(PCNT_PORT_0);
}
/**
* @brief This function will be called during start up, to check that pulse_cnt driver is not running along with the legacy pcnt driver
*/
__attribute__((constructor))
static void check_pcnt_driver_conflict(void)
{
extern int pcnt_driver_init_count;
pcnt_driver_init_count++;
if (pcnt_driver_init_count > 1) {
ESP_EARLY_LOGE(TAG, "CONFLICT! The pulse_cnt driver can't work along with the legacy pcnt driver");
abort();
}
ESP_EARLY_LOGW(TAG, "legacy pcnt driver is deprecated, please migrate to use driver/pulse_cnt.h");
}

View File

@ -0,0 +1,5 @@
# This is the project CMakeLists.txt file for the test subproject
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(legacy_pcnt_driver_test)

View File

@ -0,0 +1,2 @@
| Supported Targets | ESP32 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- |

View File

@ -0,0 +1,6 @@
set(srcs "test_app_main.c"
"test_legacy_pcnt.c")
idf_component_register(SRCS ${srcs})
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u test_app_include_legacy_pcnt")

View File

@ -0,0 +1,40 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "unity.h"
#include "unity_test_runner.h"
#include "esp_heap_caps.h"
#define TEST_MEMORY_LEAK_THRESHOLD (-300)
static size_t before_free_8bit;
static size_t before_free_32bit;
static void check_leak(size_t before_free, size_t after_free, const char *type)
{
ssize_t delta = after_free - before_free;
printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta);
TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak");
}
void setUp(void)
{
before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
}
void tearDown(void)
{
size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
check_leak(before_free_8bit, after_free_8bit, "8BIT");
check_leak(before_free_32bit, after_free_32bit, "32BIT");
}
void app_main(void)
{
unity_run_menu();
}

View File

@ -3,24 +3,12 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* this case is used for test PCNT
* prepare job for test environment UT_T1_PCNT:
* We use internal signals instead of external wiring, but please keep the following IO connections, or connect nothing to prevent the signal from being disturbed.
* 1. prepare one ESP-WROOM-32 board and connect it to PC.
* 2. connect GPIO21 with GPIO4
* 3. GPIO5 connect to 3.3v
* 4. GPIO19 connect to GND
* 5. logic analyzer will help too if possible
*
* the GPIO18 is the pulse producer, the GPIO4 is the input GPIO
*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "soc/soc_caps.h"
#if SOC_PCNT_SUPPORTED
#include "driver/gpio.h"
#include "driver/pcnt.h"
#include "driver/ledc.h"
@ -317,7 +305,7 @@ static void count_mode_test(gpio_num_t ctl_io)
}
// test PCNT basic configuration
TEST_CASE("PCNT test config", "[pcnt]")
TEST_CASE("PCNT_test_config", "[pcnt]")
{
pcnt_config_t pcnt_config = {
.pulse_gpio_num = PCNT_INPUT_IO,
@ -380,7 +368,7 @@ TEST_CASE("PCNT test config", "[pcnt]")
* 2. resume counter
* 3. clear counter
* 4. check the counter value*/
TEST_CASE("PCNT basic function test", "[pcnt]")
TEST_CASE("PCNT_basic_function_test", "[pcnt]")
{
int16_t test_counter;
int16_t time = 0;
@ -469,7 +457,7 @@ TEST_CASE("PCNT basic function test", "[pcnt]")
* 4. PCNT_EVT_H_LIM
* 5. PCNT_EVT_L_LIM
* */
TEST_CASE("PCNT interrupt method test(control IO is high)", "[pcnt][timeout=120]")
TEST_CASE("PCNT_interrupt_method_test_control_IO_high", "[pcnt][timeout=120]")
{
pcnt_config_t config = {
.pulse_gpio_num = PCNT_INPUT_IO,
@ -569,7 +557,7 @@ TEST_CASE("PCNT interrupt method test(control IO is high)", "[pcnt][timeout=120]
vQueueDelete(pcnt_evt_queue);
}
TEST_CASE("PCNT interrupt method test(control IO is low)", "[pcnt][timeout=120]")
TEST_CASE("PCNT_interrupt_method_test_control_IO_low", "[pcnt][timeout=120]")
{
pcnt_config_t config = {
.pulse_gpio_num = PCNT_INPUT_IO,
@ -671,7 +659,7 @@ TEST_CASE("PCNT interrupt method test(control IO is low)", "[pcnt][timeout=120]"
vQueueDelete(pcnt_evt_queue);
}
TEST_CASE("PCNT counting mode test", "[pcnt]")
TEST_CASE("PCNT_counting_mode_test", "[pcnt]")
{
printf("PCNT mode test for positive count\n");
count_mode_test(PCNT_CTRL_VCC_IO);
@ -679,4 +667,6 @@ TEST_CASE("PCNT counting mode test", "[pcnt]")
count_mode_test(PCNT_CTRL_GND_IO);
}
#endif // #if SOC_PCNT_SUPPORTED
void test_app_include_legacy_pcnt(void)
{
}

View File

@ -0,0 +1,22 @@
# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
from pytest_embedded import Dut
@pytest.mark.esp32
@pytest.mark.esp32s2
@pytest.mark.esp32s3
@pytest.mark.generic
@pytest.mark.parametrize(
'config',
[
'release',
],
indirect=True,
)
def test_gptimer(dut: Dut) -> None:
dut.expect_exact('Press ENTER to see the list of tests')
dut.write('*')
dut.expect_unity_test_output(timeout=240)

View File

@ -0,0 +1,5 @@
CONFIG_PM_ENABLE=y
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y

View File

@ -0,0 +1,3 @@
CONFIG_FREERTOS_HZ=1000
CONFIG_ESP_TASK_WDT=n
CONFIG_PCNT_SUPPRESS_DEPRECATE_WARN=y

View File

@ -1,7 +1,6 @@
set(srcs "test_app_main.c"
"test_legacy_timer.c")
idf_component_register(SRCS ${srcs}
PRIV_REQUIRES driver unity)
idf_component_register(SRCS ${srcs})
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u test_app_include_legacy_timer")

View File

@ -11,6 +11,6 @@ from pytest_embedded import Dut
'release',
], indirect=True)
def test_legacy_timer_driver(dut: Dut) -> None:
dut.expect('Press ENTER to see the list of tests')
dut.expect_exact('Press ENTER to see the list of tests')
dut.write('*')
dut.expect_unity_test_output(timeout=120)

View File

@ -1,6 +0,0 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(pcnt_event)

View File

@ -1,75 +0,0 @@
| Supported Targets | ESP32 | ESP32-S2 |
| ----------------- | ----- | -------- |
# Pulse Count Event Example
(See the README.md file in the upper level 'examples' directory for more information about examples.)
This example uses the pulse counter module (PCNT) to count the rising edges of the PWM pulses generated by the LED Controller module (LEDC).
## How to use example
### Hardware Required
* A development board with ESP32 SoC (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.)
* A USB cable for power supply and programming
Pin connection:
* GPIO4 is the default output GPIO of the 1 Hz pulse generator.
* GPIO18 is the default pulse input GPIO. We need to short GPIO4 and GPIO18.
* GPIO5 is the default control signal, which can be left floating with internal pull up, or connected to Ground (If GPIO5 is left floating, the value of counter increases with the rising edges of the PWM pulses. If GPIO5 is connected to Ground, the value decreases).
### Configure the project
```
idf.py menuconfig
```
### Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output:
```
idf.py -p PORT flash monitor
```
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
## Example Output
Run this example, and you can see the following output log on the serial monitor:
(Here, GPIO5 is connected to Ground)
```
Current counter value :-1
Current counter value :-2
Current counter value :-3
Current counter value :-4
Event PCNT unit[0]; cnt: -5
THRES0 EVT
Current counter value :-5
Current counter value :-6
Current counter value :-7
Current counter value :-8
Current counter value :-9
Event PCNT unit[0]; cnt: 0
L_LIM EVT
ZERO EVT
Current counter value :0
Current counter value :-1
...
```
## Troubleshooting
* program upload failure
* Hardware connection is not correct: run `idf.py -p PORT monitor`, and reboot your board to see if there are any output logs.
* The baud rate for downloading is too high: lower your baud rate in the `menuconfig` menu, and try again.
For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.

View File

@ -1,2 +0,0 @@
idf_component_register(SRCS "pcnt_event_example_main.c"
INCLUDE_DIRS ".")

View File

@ -1,197 +0,0 @@
/* 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 "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/ledc.h"
#include "driver/pcnt.h"
#include "esp_attr.h"
#include "esp_log.h"
static const char *TAG = "example";
/**
* TEST CODE BRIEF
*
* Use PCNT module to count rising edges generated by LEDC module.
*
* Functionality of GPIOs used in this example:
* - GPIO18 - output pin of a sample 1 Hz pulse generator,
* - GPIO4 - pulse input pin,
* - GPIO5 - control input pin.
*
* Load example, open a 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 pull up,
* or connect it to ground. If left floating, the count value will be increasing.
* If you connect GPIO5 to GND, the count value will be decreasing.
*
* An interrupt will be triggered when the counter value:
* - reaches 'thresh1' or 'thresh0' value,
* - reaches 'l_lim' value or 'h_lim' value,
* - will be reset to zero.
*/
#define PCNT_H_LIM_VAL 10
#define PCNT_L_LIM_VAL -10
#define PCNT_THRESH1_VAL 5
#define PCNT_THRESH0_VAL -5
#define PCNT_INPUT_SIG_IO 4 // Pulse Input GPIO
#define PCNT_INPUT_CTRL_IO 5 // Control GPIO HIGH=count up, LOW=count down
#define LEDC_OUTPUT_IO 18 // Output GPIO of a sample 1 Hz pulse generator
QueueHandle_t pcnt_evt_queue; // A queue to handle pulse counter events
/* A sample structure to pass events from the PCNT
* interrupt handler to the main program.
*/
typedef struct {
int unit; // the PCNT unit that originated an interrupt
uint32_t status; // information on the event type that caused the interrupt
} pcnt_evt_t;
/* Decode what PCNT's unit originated an interrupt
* and pass this information together with the event type
* the main program using a queue.
*/
static void IRAM_ATTR pcnt_example_intr_handler(void *arg)
{
int pcnt_unit = (int)arg;
pcnt_evt_t evt;
evt.unit = pcnt_unit;
/* Save the PCNT event type that caused an interrupt
to pass it to the main program */
pcnt_get_event_status(pcnt_unit, &evt.status);
xQueueSendFromISR(pcnt_evt_queue, &evt, NULL);
}
/* Configure LED PWM Controller
* to output sample pulses at 1 Hz with duty of about 10%
*/
static void ledc_init(void)
{
// Prepare and then apply the LEDC PWM timer configuration
ledc_timer_config_t ledc_timer;
ledc_timer.speed_mode = LEDC_LOW_SPEED_MODE;
ledc_timer.timer_num = LEDC_TIMER_1;
ledc_timer.duty_resolution = LEDC_TIMER_10_BIT;
ledc_timer.freq_hz = 1; // set output frequency at 1 Hz
ledc_timer.clk_cfg = LEDC_AUTO_CLK;
ledc_timer_config(&ledc_timer);
// Prepare and then apply the LEDC PWM channel configuration
ledc_channel_config_t ledc_channel;
ledc_channel.speed_mode = LEDC_LOW_SPEED_MODE;
ledc_channel.channel = LEDC_CHANNEL_1;
ledc_channel.timer_sel = LEDC_TIMER_1;
ledc_channel.intr_type = LEDC_INTR_DISABLE;
ledc_channel.gpio_num = LEDC_OUTPUT_IO;
ledc_channel.duty = 100; // set duty at about 10%
ledc_channel.hpoint = 0;
ledc_channel_config(&ledc_channel);
}
/* Initialize PCNT functions:
* - configure and initialize PCNT
* - set up the input filter
* - set up the counter events to watch
*/
static void pcnt_example_init(int unit)
{
/* Prepare configuration for the PCNT unit */
pcnt_config_t pcnt_config = {
// Set PCNT input signal and control GPIOs
.pulse_gpio_num = PCNT_INPUT_SIG_IO,
.ctrl_gpio_num = PCNT_INPUT_CTRL_IO,
.channel = PCNT_CHANNEL_0,
.unit = unit,
// What to do on the positive / negative edge of pulse input?
.pos_mode = PCNT_COUNT_INC, // Count up on the positive edge
.neg_mode = PCNT_COUNT_DIS, // Keep the counter value on the negative edge
// What to do when control input is low or high?
.lctrl_mode = PCNT_MODE_REVERSE, // Reverse counting direction if low
.hctrl_mode = PCNT_MODE_KEEP, // Keep the primary counter mode if high
// Set the maximum and minimum limit values to watch
.counter_h_lim = PCNT_H_LIM_VAL,
.counter_l_lim = PCNT_L_LIM_VAL,
};
/* Initialize PCNT unit */
pcnt_unit_config(&pcnt_config);
/* Configure and enable the input filter */
pcnt_set_filter_value(unit, 100);
pcnt_filter_enable(unit);
/* Set threshold 0 and 1 values and enable events to watch */
pcnt_set_event_value(unit, PCNT_EVT_THRES_1, PCNT_THRESH1_VAL);
pcnt_event_enable(unit, PCNT_EVT_THRES_1);
pcnt_set_event_value(unit, PCNT_EVT_THRES_0, PCNT_THRESH0_VAL);
pcnt_event_enable(unit, PCNT_EVT_THRES_0);
/* Enable events on zero, maximum and minimum limit values */
pcnt_event_enable(unit, PCNT_EVT_ZERO);
pcnt_event_enable(unit, PCNT_EVT_H_LIM);
pcnt_event_enable(unit, PCNT_EVT_L_LIM);
/* Initialize PCNT's counter */
pcnt_counter_pause(unit);
pcnt_counter_clear(unit);
/* Install interrupt service and add isr callback handler */
pcnt_isr_service_install(0);
pcnt_isr_handler_add(unit, pcnt_example_intr_handler, (void *)unit);
/* Everything is set up, now go to counting */
pcnt_counter_resume(unit);
}
void app_main(void)
{
int pcnt_unit = PCNT_UNIT_0;
/* Initialize LEDC to generate sample pulse signal */
ledc_init();
/* Initialize PCNT event queue and PCNT functions */
pcnt_evt_queue = xQueueCreate(10, sizeof(pcnt_evt_t));
pcnt_example_init(pcnt_unit);
int16_t count = 0;
pcnt_evt_t evt;
portBASE_TYPE res;
while (1) {
/* Wait for the event information passed from PCNT's interrupt handler.
* Once received, decode the event type and print it on the serial monitor.
*/
res = xQueueReceive(pcnt_evt_queue, &evt, 1000 / portTICK_PERIOD_MS);
if (res == pdTRUE) {
pcnt_get_counter_value(pcnt_unit, &count);
ESP_LOGI(TAG, "Event PCNT unit[%d]; cnt: %d", evt.unit, count);
if (evt.status & PCNT_EVT_THRES_1) {
ESP_LOGI(TAG, "THRES1 EVT");
}
if (evt.status & PCNT_EVT_THRES_0) {
ESP_LOGI(TAG, "THRES0 EVT");
}
if (evt.status & PCNT_EVT_L_LIM) {
ESP_LOGI(TAG, "L_LIM EVT");
}
if (evt.status & PCNT_EVT_H_LIM) {
ESP_LOGI(TAG, "H_LIM EVT");
}
if (evt.status & PCNT_EVT_ZERO) {
ESP_LOGI(TAG, "ZERO EVT");
}
} else {
pcnt_get_counter_value(pcnt_unit, &count);
ESP_LOGI(TAG, "Current counter value :%d", count);
}
}
}