mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-07 06:34:34 +02:00
Merge branch 'feature/support_pcnt_on_h2' into 'master'
pcnt: support pcnt on esp32h2 Closes IDF-6221 and IDF-6669 See merge request espressif/esp-idf!21950
This commit is contained in:
@@ -11,7 +11,9 @@
|
|||||||
#include "soc/soc_caps.h"
|
#include "soc/soc_caps.h"
|
||||||
#include "driver/gpio.h"
|
#include "driver/gpio.h"
|
||||||
#include "driver/pcnt.h"
|
#include "driver/pcnt.h"
|
||||||
|
#if SOC_LEDC_SUPPORTED
|
||||||
#include "driver/ledc.h"
|
#include "driver/ledc.h"
|
||||||
|
#endif
|
||||||
#include "esp_attr.h"
|
#include "esp_attr.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "soc/gpio_periph.h"
|
#include "soc/gpio_periph.h"
|
||||||
@@ -30,6 +32,9 @@
|
|||||||
#define PCNT_CTRL_HIGH_LEVEL 1
|
#define PCNT_CTRL_HIGH_LEVEL 1
|
||||||
#define PCNT_CTRL_LOW_LEVEL 0
|
#define PCNT_CTRL_LOW_LEVEL 0
|
||||||
|
|
||||||
|
// The following items only used in the cases that involve LEDC
|
||||||
|
#if SOC_LEDC_SUPPORTED
|
||||||
|
|
||||||
static QueueHandle_t pcnt_evt_queue = NULL;
|
static QueueHandle_t pcnt_evt_queue = NULL;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -40,6 +45,69 @@ typedef struct {
|
|||||||
int l_threshold;
|
int l_threshold;
|
||||||
int filter_time;
|
int filter_time;
|
||||||
} event_times;
|
} event_times;
|
||||||
|
#endif // SOC_LEDC_SUPPORTED
|
||||||
|
|
||||||
|
// test PCNT basic configuration
|
||||||
|
TEST_CASE("PCNT_test_config", "[pcnt]")
|
||||||
|
{
|
||||||
|
pcnt_config_t pcnt_config = {
|
||||||
|
.pulse_gpio_num = PCNT_INPUT_IO,
|
||||||
|
.ctrl_gpio_num = PCNT_CTRL_VCC_IO,
|
||||||
|
.channel = PCNT_CHANNEL_0,
|
||||||
|
.unit = PCNT_UNIT_0,
|
||||||
|
.pos_mode = PCNT_COUNT_INC,
|
||||||
|
.neg_mode = PCNT_COUNT_DIS,
|
||||||
|
.lctrl_mode = PCNT_MODE_REVERSE,
|
||||||
|
.hctrl_mode = PCNT_MODE_KEEP,
|
||||||
|
.counter_h_lim = 100,
|
||||||
|
.counter_l_lim = 0,
|
||||||
|
};
|
||||||
|
// basic configuration
|
||||||
|
pcnt_config_t temp_pcnt_config = pcnt_config;
|
||||||
|
TEST_ESP_OK(pcnt_unit_config(&pcnt_config));
|
||||||
|
|
||||||
|
// test SOC_PCNT_UNITS_PER_GROUP units, from 0-(SOC_PCNT_UNITS_PER_GROUP-1)
|
||||||
|
pcnt_config = temp_pcnt_config;
|
||||||
|
pcnt_config.unit = SOC_PCNT_UNITS_PER_GROUP;
|
||||||
|
TEST_ASSERT_NOT_NULL((void *)pcnt_unit_config(&pcnt_config));
|
||||||
|
for (int i = 0; i < SOC_PCNT_UNITS_PER_GROUP; i++) {
|
||||||
|
pcnt_config.unit = i;
|
||||||
|
TEST_ESP_OK(pcnt_unit_config(&pcnt_config));
|
||||||
|
}
|
||||||
|
|
||||||
|
// test channels
|
||||||
|
pcnt_config = temp_pcnt_config;
|
||||||
|
pcnt_config.channel = PCNT_CHANNEL_MAX;
|
||||||
|
TEST_ASSERT_NOT_NULL((void *)pcnt_unit_config(&pcnt_config));
|
||||||
|
pcnt_config = temp_pcnt_config;
|
||||||
|
pcnt_config.pulse_gpio_num = -1;
|
||||||
|
TEST_ESP_OK(pcnt_unit_config(&pcnt_config));
|
||||||
|
|
||||||
|
pcnt_config = temp_pcnt_config;
|
||||||
|
pcnt_config.pulse_gpio_num = GPIO_NUM_MAX + 1;
|
||||||
|
TEST_ASSERT_NOT_NULL((void *)pcnt_unit_config(&pcnt_config));
|
||||||
|
|
||||||
|
// test pulse_gpio_num and ctrl_gpio_num is the same
|
||||||
|
pcnt_config = temp_pcnt_config;
|
||||||
|
pcnt_config.pulse_gpio_num = PCNT_INPUT_IO;
|
||||||
|
pcnt_config.ctrl_gpio_num = PCNT_INPUT_IO;
|
||||||
|
TEST_ASSERT_NOT_NULL((void *)pcnt_unit_config(&pcnt_config));
|
||||||
|
|
||||||
|
pcnt_config = temp_pcnt_config;
|
||||||
|
pcnt_config.pos_mode = PCNT_COUNT_MAX;
|
||||||
|
TEST_ASSERT_NOT_NULL((void *)pcnt_unit_config(&pcnt_config));
|
||||||
|
|
||||||
|
pcnt_config = temp_pcnt_config;
|
||||||
|
pcnt_config.hctrl_mode = PCNT_MODE_MAX;
|
||||||
|
TEST_ASSERT_NOT_NULL((void *)pcnt_unit_config(&pcnt_config));
|
||||||
|
|
||||||
|
pcnt_config = temp_pcnt_config;
|
||||||
|
pcnt_config.lctrl_mode = PCNT_MODE_MAX;
|
||||||
|
TEST_ASSERT_NOT_NULL((void *)pcnt_unit_config(&pcnt_config));
|
||||||
|
}
|
||||||
|
|
||||||
|
// The following test cases rely on the support of LEDC
|
||||||
|
#if SOC_LEDC_SUPPORTED
|
||||||
|
|
||||||
static void pcnt_test_io_config(int ctrl_level)
|
static void pcnt_test_io_config(int ctrl_level)
|
||||||
{
|
{
|
||||||
@@ -304,65 +372,6 @@ static void count_mode_test(gpio_num_t ctl_io)
|
|||||||
TEST_ASSERT_INT16_WITHIN(1, test_counter, result[7]);
|
TEST_ASSERT_INT16_WITHIN(1, test_counter, result[7]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// test PCNT basic configuration
|
|
||||||
TEST_CASE("PCNT_test_config", "[pcnt]")
|
|
||||||
{
|
|
||||||
pcnt_config_t pcnt_config = {
|
|
||||||
.pulse_gpio_num = PCNT_INPUT_IO,
|
|
||||||
.ctrl_gpio_num = PCNT_CTRL_VCC_IO,
|
|
||||||
.channel = PCNT_CHANNEL_0,
|
|
||||||
.unit = PCNT_UNIT_0,
|
|
||||||
.pos_mode = PCNT_COUNT_INC,
|
|
||||||
.neg_mode = PCNT_COUNT_DIS,
|
|
||||||
.lctrl_mode = PCNT_MODE_REVERSE,
|
|
||||||
.hctrl_mode = PCNT_MODE_KEEP,
|
|
||||||
.counter_h_lim = 100,
|
|
||||||
.counter_l_lim = 0,
|
|
||||||
};
|
|
||||||
// basic configuration
|
|
||||||
pcnt_config_t temp_pcnt_config = pcnt_config;
|
|
||||||
TEST_ESP_OK(pcnt_unit_config(&pcnt_config));
|
|
||||||
|
|
||||||
// test SOC_PCNT_UNITS_PER_GROUP units, from 0-(SOC_PCNT_UNITS_PER_GROUP-1)
|
|
||||||
pcnt_config = temp_pcnt_config;
|
|
||||||
pcnt_config.unit = SOC_PCNT_UNITS_PER_GROUP;
|
|
||||||
TEST_ASSERT_NOT_NULL((void *)pcnt_unit_config(&pcnt_config));
|
|
||||||
for (int i = 0; i < SOC_PCNT_UNITS_PER_GROUP; i++) {
|
|
||||||
pcnt_config.unit = i;
|
|
||||||
TEST_ESP_OK(pcnt_unit_config(&pcnt_config));
|
|
||||||
}
|
|
||||||
|
|
||||||
// test channels
|
|
||||||
pcnt_config = temp_pcnt_config;
|
|
||||||
pcnt_config.channel = PCNT_CHANNEL_MAX;
|
|
||||||
TEST_ASSERT_NOT_NULL((void *)pcnt_unit_config(&pcnt_config));
|
|
||||||
pcnt_config = temp_pcnt_config;
|
|
||||||
pcnt_config.pulse_gpio_num = -1;
|
|
||||||
TEST_ESP_OK(pcnt_unit_config(&pcnt_config));
|
|
||||||
|
|
||||||
pcnt_config = temp_pcnt_config;
|
|
||||||
pcnt_config.pulse_gpio_num = GPIO_NUM_MAX + 1;
|
|
||||||
TEST_ASSERT_NOT_NULL((void *)pcnt_unit_config(&pcnt_config));
|
|
||||||
|
|
||||||
// test pulse_gpio_num and ctrl_gpio_num is the same
|
|
||||||
pcnt_config = temp_pcnt_config;
|
|
||||||
pcnt_config.pulse_gpio_num = PCNT_INPUT_IO;
|
|
||||||
pcnt_config.ctrl_gpio_num = PCNT_INPUT_IO;
|
|
||||||
TEST_ASSERT_NOT_NULL((void *)pcnt_unit_config(&pcnt_config));
|
|
||||||
|
|
||||||
pcnt_config = temp_pcnt_config;
|
|
||||||
pcnt_config.pos_mode = PCNT_COUNT_MAX;
|
|
||||||
TEST_ASSERT_NOT_NULL((void *)pcnt_unit_config(&pcnt_config));
|
|
||||||
|
|
||||||
pcnt_config = temp_pcnt_config;
|
|
||||||
pcnt_config.hctrl_mode = PCNT_MODE_MAX;
|
|
||||||
TEST_ASSERT_NOT_NULL((void *)pcnt_unit_config(&pcnt_config));
|
|
||||||
|
|
||||||
pcnt_config = temp_pcnt_config;
|
|
||||||
pcnt_config.lctrl_mode = PCNT_MODE_MAX;
|
|
||||||
TEST_ASSERT_NOT_NULL((void *)pcnt_unit_config(&pcnt_config));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* PCNT basic property:
|
/* PCNT basic property:
|
||||||
* 1. pause counter
|
* 1. pause counter
|
||||||
* 2. resume counter
|
* 2. resume counter
|
||||||
@@ -666,3 +675,4 @@ TEST_CASE("PCNT_counting_mode_test", "[pcnt]")
|
|||||||
printf("PCNT mode test for negative count\n");
|
printf("PCNT mode test for negative count\n");
|
||||||
count_mode_test(PCNT_CTRL_GND_IO);
|
count_mode_test(PCNT_CTRL_GND_IO);
|
||||||
}
|
}
|
||||||
|
#endif // SOC_LEDC_SUPPORTED
|
||||||
|
@@ -9,6 +9,7 @@ from pytest_embedded import Dut
|
|||||||
@pytest.mark.esp32s2
|
@pytest.mark.esp32s2
|
||||||
@pytest.mark.esp32s3
|
@pytest.mark.esp32s3
|
||||||
@pytest.mark.esp32c6
|
@pytest.mark.esp32c6
|
||||||
|
# @pytest.mark.esp32h2 # TODO: IDF-6263, IDF-6235
|
||||||
@pytest.mark.generic
|
@pytest.mark.generic
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
'config',
|
'config',
|
||||||
|
@@ -9,6 +9,7 @@ from pytest_embedded import Dut
|
|||||||
@pytest.mark.esp32s2
|
@pytest.mark.esp32s2
|
||||||
@pytest.mark.esp32s3
|
@pytest.mark.esp32s3
|
||||||
@pytest.mark.esp32c6
|
@pytest.mark.esp32c6
|
||||||
|
# @pytest.mark.esp32h2 # TODO: IDF-6263, IDF-6227
|
||||||
@pytest.mark.generic
|
@pytest.mark.generic
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
'config',
|
'config',
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -23,6 +23,8 @@ static inline uint32_t periph_ll_get_clk_en_mask(periph_module_t periph)
|
|||||||
return PCR_SARADC_CLK_EN;
|
return PCR_SARADC_CLK_EN;
|
||||||
case PERIPH_RMT_MODULE:
|
case PERIPH_RMT_MODULE:
|
||||||
return PCR_RMT_CLK_EN;
|
return PCR_RMT_CLK_EN;
|
||||||
|
case PERIPH_PCNT_MODULE:
|
||||||
|
return PCR_PCNT_CLK_EN;
|
||||||
case PERIPH_LEDC_MODULE:
|
case PERIPH_LEDC_MODULE:
|
||||||
return PCR_LEDC_CLK_EN;
|
return PCR_LEDC_CLK_EN;
|
||||||
case PERIPH_UART0_MODULE:
|
case PERIPH_UART0_MODULE:
|
||||||
@@ -88,6 +90,8 @@ static inline uint32_t periph_ll_get_rst_en_mask(periph_module_t periph, bool en
|
|||||||
return PCR_SARADC_RST_EN;
|
return PCR_SARADC_RST_EN;
|
||||||
case PERIPH_RMT_MODULE:
|
case PERIPH_RMT_MODULE:
|
||||||
return PCR_RMT_RST_EN;
|
return PCR_RMT_RST_EN;
|
||||||
|
case PERIPH_PCNT_MODULE:
|
||||||
|
return PCR_PCNT_RST_EN;
|
||||||
case PERIPH_LEDC_MODULE:
|
case PERIPH_LEDC_MODULE:
|
||||||
return PCR_LEDC_RST_EN;
|
return PCR_LEDC_RST_EN;
|
||||||
case PERIPH_UART0_MODULE:
|
case PERIPH_UART0_MODULE:
|
||||||
@@ -178,6 +182,8 @@ static uint32_t periph_ll_get_clk_en_reg(periph_module_t periph)
|
|||||||
return PCR_RMT_CONF_REG;
|
return PCR_RMT_CONF_REG;
|
||||||
case PERIPH_LEDC_MODULE:
|
case PERIPH_LEDC_MODULE:
|
||||||
return PCR_LEDC_CONF_REG;
|
return PCR_LEDC_CONF_REG;
|
||||||
|
case PERIPH_PCNT_MODULE:
|
||||||
|
return PCR_PCNT_CONF_REG;
|
||||||
case PERIPH_UART0_MODULE:
|
case PERIPH_UART0_MODULE:
|
||||||
return PCR_UART0_CONF_REG;
|
return PCR_UART0_CONF_REG;
|
||||||
case PERIPH_UART1_MODULE:
|
case PERIPH_UART1_MODULE:
|
||||||
@@ -227,6 +233,8 @@ static uint32_t periph_ll_get_rst_en_reg(periph_module_t periph)
|
|||||||
return PCR_SARADC_CONF_REG;
|
return PCR_SARADC_CONF_REG;
|
||||||
case PERIPH_RMT_MODULE:
|
case PERIPH_RMT_MODULE:
|
||||||
return PCR_RMT_CONF_REG;
|
return PCR_RMT_CONF_REG;
|
||||||
|
case PERIPH_PCNT_MODULE:
|
||||||
|
return PCR_PCNT_CONF_REG;
|
||||||
case PERIPH_LEDC_MODULE:
|
case PERIPH_LEDC_MODULE:
|
||||||
return PCR_LEDC_CONF_REG;
|
return PCR_LEDC_CONF_REG;
|
||||||
case PERIPH_UART0_MODULE:
|
case PERIPH_UART0_MODULE:
|
||||||
|
426
components/hal/esp32h2/include/hal/pcnt_ll.h
Normal file
426
components/hal/esp32h2/include/hal/pcnt_ll.h
Normal file
@@ -0,0 +1,426 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* NOTICE
|
||||||
|
* The hal is not public api, don't use in application code.
|
||||||
|
* See readme.md in hal/include/hal/readme.md
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
// The LL layer for ESP32-H2 PCNT register operations
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "soc/pcnt_struct.h"
|
||||||
|
#include "hal/pcnt_types.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define PCNT_LL_GET_HW(num) (((num) == 0) ? (&PCNT) : NULL)
|
||||||
|
#define PCNT_LL_MAX_GLITCH_WIDTH 1023
|
||||||
|
#define PCNT_LL_MAX_LIM SHRT_MAX
|
||||||
|
#define PCNT_LL_MIN_LIN SHRT_MIN
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
PCNT_LL_WATCH_EVENT_INVALID = -1,
|
||||||
|
PCNT_LL_WATCH_EVENT_THRES1,
|
||||||
|
PCNT_LL_WATCH_EVENT_THRES0,
|
||||||
|
PCNT_LL_WATCH_EVENT_LOW_LIMIT,
|
||||||
|
PCNT_LL_WATCH_EVENT_HIGH_LIMIT,
|
||||||
|
PCNT_LL_WATCH_EVENT_ZERO_CROSS,
|
||||||
|
PCNT_LL_WATCH_EVENT_MAX
|
||||||
|
} pcnt_ll_watch_event_id_t;
|
||||||
|
|
||||||
|
#define PCNT_LL_WATCH_EVENT_MASK ((1 << PCNT_LL_WATCH_EVENT_MAX) - 1)
|
||||||
|
#define PCNT_LL_UNIT_WATCH_EVENT(unit_id) (1 << (unit_id))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set PCNT channel edge action
|
||||||
|
*
|
||||||
|
* @param hw Peripheral PCNT hardware instance address.
|
||||||
|
* @param unit PCNT unit number
|
||||||
|
* @param channel PCNT channel number
|
||||||
|
* @param pos_act Counter action when detecting positive edge
|
||||||
|
* @param neg_act Counter action when detecting negative edge
|
||||||
|
*/
|
||||||
|
static inline void pcnt_ll_set_edge_action(pcnt_dev_t *hw, uint32_t unit, uint32_t channel, pcnt_channel_edge_action_t pos_act, pcnt_channel_edge_action_t neg_act)
|
||||||
|
{
|
||||||
|
if (channel == 0) {
|
||||||
|
hw->conf_unit[unit].conf0.ch0_pos_mode = pos_act;
|
||||||
|
hw->conf_unit[unit].conf0.ch0_neg_mode = neg_act;
|
||||||
|
} else {
|
||||||
|
hw->conf_unit[unit].conf0.ch1_pos_mode = pos_act;
|
||||||
|
hw->conf_unit[unit].conf0.ch1_neg_mode = neg_act;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set PCNT channel level action
|
||||||
|
*
|
||||||
|
* @param hw Peripheral PCNT hardware instance address.
|
||||||
|
* @param unit PCNT unit number
|
||||||
|
* @param channel PCNT channel number
|
||||||
|
* @param high_act Counter action when control signal is high level
|
||||||
|
* @param low_act Counter action when control signal is low level
|
||||||
|
*/
|
||||||
|
static inline void pcnt_ll_set_level_action(pcnt_dev_t *hw, uint32_t unit, uint32_t channel, pcnt_channel_level_action_t high_act, pcnt_channel_level_action_t low_act)
|
||||||
|
{
|
||||||
|
if (channel == 0) {
|
||||||
|
hw->conf_unit[unit].conf0.ch0_hctrl_mode = high_act;
|
||||||
|
hw->conf_unit[unit].conf0.ch0_lctrl_mode = low_act;
|
||||||
|
} else {
|
||||||
|
hw->conf_unit[unit].conf0.ch1_hctrl_mode = high_act;
|
||||||
|
hw->conf_unit[unit].conf0.ch1_lctrl_mode = low_act;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get pulse counter value
|
||||||
|
*
|
||||||
|
* @param hw Peripheral PCNT hardware instance address.
|
||||||
|
* @param unit Pulse Counter unit number
|
||||||
|
* @return PCNT count value (a signed integer)
|
||||||
|
*/
|
||||||
|
__attribute__((always_inline))
|
||||||
|
static inline int pcnt_ll_get_count(pcnt_dev_t *hw, uint32_t unit)
|
||||||
|
{
|
||||||
|
pcnt_un_cnt_reg_t cnt_reg = hw->cnt_unit[unit];
|
||||||
|
int16_t value = cnt_reg.pulse_cnt;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Pause PCNT counter of PCNT unit
|
||||||
|
*
|
||||||
|
* @param hw Peripheral PCNT hardware instance address.
|
||||||
|
* @param unit PCNT unit number
|
||||||
|
*/
|
||||||
|
__attribute__((always_inline))
|
||||||
|
static inline void pcnt_ll_stop_count(pcnt_dev_t *hw, uint32_t unit)
|
||||||
|
{
|
||||||
|
hw->ctrl.val |= 1 << (2 * unit + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Resume counting for PCNT counter
|
||||||
|
*
|
||||||
|
* @param hw Peripheral PCNT hardware instance address.
|
||||||
|
* @param unit PCNT unit number, select from uint32_t
|
||||||
|
*/
|
||||||
|
__attribute__((always_inline))
|
||||||
|
static inline void pcnt_ll_start_count(pcnt_dev_t *hw, uint32_t unit)
|
||||||
|
{
|
||||||
|
hw->ctrl.val &= ~(1 << (2 * unit + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clear PCNT counter value to zero
|
||||||
|
*
|
||||||
|
* @param hw Peripheral PCNT hardware instance address.
|
||||||
|
* @param unit PCNT unit number, select from uint32_t
|
||||||
|
*/
|
||||||
|
__attribute__((always_inline))
|
||||||
|
static inline void pcnt_ll_clear_count(pcnt_dev_t *hw, uint32_t unit)
|
||||||
|
{
|
||||||
|
hw->ctrl.val |= 1 << (2 * unit);
|
||||||
|
hw->ctrl.val &= ~(1 << (2 * unit));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable PCNT interrupt for PCNT unit
|
||||||
|
* @note Each PCNT unit has five watch point events that share the same interrupt bit.
|
||||||
|
*
|
||||||
|
* @param hw Peripheral PCNT hardware instance address.
|
||||||
|
* @param unit_mask PCNT units mask
|
||||||
|
* @param enable True to enable interrupt, False to disable interrupt
|
||||||
|
*/
|
||||||
|
static inline void pcnt_ll_enable_intr(pcnt_dev_t *hw, uint32_t unit_mask, bool enable)
|
||||||
|
{
|
||||||
|
if (enable) {
|
||||||
|
hw->int_ena.val |= unit_mask;
|
||||||
|
} else {
|
||||||
|
hw->int_ena.val &= ~unit_mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get PCNT interrupt status
|
||||||
|
*
|
||||||
|
* @param hw Peripheral PCNT hardware instance address.
|
||||||
|
* @return Interrupt status word
|
||||||
|
*/
|
||||||
|
__attribute__((always_inline))
|
||||||
|
static inline uint32_t pcnt_ll_get_intr_status(pcnt_dev_t *hw)
|
||||||
|
{
|
||||||
|
return hw->int_st.val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clear PCNT interrupt status
|
||||||
|
*
|
||||||
|
* @param hw Peripheral PCNT hardware instance address.
|
||||||
|
* @param status value to clear interrupt status
|
||||||
|
*/
|
||||||
|
__attribute__((always_inline))
|
||||||
|
static inline void pcnt_ll_clear_intr_status(pcnt_dev_t *hw, uint32_t status)
|
||||||
|
{
|
||||||
|
hw->int_clr.val = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable PCNT high limit event
|
||||||
|
*
|
||||||
|
* @param hw Peripheral PCNT hardware instance address.
|
||||||
|
* @param unit PCNT unit number
|
||||||
|
* @param enable true to enable, false to disable
|
||||||
|
*/
|
||||||
|
static inline void pcnt_ll_enable_high_limit_event(pcnt_dev_t *hw, uint32_t unit, bool enable)
|
||||||
|
{
|
||||||
|
hw->conf_unit[unit].conf0.thr_h_lim_en = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable PCNT low limit event
|
||||||
|
*
|
||||||
|
* @param hw Peripheral PCNT hardware instance address.
|
||||||
|
* @param unit PCNT unit number
|
||||||
|
* @param enable true to enable, false to disable
|
||||||
|
*/
|
||||||
|
static inline void pcnt_ll_enable_low_limit_event(pcnt_dev_t *hw, uint32_t unit, bool enable)
|
||||||
|
{
|
||||||
|
hw->conf_unit[unit].conf0.thr_l_lim_en = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable PCNT zero cross event
|
||||||
|
*
|
||||||
|
* @param hw Peripheral PCNT hardware instance address.
|
||||||
|
* @param unit PCNT unit number
|
||||||
|
* @param enable true to enable, false to disable
|
||||||
|
*/
|
||||||
|
static inline void pcnt_ll_enable_zero_cross_event(pcnt_dev_t *hw, uint32_t unit, bool enable)
|
||||||
|
{
|
||||||
|
hw->conf_unit[unit].conf0.thr_zero_en = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable PCNT threshold event
|
||||||
|
*
|
||||||
|
* @param hw Peripheral PCNT hardware instance address.
|
||||||
|
* @param unit PCNT unit number
|
||||||
|
* @param thres Threshold ID
|
||||||
|
* @param enable true to enable, false to disable
|
||||||
|
*/
|
||||||
|
static inline void pcnt_ll_enable_thres_event(pcnt_dev_t *hw, uint32_t unit, uint32_t thres, bool enable)
|
||||||
|
{
|
||||||
|
if (thres == 0) {
|
||||||
|
hw->conf_unit[unit].conf0.thr_thres0_en = enable;
|
||||||
|
} else {
|
||||||
|
hw->conf_unit[unit].conf0.thr_thres1_en = enable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disable all PCNT threshold events
|
||||||
|
*
|
||||||
|
* @param hw Peripheral PCNT hardware instance address.
|
||||||
|
* @param unit unit number
|
||||||
|
*/
|
||||||
|
static inline void pcnt_ll_disable_all_events(pcnt_dev_t *hw, uint32_t unit)
|
||||||
|
{
|
||||||
|
hw->conf_unit[unit].conf0.val &= ~(PCNT_LL_WATCH_EVENT_MASK << 11);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set PCNT high limit value
|
||||||
|
*
|
||||||
|
* @param hw Peripheral PCNT hardware instance address.
|
||||||
|
* @param unit PCNT unit number
|
||||||
|
* @param value PCNT high limit value
|
||||||
|
*/
|
||||||
|
static inline void pcnt_ll_set_high_limit_value(pcnt_dev_t *hw, uint32_t unit, int value)
|
||||||
|
{
|
||||||
|
pcnt_un_conf2_reg_t conf2_reg = hw->conf_unit[unit].conf2;
|
||||||
|
conf2_reg.cnt_h_lim = value;
|
||||||
|
hw->conf_unit[unit].conf2 = conf2_reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set PCNT low limit value
|
||||||
|
*
|
||||||
|
* @param hw Peripheral PCNT hardware instance address.
|
||||||
|
* @param unit PCNT unit number
|
||||||
|
* @param value PCNT low limit value
|
||||||
|
*/
|
||||||
|
static inline void pcnt_ll_set_low_limit_value(pcnt_dev_t *hw, uint32_t unit, int value)
|
||||||
|
{
|
||||||
|
pcnt_un_conf2_reg_t conf2_reg = hw->conf_unit[unit].conf2;
|
||||||
|
conf2_reg.cnt_l_lim = value;
|
||||||
|
hw->conf_unit[unit].conf2 = conf2_reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set PCNT threshold value
|
||||||
|
*
|
||||||
|
* @param hw Peripheral PCNT hardware instance address.
|
||||||
|
* @param unit PCNT unit number
|
||||||
|
* @param thres Threshold ID
|
||||||
|
* @param value PCNT threshold value
|
||||||
|
*/
|
||||||
|
static inline void pcnt_ll_set_thres_value(pcnt_dev_t *hw, uint32_t unit, uint32_t thres, int value)
|
||||||
|
{
|
||||||
|
pcnt_un_conf1_reg_t conf1_reg = hw->conf_unit[unit].conf1;
|
||||||
|
if (thres == 0) {
|
||||||
|
conf1_reg.cnt_thres0 = value;
|
||||||
|
} else {
|
||||||
|
conf1_reg.cnt_thres1 = value;
|
||||||
|
}
|
||||||
|
hw->conf_unit[unit].conf1 = conf1_reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get PCNT high limit value
|
||||||
|
*
|
||||||
|
* @param hw Peripheral PCNT hardware instance address.
|
||||||
|
* @param unit PCNT unit number
|
||||||
|
* @return PCNT high limit value
|
||||||
|
*/
|
||||||
|
static inline int pcnt_ll_get_high_limit_value(pcnt_dev_t *hw, uint32_t unit)
|
||||||
|
{
|
||||||
|
pcnt_un_conf2_reg_t conf2_reg = hw->conf_unit[unit].conf2;
|
||||||
|
int16_t value = conf2_reg.cnt_h_lim ;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get PCNT low limit value
|
||||||
|
*
|
||||||
|
* @param hw Peripheral PCNT hardware instance address.
|
||||||
|
* @param unit PCNT unit number
|
||||||
|
* @return PCNT high limit value
|
||||||
|
*/
|
||||||
|
static inline int pcnt_ll_get_low_limit_value(pcnt_dev_t *hw, uint32_t unit)
|
||||||
|
{
|
||||||
|
pcnt_un_conf2_reg_t conf2_reg = hw->conf_unit[unit].conf2;
|
||||||
|
int16_t value = conf2_reg.cnt_l_lim ;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get PCNT threshold value
|
||||||
|
*
|
||||||
|
* @param hw Peripheral PCNT hardware instance address.
|
||||||
|
* @param unit PCNT unit number
|
||||||
|
* @param thres Threshold ID
|
||||||
|
* @return PCNT threshold value
|
||||||
|
*/
|
||||||
|
static inline int pcnt_ll_get_thres_value(pcnt_dev_t *hw, uint32_t unit, uint32_t thres)
|
||||||
|
{
|
||||||
|
int16_t value;
|
||||||
|
pcnt_un_conf1_reg_t conf1_reg = hw->conf_unit[unit].conf1;
|
||||||
|
if (thres == 0) {
|
||||||
|
value = conf1_reg.cnt_thres0 ;
|
||||||
|
} else {
|
||||||
|
value = conf1_reg.cnt_thres1 ;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get PCNT unit runtime status
|
||||||
|
*
|
||||||
|
* @param hw Peripheral PCNT hardware instance address.
|
||||||
|
* @param unit PCNT unit number
|
||||||
|
* @return PCNT unit runtime status
|
||||||
|
*/
|
||||||
|
static inline uint32_t pcnt_ll_get_unit_status(pcnt_dev_t *hw, uint32_t unit)
|
||||||
|
{
|
||||||
|
return hw->status_unit[unit].val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get PCNT zero cross mode
|
||||||
|
*
|
||||||
|
* @param hw Peripheral PCNT hardware instance address.
|
||||||
|
* @param unit PCNT unit number
|
||||||
|
* @return Zero cross mode
|
||||||
|
*/
|
||||||
|
__attribute__((always_inline))
|
||||||
|
static inline pcnt_unit_zero_cross_mode_t pcnt_ll_get_zero_cross_mode(pcnt_dev_t *hw, uint32_t unit)
|
||||||
|
{
|
||||||
|
return hw->status_unit[unit].val & 0x03;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get PCNT event status
|
||||||
|
*
|
||||||
|
* @param hw Peripheral PCNT hardware instance address.
|
||||||
|
* @param unit PCNT unit number
|
||||||
|
* @return Event status word
|
||||||
|
*/
|
||||||
|
__attribute__((always_inline))
|
||||||
|
static inline uint32_t pcnt_ll_get_event_status(pcnt_dev_t *hw, uint32_t unit)
|
||||||
|
{
|
||||||
|
return hw->status_unit[unit].val >> 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set PCNT glitch filter threshold
|
||||||
|
*
|
||||||
|
* @param hw Peripheral PCNT hardware instance address.
|
||||||
|
* @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.
|
||||||
|
*/
|
||||||
|
static inline void pcnt_ll_set_glitch_filter_thres(pcnt_dev_t *hw, uint32_t unit, uint32_t filter_val)
|
||||||
|
{
|
||||||
|
hw->conf_unit[unit].conf0.filter_thres = filter_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get PCNT glitch filter threshold
|
||||||
|
*
|
||||||
|
* @param hw Peripheral PCNT hardware instance address.
|
||||||
|
* @param unit PCNT unit number
|
||||||
|
* @return glitch filter threshold
|
||||||
|
*/
|
||||||
|
static inline uint32_t pcnt_ll_get_glitch_filter_thres(pcnt_dev_t *hw, uint32_t unit)
|
||||||
|
{
|
||||||
|
return hw->conf_unit[unit].conf0.filter_thres ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable PCNT glitch filter
|
||||||
|
*
|
||||||
|
* @param hw Peripheral PCNT hardware instance address.
|
||||||
|
* @param unit PCNT unit number
|
||||||
|
* @param enable True to enable the filter, False to disable the filter
|
||||||
|
*/
|
||||||
|
static inline void pcnt_ll_enable_glitch_filter(pcnt_dev_t *hw, uint32_t unit, bool enable)
|
||||||
|
{
|
||||||
|
hw->conf_unit[unit].conf0.filter_en = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get interrupt status register address.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
*
|
||||||
|
* @return Interrupt status register address
|
||||||
|
*/
|
||||||
|
static inline volatile void *pcnt_ll_get_intr_status_reg(pcnt_dev_t *hw)
|
||||||
|
{
|
||||||
|
return &hw->int_st.val;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
@@ -6,6 +6,7 @@ set(srcs
|
|||||||
"interrupts.c"
|
"interrupts.c"
|
||||||
"spi_periph.c"
|
"spi_periph.c"
|
||||||
"ledc_periph.c"
|
"ledc_periph.c"
|
||||||
|
"pcnt_periph.c"
|
||||||
"rmt_periph.c"
|
"rmt_periph.c"
|
||||||
"sdm_periph.c"
|
"sdm_periph.c"
|
||||||
"i2s_periph.c"
|
"i2s_periph.c"
|
||||||
|
@@ -11,6 +11,10 @@ config SOC_ASYNC_MEMCPY_SUPPORTED
|
|||||||
bool
|
bool
|
||||||
default y
|
default y
|
||||||
|
|
||||||
|
config SOC_PCNT_SUPPORTED
|
||||||
|
bool
|
||||||
|
default y
|
||||||
|
|
||||||
config SOC_GPTIMER_SUPPORTED
|
config SOC_GPTIMER_SUPPORTED
|
||||||
bool
|
bool
|
||||||
default y
|
default y
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -22,6 +22,7 @@ typedef enum {
|
|||||||
PERIPH_TIMG1_MODULE,
|
PERIPH_TIMG1_MODULE,
|
||||||
PERIPH_UHCI0_MODULE,
|
PERIPH_UHCI0_MODULE,
|
||||||
PERIPH_RMT_MODULE,
|
PERIPH_RMT_MODULE,
|
||||||
|
PERIPH_PCNT_MODULE,
|
||||||
PERIPH_SPI_MODULE, //SPI1
|
PERIPH_SPI_MODULE, //SPI1
|
||||||
PERIPH_SPI2_MODULE, //SPI2
|
PERIPH_SPI2_MODULE, //SPI2
|
||||||
PERIPH_TWAI0_MODULE,
|
PERIPH_TWAI0_MODULE,
|
||||||
|
@@ -29,7 +29,7 @@
|
|||||||
// #define SOC_DEDICATED_GPIO_SUPPORTED 1 // TODO: IDF-6241
|
// #define SOC_DEDICATED_GPIO_SUPPORTED 1 // TODO: IDF-6241
|
||||||
#define SOC_GDMA_SUPPORTED 1
|
#define SOC_GDMA_SUPPORTED 1
|
||||||
#define SOC_ASYNC_MEMCPY_SUPPORTED 1
|
#define SOC_ASYNC_MEMCPY_SUPPORTED 1
|
||||||
// #define SOC_PCNT_SUPPORTED 1 // TODO: IDF-6221
|
#define SOC_PCNT_SUPPORTED 1
|
||||||
// #define SOC_MCPWM_SUPPORTED 1 // TODO: IDF-6237
|
// #define SOC_MCPWM_SUPPORTED 1 // TODO: IDF-6237
|
||||||
// #define SOC_TWAI_SUPPORTED 1 // TODO: IDF-6217
|
// #define SOC_TWAI_SUPPORTED 1 // TODO: IDF-6217
|
||||||
// #define SOC_BT_SUPPORTED 1 // TODO: IDF-6416
|
// #define SOC_BT_SUPPORTED 1 // TODO: IDF-6416
|
||||||
@@ -212,7 +212,6 @@
|
|||||||
#define SOC_MPU_REGION_RO_SUPPORTED 0
|
#define SOC_MPU_REGION_RO_SUPPORTED 0
|
||||||
#define SOC_MPU_REGION_WO_SUPPORTED 0
|
#define SOC_MPU_REGION_WO_SUPPORTED 0
|
||||||
|
|
||||||
// TODO: IDF-6221
|
|
||||||
/*-------------------------- PCNT CAPS ---------------------------------------*/
|
/*-------------------------- PCNT CAPS ---------------------------------------*/
|
||||||
#define SOC_PCNT_GROUPS 1U
|
#define SOC_PCNT_GROUPS 1U
|
||||||
#define SOC_PCNT_UNITS_PER_GROUP 4
|
#define SOC_PCNT_UNITS_PER_GROUP 4
|
||||||
|
67
components/soc/esp32h2/pcnt_periph.c
Normal file
67
components/soc/esp32h2/pcnt_periph.c
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "soc/pcnt_periph.h"
|
||||||
|
#include "soc/gpio_sig_map.h"
|
||||||
|
|
||||||
|
const pcnt_signal_conn_t pcnt_periph_signals = {
|
||||||
|
.groups = {
|
||||||
|
[0] = {
|
||||||
|
.module = PERIPH_PCNT_MODULE,
|
||||||
|
.irq = ETS_PCNT_INTR_SOURCE,
|
||||||
|
.units = {
|
||||||
|
[0] = {
|
||||||
|
.channels = {
|
||||||
|
[0] = {
|
||||||
|
.control_sig = PCNT_CTRL_CH0_IN0_IDX,
|
||||||
|
.pulse_sig = PCNT_SIG_CH0_IN0_IDX
|
||||||
|
},
|
||||||
|
[1] = {
|
||||||
|
.control_sig = PCNT_CTRL_CH1_IN0_IDX,
|
||||||
|
.pulse_sig = PCNT_SIG_CH1_IN0_IDX
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[1] = {
|
||||||
|
.channels = {
|
||||||
|
[0] = {
|
||||||
|
.control_sig = PCNT_CTRL_CH0_IN1_IDX,
|
||||||
|
.pulse_sig = PCNT_SIG_CH0_IN1_IDX
|
||||||
|
},
|
||||||
|
[1] = {
|
||||||
|
.control_sig = PCNT_CTRL_CH1_IN1_IDX,
|
||||||
|
.pulse_sig = PCNT_SIG_CH1_IN1_IDX
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[2] = {
|
||||||
|
.channels = {
|
||||||
|
[0] = {
|
||||||
|
.control_sig = PCNT_CTRL_CH0_IN2_IDX,
|
||||||
|
.pulse_sig = PCNT_SIG_CH0_IN2_IDX
|
||||||
|
},
|
||||||
|
[1] = {
|
||||||
|
.control_sig = PCNT_CTRL_CH1_IN2_IDX,
|
||||||
|
.pulse_sig = PCNT_SIG_CH1_IN2_IDX
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[3] = {
|
||||||
|
.channels = {
|
||||||
|
[0] = {
|
||||||
|
.control_sig = PCNT_CTRL_CH0_IN3_IDX,
|
||||||
|
.pulse_sig = PCNT_SIG_CH0_IN3_IDX
|
||||||
|
},
|
||||||
|
[1] = {
|
||||||
|
.control_sig = PCNT_CTRL_CH1_IN3_IDX,
|
||||||
|
.pulse_sig = PCNT_SIG_CH1_IN3_IDX
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
@@ -9,6 +9,7 @@ from pytest_embedded.dut import Dut
|
|||||||
@pytest.mark.esp32s2
|
@pytest.mark.esp32s2
|
||||||
@pytest.mark.esp32s3
|
@pytest.mark.esp32s3
|
||||||
@pytest.mark.esp32c6
|
@pytest.mark.esp32c6
|
||||||
|
# @pytest.mark.esp32h2 # TODO: IDF-6263, IDF-6227
|
||||||
@pytest.mark.generic
|
@pytest.mark.generic
|
||||||
def test_rotary_encoder(dut: Dut) -> None:
|
def test_rotary_encoder(dut: Dut) -> None:
|
||||||
dut.expect_exact('install pcnt unit')
|
dut.expect_exact('install pcnt unit')
|
||||||
|
Reference in New Issue
Block a user