feat(esp32h21): refactor gpio_ll to use io_mux_struct

This commit is contained in:
gaoxu 2025-02-17 15:53:13 +08:00
parent 760f134d84
commit d3acbe15aa
6 changed files with 187 additions and 67 deletions

View File

@ -535,9 +535,6 @@ TEST_CASE("GPIO_set_output_level_get_input_level_test", "[gpio]")
TEST_ASSERT_EQUAL_INT_MESSAGE(1, gpio_get_level(TEST_GPIO_EXT_IN_IO), "get level error! the level should be high!");
}
#if !CONFIG_IDF_ENV_FPGA
// On FPGA do not support GPIO pull down
// This test routes constant-high/low signal to pins, another way is to directly connect TEST_GPIO_EXT_IN_IO to
// 3.3v or GND pin
TEST_CASE("GPIO_get_level_from_fixed_voltage_test", "[gpio]")
@ -564,6 +561,9 @@ TEST_CASE("GPIO_get_level_from_fixed_voltage_test", "[gpio]")
TEST_ASSERT_EQUAL_INT_MESSAGE(0, level2, "get level error! the level should be low!");
}
#if !CONFIG_IDF_ENV_FPGA
// On FPGA do not support GPIO pull down
TEST_CASE("GPIO_io_pull_up/down_function", "[gpio]")
{
// First, ensure that the output IO will not affect the level

View File

@ -259,7 +259,7 @@ static inline void gpio_ll_pin_filter_disable(gpio_dev_t *hw, uint32_t gpio_num)
static inline void gpio_ll_pin_input_hysteresis_enable(gpio_dev_t *hw, uint32_t gpio_num)
{
// On ESP32C5, there is an efuse bit that controls the hysteresis enable or not for all IOs.
// We are not going to use the hardware control in IDF for C5.
// We are not going to use the hardware control for C5.
// Therefore, we need to always switch to use software control first.
// i.e. Swt hys_sel to 1, so that hys_en determines whether hysteresis is enabled or not
IO_MUX.gpio[gpio_num].hys_sel = 1;

View File

@ -21,9 +21,10 @@
#include "soc/gpio_struct.h"
#include "soc/lp_aon_struct.h"
#include "soc/pmu_struct.h"
#include "soc/usb_serial_jtag_reg.h"
#include "soc/pcr_struct.h"
#include "soc/clk_tree_defs.h"
#include "soc/io_mux_struct.h"
#include "soc/usb_serial_jtag_struct.h"
#include "hal/gpio_types.h"
#include "hal/misc.h"
#include "hal/assert.h"
@ -48,18 +49,17 @@ extern "C" {
static inline void gpio_ll_get_io_config(gpio_dev_t *hw, uint32_t gpio_num, gpio_io_config_t *io_config)
{
uint32_t bit_mask = 1 << gpio_num;
uint32_t iomux_reg_val = REG_READ(IO_MUX_GPIO0_REG + (gpio_num * 4));
io_config->pu = (iomux_reg_val & FUN_PU_M) >> FUN_PU_S;
io_config->pd = (iomux_reg_val & FUN_PD_M) >> FUN_PD_S;
io_config->ie = (iomux_reg_val & FUN_IE_M) >> FUN_IE_S;
io_config->pu = IO_MUX.gpio[gpio_num].fun_wpu;
io_config->pd = IO_MUX.gpio[gpio_num].fun_wpd;
io_config->ie = IO_MUX.gpio[gpio_num].fun_ie;
io_config->oe = (hw->enable.val & bit_mask) >> gpio_num;
io_config->oe_ctrl_by_periph = !(hw->funcn_out_sel_cfg[gpio_num].funcn_oe_sel);
io_config->oe_inv = hw->funcn_out_sel_cfg[gpio_num].funcn_oe_inv_sel;
io_config->od = hw->pinn[gpio_num].pinn_pad_driver;
io_config->drv = (gpio_drive_cap_t)((iomux_reg_val & FUN_DRV_M) >> FUN_DRV_S);
io_config->fun_sel = (iomux_reg_val & MCU_SEL_M) >> MCU_SEL_S;
io_config->drv = (gpio_drive_cap_t)IO_MUX.gpio[gpio_num].fun_drv;
io_config->fun_sel = IO_MUX.gpio[gpio_num].mcu_sel;
io_config->sig_out = hw->funcn_out_sel_cfg[gpio_num].funcn_out_sel;
io_config->slp_sel = (iomux_reg_val & SLP_SEL_M) >> SLP_SEL_S;
io_config->slp_sel = IO_MUX.gpio[gpio_num].slp_sel;
}
/**
@ -70,7 +70,7 @@ static inline void gpio_ll_get_io_config(gpio_dev_t *hw, uint32_t gpio_num, gpio
*/
static inline void gpio_ll_pullup_en(gpio_dev_t *hw, gpio_num_t gpio_num)
{
REG_SET_BIT(IO_MUX_GPIO0_REG + (gpio_num * 4), FUN_PU);
IO_MUX.gpio[gpio_num].fun_wpu = 1;
}
/**
@ -88,10 +88,10 @@ static inline void gpio_ll_pullup_dis(gpio_dev_t *hw, gpio_num_t gpio_num)
// which should be checked is USB_INT_PHY0_DM_GPIO_NUM instead.
// TODO: read the specific efuse with efuse_ll.h
if (gpio_num == USB_INT_PHY0_DP_GPIO_NUM) {
SET_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_PAD_PULL_OVERRIDE);
CLEAR_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_DP_PULLUP);
USB_SERIAL_JTAG.serial_jtag_conf0.serial_jtag_pad_pull_override = 1;
USB_SERIAL_JTAG.serial_jtag_conf0.serial_jtag_dp_pullup = 0;
}
REG_CLR_BIT(IO_MUX_GPIO0_REG + (gpio_num * 4), FUN_PU);
IO_MUX.gpio[gpio_num].fun_wpu = 0;
}
/**
@ -102,7 +102,7 @@ static inline void gpio_ll_pullup_dis(gpio_dev_t *hw, gpio_num_t gpio_num)
*/
static inline void gpio_ll_pulldown_en(gpio_dev_t *hw, gpio_num_t gpio_num)
{
REG_SET_BIT(IO_MUX_GPIO0_REG + (gpio_num * 4), FUN_PD);
IO_MUX.gpio[gpio_num].fun_wpd = 1;
}
/**
@ -114,7 +114,7 @@ static inline void gpio_ll_pulldown_en(gpio_dev_t *hw, gpio_num_t gpio_num)
__attribute__((always_inline))
static inline void gpio_ll_pulldown_dis(gpio_dev_t *hw, gpio_num_t gpio_num)
{
REG_CLR_BIT(IO_MUX_GPIO0_REG + (gpio_num * 4), FUN_PD);
IO_MUX.gpio[gpio_num].fun_wpd = 0;
}
/**
@ -215,7 +215,7 @@ static inline void gpio_ll_intr_disable(gpio_dev_t *hw, gpio_num_t gpio_num)
__attribute__((always_inline))
static inline void gpio_ll_input_disable(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_INPUT_DISABLE(IO_MUX_GPIO0_REG + (gpio_num * 4));
IO_MUX.gpio[gpio_num].fun_ie = 0;
}
/**
@ -227,7 +227,7 @@ static inline void gpio_ll_input_disable(gpio_dev_t *hw, gpio_num_t gpio_num)
__attribute__((always_inline))
static inline void gpio_ll_input_enable(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_INPUT_ENABLE(IO_MUX_GPIO0_REG + (gpio_num * 4));
IO_MUX.gpio[gpio_num].fun_ie = 1;
}
/**
@ -238,7 +238,7 @@ static inline void gpio_ll_input_enable(gpio_dev_t *hw, gpio_num_t gpio_num)
*/
static inline void gpio_ll_pin_filter_enable(gpio_dev_t *hw, uint32_t gpio_num)
{
PIN_FILTER_EN(IO_MUX_GPIO0_REG + (gpio_num * 4));
IO_MUX.gpio[gpio_num].filter_en = 1;
}
/**
@ -249,29 +249,7 @@ static inline void gpio_ll_pin_filter_enable(gpio_dev_t *hw, uint32_t gpio_num)
*/
static inline void gpio_ll_pin_filter_disable(gpio_dev_t *hw, uint32_t gpio_num)
{
PIN_FILTER_DIS(IO_MUX_GPIO0_REG + (gpio_num * 4));
}
/**
* @brief Select gpio hysteresis control by efuse.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_pin_input_hysteresis_ctrl_sel_efuse(gpio_dev_t *hw, uint32_t gpio_num)
{
PIN_HYS_EN_SEL_EFUSE(IO_MUX_GPIO0_REG + (gpio_num * 4));
}
/**
* @brief Select gpio hysteresis control by software.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_pin_input_hysteresis_ctrl_sel_soft(gpio_dev_t *hw, uint32_t gpio_num)
{
PIN_HYS_EN_SEL_SOFT(IO_MUX_GPIO0_REG + (gpio_num * 4));
IO_MUX.gpio[gpio_num].filter_en = 0;
}
/**
@ -282,7 +260,12 @@ static inline void gpio_ll_pin_input_hysteresis_ctrl_sel_soft(gpio_dev_t *hw, ui
*/
static inline void gpio_ll_pin_input_hysteresis_enable(gpio_dev_t *hw, uint32_t gpio_num)
{
PIN_HYS_SOFT_ENABLE(IO_MUX_GPIO0_REG + (gpio_num * 4));
// On ESP32H21, there is an efuse bit that controls the hysteresis enable or not for all IOs.
// We are not going to use the hardware control for H21.
// Therefore, we need to always switch to use software control first.
// i.e. Swt hys_sel to 1, so that hys_en determines whether hysteresis is enabled or not
IO_MUX.gpio[gpio_num].hys_sel = 1;
IO_MUX.gpio[gpio_num].hys_en = 1;
}
/**
@ -293,7 +276,8 @@ static inline void gpio_ll_pin_input_hysteresis_enable(gpio_dev_t *hw, uint32_t
*/
static inline void gpio_ll_pin_input_hysteresis_disable(gpio_dev_t *hw, uint32_t gpio_num)
{
PIN_HYS_SOFT_DISABLE(IO_MUX_GPIO0_REG + (gpio_num * 4));
IO_MUX.gpio[gpio_num].hys_sel = 1;
IO_MUX.gpio[gpio_num].hys_en = 0;
}
/**
@ -424,7 +408,7 @@ static inline void gpio_ll_wakeup_disable(gpio_dev_t *hw, gpio_num_t gpio_num)
*/
static inline void gpio_ll_set_drive_capability(gpio_dev_t *hw, gpio_num_t gpio_num, gpio_drive_cap_t strength)
{
SET_PERI_REG_BITS(IO_MUX_GPIO0_REG + (gpio_num * 4), FUN_DRV_V, strength, FUN_DRV_S);
IO_MUX.gpio[gpio_num].fun_drv = strength;
}
/**
@ -436,7 +420,7 @@ static inline void gpio_ll_set_drive_capability(gpio_dev_t *hw, gpio_num_t gpio_
*/
static inline void gpio_ll_get_drive_capability(gpio_dev_t *hw, gpio_num_t gpio_num, gpio_drive_cap_t *strength)
{
*strength = (gpio_drive_cap_t)GET_PERI_REG_BITS2(IO_MUX_GPIO0_REG + (gpio_num * 4), FUN_DRV_V, FUN_DRV_S);
*strength = (gpio_drive_cap_t)(IO_MUX.gpio[gpio_num].fun_drv);
}
/**
@ -518,11 +502,11 @@ static inline void gpio_ll_set_output_enable_ctrl(gpio_dev_t *hw, uint8_t gpio_n
__attribute__((always_inline))
static inline void gpio_ll_func_sel(gpio_dev_t *hw, uint8_t gpio_num, uint32_t func)
{
// Disable USB Serial JTAG if pins 26 or pins 27 needs to select an IOMUX function
// Disable USB Serial JTAG if pins 17 or pins 18 needs to select an IOMUX function
if (gpio_num == USB_INT_PHY0_DM_GPIO_NUM || gpio_num == USB_INT_PHY0_DP_GPIO_NUM) {
CLEAR_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_USB_PAD_ENABLE);
USB_SERIAL_JTAG.serial_jtag_conf0.serial_jtag_usb_pad_enable = 0;
}
PIN_FUNC_SELECT(IO_MUX_GPIO0_REG + (gpio_num * 4), func);
IO_MUX.gpio[gpio_num].mcu_sel = func;
}
/**
@ -594,7 +578,7 @@ static inline void gpio_ll_force_unhold_all(void)
*/
static inline void gpio_ll_sleep_sel_en(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_SEL_ENABLE(IO_MUX_GPIO0_REG + (gpio_num * 4));
IO_MUX.gpio[gpio_num].slp_sel = 1;
}
/**
@ -606,7 +590,7 @@ static inline void gpio_ll_sleep_sel_en(gpio_dev_t *hw, gpio_num_t gpio_num)
*/
static inline void gpio_ll_sleep_sel_dis(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_SEL_DISABLE(IO_MUX_GPIO0_REG + (gpio_num * 4));
IO_MUX.gpio[gpio_num].slp_sel = 0;
}
/**
@ -617,7 +601,7 @@ static inline void gpio_ll_sleep_sel_dis(gpio_dev_t *hw, gpio_num_t gpio_num)
*/
static inline void gpio_ll_sleep_pullup_dis(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_PULLUP_DISABLE(IO_MUX_GPIO0_REG + (gpio_num * 4));
IO_MUX.gpio[gpio_num].mcu_wpu = 0;
}
/**
@ -628,7 +612,7 @@ static inline void gpio_ll_sleep_pullup_dis(gpio_dev_t *hw, gpio_num_t gpio_num)
*/
static inline void gpio_ll_sleep_pullup_en(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_PULLUP_ENABLE(IO_MUX_GPIO0_REG + (gpio_num * 4));
IO_MUX.gpio[gpio_num].mcu_wpu = 1;
}
/**
@ -639,7 +623,7 @@ static inline void gpio_ll_sleep_pullup_en(gpio_dev_t *hw, gpio_num_t gpio_num)
*/
static inline void gpio_ll_sleep_pulldown_en(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_PULLDOWN_ENABLE(IO_MUX_GPIO0_REG + (gpio_num * 4));
IO_MUX.gpio[gpio_num].mcu_wpd = 1;
}
/**
@ -650,9 +634,8 @@ static inline void gpio_ll_sleep_pulldown_en(gpio_dev_t *hw, gpio_num_t gpio_num
*/
static inline void gpio_ll_sleep_pulldown_dis(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_PULLDOWN_DISABLE(IO_MUX_GPIO0_REG + (gpio_num * 4));
IO_MUX.gpio[gpio_num].mcu_wpd = 0;
}
/**
* @brief Disable GPIO input in sleep mode.
*
@ -661,7 +644,7 @@ static inline void gpio_ll_sleep_pulldown_dis(gpio_dev_t *hw, gpio_num_t gpio_nu
*/
static inline void gpio_ll_sleep_input_disable(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_INPUT_DISABLE(IO_MUX_GPIO0_REG + (gpio_num * 4));
IO_MUX.gpio[gpio_num].mcu_ie = 0;
}
/**
@ -672,7 +655,7 @@ static inline void gpio_ll_sleep_input_disable(gpio_dev_t *hw, gpio_num_t gpio_n
*/
static inline void gpio_ll_sleep_input_enable(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_INPUT_ENABLE(IO_MUX_GPIO0_REG + (gpio_num * 4));
IO_MUX.gpio[gpio_num].mcu_ie = 1;
}
/**
@ -683,7 +666,7 @@ static inline void gpio_ll_sleep_input_enable(gpio_dev_t *hw, gpio_num_t gpio_nu
*/
static inline void gpio_ll_sleep_output_disable(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_OUTPUT_DISABLE(IO_MUX_GPIO0_REG + (gpio_num * 4));
IO_MUX.gpio[gpio_num].mcu_oe = 0;
}
/**
@ -694,7 +677,7 @@ static inline void gpio_ll_sleep_output_disable(gpio_dev_t *hw, gpio_num_t gpio_
*/
static inline void gpio_ll_sleep_output_enable(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_OUTPUT_ENABLE(IO_MUX_GPIO0_REG + (gpio_num * 4));
IO_MUX.gpio[gpio_num].mcu_oe = 1;
}
/**

View File

@ -235,10 +235,6 @@ config SOC_GPIO_PIN_COUNT
int
default 26
config SOC_GPIO_SUPPORT_PIN_HYS_CTRL_BY_EFUSE
bool
default y
config SOC_GPIO_SUPPORT_RTC_INDEPENDENT
bool
default y

View File

@ -193,7 +193,6 @@
// #define SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER 1
// #define SOC_GPIO_FLEX_GLITCH_FILTER_NUM 8
// #define SOC_GPIO_SUPPORT_PIN_HYS_FILTER 1
#define SOC_GPIO_SUPPORT_PIN_HYS_CTRL_BY_EFUSE 1 // By default, hysteresis enable/disable is controlled by efuse
// GPIO peripheral has the ETM extension
// #define SOC_GPIO_SUPPORT_ETM 1

View File

@ -0,0 +1,142 @@
/**
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/** Group: Configuration Registers */
/** Type of gpio register
* IO MUX configuration register for gpio
*/
typedef union {
struct {
/** mcu_oe : R/W; bitpos: [0]; default: 0;
* Output enable of the pad in sleep mode.
* 1: output enabled.
* 0: output disabled.
*/
uint32_t mcu_oe:1;
/** slp_sel : R/W; bitpos: [1]; default: 0;
* Sleep mode selection of this pad. Set to 1 to put the pad in pad mode.
*/
uint32_t slp_sel:1;
/** mcu_wpd : R/W; bitpos: [2]; default: 0;
* Pull-down enable of the pad in sleep mode.
* 1: internal pull-down enabled.
* 0: internal pull-down disabled.
*/
uint32_t mcu_wpd:1;
/** mcu_wpu : R/W; bitpos: [3]; default: 0;
* Pull-up enable of the pad during sleep mode.
* 1: internal pull-up enabled.
* 0: internal pull-up disabled.
*/
uint32_t mcu_wpu:1;
/** mcu_ie : R/W; bitpos: [4]; default: 0;
* Input enable of the pad during sleep mode.
* 1: input enabled.
* 0: input disabled.
*/
uint32_t mcu_ie:1;
/** mcu_drv : R/W; bitpos: [6:5]; default: 0;
* Select the drive strength of the pad during sleep mode.
* 0: ~5 mA\\
* 1: ~10 mA\\
* 2: ~20 mA\\
* 3: ~40 mA\\
*/
uint32_t mcu_drv:2;
/** fun_wpd : R/W; bitpos: [7]; default: 0;
* Pull-down enable of the pad.
* 1: internal pull-down enabled.
* 0: internal pull-down disabled.
*/
uint32_t fun_wpd:1;
/** fun_wpu : R/W; bitpos: [8]; default: 0;
* Pull-up enable of the pad.
* 1: internal pull-up enabled.
* 0: internal pull-up disabled.
*/
uint32_t fun_wpu:1;
/** fun_ie : R/W; bitpos: [9]; default: 0;
* Input enable of the pad.
* 1: input enabled.
* 0: input disabled.
*/
uint32_t fun_ie:1;
/** fun_drv : R/W; bitpos: [11:10]; default: 2;
* Select the drive strength of the pad.
* 0: ~5 mA\\
* 1: ~10 mA\\
* 2: ~20 mA\\
* 3: ~40 mA\\
*/
uint32_t fun_drv:2;
/** mcu_sel : R/W; bitpos: [14:12]; default: 1;
* Select IO MUX function for this signal.
* 0: Select Function 1.
* 1: Select Function 2. etc.
* ......\\
*/
uint32_t mcu_sel:3;
/** filter_en : R/W; bitpos: [15]; default: 0;
* Enable filter for pin input signals.
* 1: Filter enabled.
* 0: Filter disabled.
*/
uint32_t filter_en:1;
/** hys_en : R/W; bitpos: [16]; default: 0;
* Software enables hysteresis function for the pad.
* 1: Filter enabled.
* 0: Filter disabled.
*/
uint32_t hys_en:1;
/** hys_sel : R/W; bitpos: [17]; default: 0;
* Select enabling signals of the pad from software and efuse hardware.
* 1: Hysteresis enabled.
* 0: Hysteresis disabled.
*/
uint32_t hys_sel:1;
uint32_t reserved_18:14;
};
uint32_t val;
} io_mux_gpio_reg_t;
/** Group: Version Register */
/** Type of date register
* Version control register
*/
typedef union {
struct {
/** reg_date : R/W; bitpos: [27:0]; default: 36770416;
* Version control register
*/
uint32_t reg_date:28;
uint32_t reserved_28:4;
};
uint32_t val;
} io_mux_date_reg_t;
typedef struct {
volatile io_mux_gpio_reg_t gpio[26];
uint32_t reserved_074[101];
volatile io_mux_date_reg_t date;
} io_mux_dev_t;
extern io_mux_dev_t IO_MUX;
#ifndef __cplusplus
_Static_assert(sizeof(io_mux_dev_t) == 0x200, "Invalid size of io_mux_dev_t structure");
#endif
#ifdef __cplusplus
}
#endif