diff --git a/components/hal/esp32p4/include/hal/i2c_ll.h b/components/hal/esp32p4/include/hal/i2c_ll.h index 551e82eeea..a95aa8e302 100644 --- a/components/hal/esp32p4/include/hal/i2c_ll.h +++ b/components/hal/esp32p4/include/hal/i2c_ll.h @@ -17,6 +17,7 @@ #include "hal/i2c_types.h" #include "soc/clk_tree_defs.h" #include "soc/hp_sys_clkrst_struct.h" +#include "soc/lpperi_struct.h" #include "hal/misc.h" #ifdef __cplusplus @@ -796,6 +797,65 @@ static inline void i2c_ll_set_source_clk(i2c_dev_t *hw, i2c_clock_source_t src_c /// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance #define i2c_ll_set_source_clk(...) do {(void)__DECLARE_RCC_ATOMIC_ENV; i2c_ll_set_source_clk(__VA_ARGS__);} while(0) +/** + * @brief Set LP I2C source clock + * + * @param hw Address offset of the LP I2C peripheral registers + * @param src_clk Source clock for the LP I2C peripheral + */ +static inline void lp_i2c_ll_set_source_clk(i2c_dev_t *hw, soc_periph_lp_i2c_clk_src_t src_clk) +{ + (void)hw; + // src_clk : (0) for LP_FAST_CLK (RTC Fast), (1) for XTAL_D2_CLK, (2) for LP_PLL + switch (src_clk) { + case LP_I2C_SCLK_LP_FAST: + LPPERI.core_clk_sel.lp_i2c_clk_sel = 0; + break; + case LP_I2C_SCLK_XTAL_D2: + LPPERI.core_clk_sel.lp_i2c_clk_sel = 1; + break; + // case LP_I2C_SCLK_LP_PLL: + // LPPERI.core_clk_sel.lp_i2c_clk_sel = 2; + // break; + default: + // Invalid source clock selected + HAL_ASSERT(false); + } +} + +/// LP_AON_CLKRST.lpperi is a shared register, so this function must be used in an atomic way +#define lp_i2c_ll_set_source_clk(...) (void)__DECLARE_RCC_ATOMIC_ENV; lp_i2c_ll_set_source_clk(__VA_ARGS__) + +/** + * @brief Enable bus clock for the LP I2C module + * + * @param hw_id LP I2C instance ID + * @param enable True to enable, False to disable + */ +static inline void _lp_i2c_ll_enable_bus_clock(int hw_id, bool enable) +{ + (void)hw_id; + LPPERI.clk_en.ck_en_lp_i2c = enable ? 1 : 0; +} + +/// LPPERI.clk_en is a shared register, so this function must be used in an atomic way +#define lp_i2c_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; _lp_i2c_ll_enable_bus_clock(__VA_ARGS__) + +/** + * @brief Reset LP I2C module + * + * @param hw_id LP I2C instance ID + */ +static inline void lp_i2c_ll_reset_register(int hw_id) +{ + (void)hw_id; + LPPERI.reset_en.rst_en_lp_i2c = 1; + LPPERI.reset_en.rst_en_lp_i2c = 0; +} + +/// LPPERI.reset_en is a shared register, so this function must be used in an atomic way +#define lp_i2c_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; lp_i2c_ll_reset_register(__VA_ARGS__) + /** * @brief Enable I2C peripheral controller clock * diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index df74111cc2..4510070e4e 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -199,6 +199,10 @@ config SOC_LP_PERIPHERALS_SUPPORTED bool default y +config SOC_LP_I2C_SUPPORTED + bool + default y + config SOC_SPIRAM_SUPPORTED bool default y @@ -615,6 +619,14 @@ config SOC_I2C_SLAVE_SUPPORT_SLAVE_UNMATCH bool default y +config SOC_LP_I2C_NUM + int + default 1 + +config SOC_LP_I2C_FIFO_LEN + int + default 16 + config SOC_I2S_NUM int default 3 diff --git a/components/soc/esp32p4/include/soc/clk_tree_defs.h b/components/soc/esp32p4/include/soc/clk_tree_defs.h index 26fb9a0f82..b39730b19a 100644 --- a/components/soc/esp32p4/include/soc/clk_tree_defs.h +++ b/components/soc/esp32p4/include/soc/clk_tree_defs.h @@ -420,6 +420,24 @@ typedef enum { I2C_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as the source clock */ I2C_CLK_SRC_DEFAULT = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the default source clock */ } soc_periph_i2c_clk_src_t; + +///////////////////////////////////////////////LP_I2C/////////////////////////////////////////////////////////////////// + +/** + * @brief Array initializer for all supported clock sources of LP_I2C + */ +#define SOC_LP_I2C_CLKS {SOC_MOD_CLK_RTC_FAST, SOC_MOD_CLK_XTAL_D2} + +/** + * @brief Type of LP_I2C clock source. + */ +typedef enum { + LP_I2C_SCLK_LP_FAST = SOC_MOD_CLK_RTC_FAST, /*!< LP_I2C source clock is RTC_FAST */ + LP_I2C_SCLK_XTAL_D2 = SOC_MOD_CLK_XTAL_D2, /*!< LP_I2C source clock is XTAL_D2 */ + // LP_I2C_SCLK_LP_PLL = SOC_MOD_CLK_LP_PLL, /*!< LP_I2C source clock is LP_PLL */ + LP_I2C_SCLK_DEFAULT = SOC_MOD_CLK_RTC_FAST, /*!< LP_I2C source clock default choice is RTC_FAST */ +} soc_periph_lp_i2c_clk_src_t; + /////////////////////////////////////////////////SPI//////////////////////////////////////////////////////////////////// /** diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 2ccdeb3908..aff18e68db 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -75,6 +75,7 @@ #define SOC_ULP_LP_UART_SUPPORTED 1 #define SOC_LP_GPIO_MATRIX_SUPPORTED 1 #define SOC_LP_PERIPHERALS_SUPPORTED 1 +#define SOC_LP_I2C_SUPPORTED 1 #define SOC_SPIRAM_SUPPORTED 1 #define SOC_PSRAM_DMA_CAPABLE 1 // #define SOC_ULP_SUPPORTED 1 //TODO: IDF-7534 @@ -268,6 +269,12 @@ #define SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS (1) #define SOC_I2C_SLAVE_SUPPORT_SLAVE_UNMATCH (1) +/*-------------------------- LP_I2C CAPS -------------------------------------*/ +// ESP32-P4 has 1 LP_I2C +#define SOC_LP_I2C_NUM (1U) + +#define SOC_LP_I2C_FIFO_LEN (16) /*!< LP_I2C hardware FIFO depth */ + /*-------------------------- I2S CAPS ----------------------------------------*/ #define SOC_I2S_NUM (3U) #define SOC_I2S_HW_VERSION_2 (1) diff --git a/components/ulp/CMakeLists.txt b/components/ulp/CMakeLists.txt index f4f0178ad4..ba78779040 100644 --- a/components/ulp/CMakeLists.txt +++ b/components/ulp/CMakeLists.txt @@ -59,7 +59,6 @@ if(CONFIG_ULP_COPROC_TYPE_LP_CORE) endif() if(CONFIG_SOC_LP_I2C_SUPPORTED) - # Add to P4 TODO IDF-7540 list(APPEND srcs "lp_core/lp_core_i2c.c") endif() diff --git a/components/ulp/lp_core/lp_core/lp_core_i2c.c b/components/ulp/lp_core/lp_core/lp_core_i2c.c index 524b8cadd3..7cbb4b9490 100644 --- a/components/ulp/lp_core/lp_core/lp_core_i2c.c +++ b/components/ulp/lp_core/lp_core/lp_core_i2c.c @@ -481,4 +481,4 @@ esp_err_t lp_core_i2c_master_write_read_device(i2c_port_t lp_i2c_num, uint16_t d return ret; } -#endif //!SOC_LP_I2C_SUPPORTED +#endif /* SOC_LP_I2C_SUPPORTED */ diff --git a/components/ulp/lp_core/lp_core_i2c.c b/components/ulp/lp_core/lp_core_i2c.c index 58d74eb9ee..0d41f7fba1 100644 --- a/components/ulp/lp_core/lp_core_i2c.c +++ b/components/ulp/lp_core/lp_core_i2c.c @@ -7,7 +7,6 @@ #include "lp_core_i2c.h" #include "esp_check.h" #include "hal/i2c_hal.h" -#include "soc/lp_io_struct.h" #include "driver/rtc_io.h" #include "soc/rtc_io_channel.h" #include "esp_private/esp_clk_tree_common.h" @@ -15,20 +14,28 @@ static const char *LPI2C_TAG = "lp_core_i2c"; +#if !SOC_LP_GPIO_MATRIX_SUPPORTED +#include "soc/lp_io_struct.h" + +/* Use the register structure to access LP_IO module registers */ +lp_io_dev_t *lp_io_dev = &LP_IO; +#else +#include "driver/lp_io.h" +#include "soc/lp_gpio_sig_map.h" +#endif /* !SOC_LP_GPIO_MATRIX_SUPPORTED */ + #define LP_I2C_FILTER_CYC_NUM_DEF (7) /* I2C LL context */ i2c_hal_context_t i2c_hal; -/* Use the register structure to access LP_IO module registers */ -lp_io_dev_t *lp_io_dev = &LP_IO; - static esp_err_t lp_i2c_gpio_is_cfg_valid(gpio_num_t sda_io_num, gpio_num_t scl_io_num) { /* Verify that the SDA and SCL GPIOs are valid LP IO (RTCIO) pins */ ESP_RETURN_ON_ERROR(!rtc_gpio_is_valid_gpio(sda_io_num), LPI2C_TAG, "LP I2C SDA GPIO invalid"); ESP_RETURN_ON_ERROR(!rtc_gpio_is_valid_gpio(scl_io_num), LPI2C_TAG, "LP I2C SCL GPIO invalid"); +#if !SOC_LP_GPIO_MATRIX_SUPPORTED /* Verify that the SDA and SCL line belong to the LP IO Mux I2C function group */ if (sda_io_num != RTCIO_GPIO6_CHANNEL) { ESP_LOGE(LPI2C_TAG, "SDA pin can only be configured as GPIO#6"); @@ -39,6 +46,7 @@ static esp_err_t lp_i2c_gpio_is_cfg_valid(gpio_num_t sda_io_num, gpio_num_t scl_ ESP_LOGE(LPI2C_TAG, "SCL pin can only be configured as GPIO#7"); return ESP_ERR_INVALID_ARG; } +#endif /* !SOC_LP_GPIO_MATRIX_SUPPORTED */ return ESP_OK; } @@ -64,6 +72,8 @@ static esp_err_t lp_i2c_configure_io(gpio_num_t io_num, bool pullup_en) static esp_err_t lp_i2c_set_pin(const lp_core_i2c_cfg_t *cfg) { + esp_err_t ret = ESP_OK; + gpio_num_t sda_io_num = cfg->i2c_pin_cfg.sda_io_num; gpio_num_t scl_io_num = cfg->i2c_pin_cfg.scl_io_num; bool sda_pullup_en = cfg->i2c_pin_cfg.sda_pullup_en; @@ -78,13 +88,23 @@ static esp_err_t lp_i2c_set_pin(const lp_core_i2c_cfg_t *cfg) /* Initialize SCL Pin */ ESP_RETURN_ON_ERROR(lp_i2c_configure_io(scl_io_num, scl_pullup_en), LPI2C_TAG, "LP I2C SCL pin config failed"); +#if !SOC_LP_GPIO_MATRIX_SUPPORTED /* Select LP I2C function for the SDA Pin */ lp_io_dev->gpio[sda_io_num].mcu_sel = 1; /* Select LP I2C function for the SCL Pin */ lp_io_dev->gpio[scl_io_num].mcu_sel = 1; +#else + /* Connect the SDA pin of the LP_I2C peripheral to the LP_IO Matrix */ + ret = lp_gpio_connect_out_signal(sda_io_num, LP_I2C_SDA_PAD_OUT_IDX, 0, 0); + ret = lp_gpio_connect_in_signal(sda_io_num, LP_I2C_SDA_PAD_IN_IDX, 0); - return ESP_OK; + /* Connect the SCL pin of the LP_I2C peripheral to the LP_IO Matrix */ + ret = lp_gpio_connect_out_signal(scl_io_num, LP_I2C_SCL_PAD_OUT_IDX, 0, 0); + ret = lp_gpio_connect_in_signal(scl_io_num, LP_I2C_SCL_PAD_IN_IDX, 0); +#endif /* !SOC_LP_GPIO_MATRIX_SUPPORTED */ + + return ret; } static esp_err_t lp_i2c_config_clk(const lp_core_i2c_cfg_t *cfg) @@ -112,10 +132,10 @@ static esp_err_t lp_i2c_config_clk(const lp_core_i2c_cfg_t *cfg) /* LP I2C clock source is mixed with other peripherals in the same register */ PERIPH_RCC_ATOMIC() { lp_i2c_ll_set_source_clk(i2c_hal.dev, source_clk); - } - /* Configure LP I2C timing paramters. source_clk is ignored for LP_I2C in this call */ - i2c_hal_set_bus_timing(&i2c_hal, cfg->i2c_timing_cfg.clk_speed_hz, (i2c_clock_source_t)source_clk, source_freq); + /* Configure LP I2C timing parameters. source_clk is ignored for LP_I2C in this call */ + i2c_hal_set_bus_timing(&i2c_hal, cfg->i2c_timing_cfg.clk_speed_hz, (i2c_clock_source_t)source_clk, source_freq); + } return ret; } @@ -134,12 +154,13 @@ esp_err_t lp_core_i2c_master_init(i2c_port_t lp_i2c_num, const lp_core_i2c_cfg_t PERIPH_RCC_ATOMIC() { /* Enable LP I2C bus clock */ lp_i2c_ll_enable_bus_clock(lp_i2c_num - LP_I2C_NUM_0, true); + /* Reset LP I2C register */ lp_i2c_ll_reset_register(lp_i2c_num - LP_I2C_NUM_0); - } - /* Initialize LP I2C HAL */ - i2c_hal_init(&i2c_hal, lp_i2c_num); + /* Initialize LP I2C HAL */ + i2c_hal_init(&i2c_hal, lp_i2c_num); + } /* Initialize LP I2C Master mode */ i2c_hal_master_init(&i2c_hal); @@ -148,7 +169,7 @@ esp_err_t lp_core_i2c_master_init(i2c_port_t lp_i2c_num, const lp_core_i2c_cfg_t i2c_hal.dev->ctr.sda_force_out = 0; i2c_hal.dev->ctr.scl_force_out = 0; - /* Configure LP I2C clock and timing paramters */ + /* Configure LP I2C clock and timing parameters */ ESP_RETURN_ON_ERROR(lp_i2c_config_clk(cfg), LPI2C_TAG, "Failed to configure LP I2C source clock"); /* Enable SDA and SCL filtering. This configuration matches the HP I2C filter config */ diff --git a/components/ulp/test_apps/lp_core/pytest_lp_core.py b/components/ulp/test_apps/lp_core/pytest_lp_core.py index 6c14deba2a..24fdcd3bdf 100644 --- a/components/ulp/test_apps/lp_core/pytest_lp_core.py +++ b/components/ulp/test_apps/lp_core/pytest_lp_core.py @@ -12,6 +12,7 @@ def test_lp_core(dut: Dut) -> None: @pytest.mark.esp32c6 +# TODO: Enable LP I2C test for esp32p4 (IDF-9407) @pytest.mark.generic_multi_device @pytest.mark.parametrize( 'count', [2], indirect=True diff --git a/examples/system/.build-test-rules.yml b/examples/system/.build-test-rules.yml index 5113c2c41e..d483ebeb81 100644 --- a/examples/system/.build-test-rules.yml +++ b/examples/system/.build-test-rules.yml @@ -276,7 +276,7 @@ examples/system/ulp/lp_core/lp_i2c: disable: - if: IDF_TARGET == "esp32p4" temporary: true - reason: target esp32p4 is not supported yet, TODO IDF-7540 + reason: target esp32p4 is not supported yet, TODO IDF-9407 depends_components: - ulp