From 1216dd1abd527101813a8caa75157a94535ef172 Mon Sep 17 00:00:00 2001 From: Xiaoyu Liu Date: Thu, 11 Jul 2024 11:28:40 +0800 Subject: [PATCH] change(ulp): bu lp i2c on esp32c5 --- components/hal/esp32c5/include/hal/i2c_ll.h | 95 ++++++++++++++++++- components/soc/esp32c5/i2c_periph.c | 22 +++++ .../esp32c5/include/soc/Kconfig.soc_caps.in | 14 ++- .../soc/esp32c5/include/soc/clk_tree_defs.h | 6 +- .../soc/esp32c5/include/soc/i2c_struct.h | 1 + components/soc/esp32c5/include/soc/soc_caps.h | 9 +- .../soc/esp32c6/include/soc/lp_i2c_struct.h | 2 +- components/ulp/lp_core/lp_core_i2c.c | 15 +-- examples/system/.build-test-rules.yml | 2 +- examples/system/ulp/lp_core/lp_i2c/README.md | 9 +- 10 files changed, 147 insertions(+), 28 deletions(-) diff --git a/components/hal/esp32c5/include/hal/i2c_ll.h b/components/hal/esp32c5/include/hal/i2c_ll.h index 5c6547f292..0e46063988 100644 --- a/components/hal/esp32c5/include/hal/i2c_ll.h +++ b/components/hal/esp32c5/include/hal/i2c_ll.h @@ -19,6 +19,8 @@ #include "soc/pcr_struct.h" #include "hal/i2c_types.h" #include "soc/clk_tree_defs.h" +#include "soc/lp_clkrst_struct.h" +#include "soc/lpperi_struct.h" #include "hal/misc.h" #ifdef __cplusplus @@ -69,7 +71,7 @@ typedef enum { } i2c_ll_slave_intr_t; // Get the I2C hardware instance -#define I2C_LL_GET_HW(i2c_num) (&I2C0) +#define I2C_LL_GET_HW(i2c_num) (((i2c_num) == I2C_NUM_0) ? (&I2C0) : (&LP_I2C)) #define I2C_LL_MASTER_EVENT_INTR (I2C_NACK_INT_ENA_M|I2C_TIME_OUT_INT_ENA_M|I2C_TRANS_COMPLETE_INT_ENA_M|I2C_ARBITRATION_LOST_INT_ENA_M|I2C_END_DETECT_INT_ENA_M) #define I2C_LL_SLAVE_EVENT_INTR (I2C_TRANS_COMPLETE_INT_ENA_M|I2C_TXFIFO_WM_INT_ENA_M|I2C_RXFIFO_WM_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M) #define I2C_LL_SLAVE_RX_EVENT_INTR (I2C_TRANS_COMPLETE_INT_ENA_M | I2C_RXFIFO_WM_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M) @@ -77,6 +79,14 @@ typedef enum { #define I2C_LL_RESET_SLV_SCL_PULSE_NUM_DEFAULT (9) #define I2C_LL_SCL_WAIT_US_VAL_DEFAULT (2500) // Approximate value for SCL timeout regs (in us). +// Record for Pins usage logs + +#define LP_I2C_SCL_PIN_ERR_LOG "SCL pin can only be configured as GPIO#7" +#define LP_I2C_SDA_PIN_ERR_LOG "SDA pin can only be configured as GPIO#6" + +#define LP_I2C_SDA_IOMUX_PAD 6 +#define LP_I2C_SCL_IOMUX_PAD 7 + /** * @brief Calculate I2C bus frequency * Note that the clock accuracy is affected by the external pull-up resistor, @@ -752,6 +762,20 @@ static inline void i2c_ll_master_clr_bus(i2c_dev_t *hw, uint32_t slave_pulses) hw->ctr.conf_upgate = 1; } +/** + * @brief Set the ACK level that the I2C master must send when the Rx FIFO count has reached the threshold value. + * ack_level: 1 (NACK) + * ack_level: 0 (ACK) + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_master_rx_full_ack_level(i2c_dev_t *hw, int ack_level) +{ + hw->ctr.rx_full_ack_level = ack_level; +} + /** * @brief Set I2C source clock * @@ -762,10 +786,73 @@ static inline void i2c_ll_master_clr_bus(i2c_dev_t *hw, uint32_t slave_pulses) */ static inline void i2c_ll_set_source_clk(i2c_dev_t *hw, i2c_clock_source_t src_clk) { + if (hw == &LP_I2C) { + // Do nothing + return; + } + // src_clk : (1) for RTC_CLK, (0) for XTAL PCR.i2c[0].i2c_sclk_conf.i2c_sclk_sel = (src_clk == I2C_CLK_SRC_RC_FAST) ? 1 : 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 + * + * @return None + */ +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 + switch (src_clk) { + case LP_I2C_SCLK_LP_FAST: + LP_CLKRST.lpperi.lp_i2c_clk_sel = 0; + break; + case LP_I2C_SCLK_XTAL_D2: + LP_CLKRST.lpperi.lp_i2c_clk_sel = 1; + break; + default: + // Invalid source clock selected + abort(); + } +} + +/// LP_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.lp_ext_i2c_ck_en = enable; +} + +/// 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.lp_ext_i2c_reset_en = 1; + LPPERI.reset_en.lp_ext_i2c_reset_en = 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 * @@ -774,7 +861,11 @@ static inline void i2c_ll_set_source_clk(i2c_dev_t *hw, i2c_clock_source_t src_c */ static inline void i2c_ll_enable_controller_clock(i2c_dev_t *hw, bool en) { - (void)hw; + if (hw == &LP_I2C) { + // Do nothing + return; + } + PCR.i2c[0].i2c_sclk_conf.i2c_sclk_en = en; } diff --git a/components/soc/esp32c5/i2c_periph.c b/components/soc/esp32c5/i2c_periph.c index 4e87d0c44f..2ad3380e61 100644 --- a/components/soc/esp32c5/i2c_periph.c +++ b/components/soc/esp32c5/i2c_periph.c @@ -10,13 +10,35 @@ /* Bunch of constants for every I2C peripheral: GPIO signals, irqs, hw addr of registers etc */ +typedef enum +{ + LP_I2C_MUX_FUNC = 0, + LP_GPIO_MUX_FUNC = 1, + LP_IO_MUX_FUNC_NUM = 2, + LP_MUX_FUNC_NOT_USED = 0xFF, +} lp_io_mux_func_t; + +static_assert(SOC_I2C_NUM == (SOC_HP_I2C_NUM + SOC_LP_I2C_NUM)); + const i2c_signal_conn_t i2c_periph_signal[SOC_I2C_NUM] = { + /* I2C_NUM_0*/ { .sda_out_sig = I2CEXT0_SDA_OUT_IDX, .sda_in_sig = I2CEXT0_SDA_IN_IDX, .scl_out_sig = I2CEXT0_SCL_OUT_IDX, .scl_in_sig = I2CEXT0_SCL_IN_IDX, + .iomux_func = (uint8_t)LP_MUX_FUNC_NOT_USED, .irq = ETS_I2C_EXT0_INTR_SOURCE, .module = PERIPH_I2C0_MODULE, }, + /* LP_I2C_NUM_0*/ + { + .sda_out_sig = 0, + .sda_in_sig = 0, + .scl_out_sig = 0, + .scl_in_sig = 0, + .iomux_func = (uint8_t)LP_I2C_MUX_FUNC, + .irq = ETS_LP_I2C_INTR_SOURCE, + .module = PERIPH_LP_I2C0_MODULE, + }, }; diff --git a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in index f6d62e0f77..bb2b84db83 100644 --- a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in @@ -167,6 +167,10 @@ config SOC_LP_PERIPHERALS_SUPPORTED bool default y +config SOC_LP_I2C_SUPPORTED + bool + default y + config SOC_ULP_LP_UART_SUPPORTED bool default y @@ -505,7 +509,7 @@ config SOC_DEDIC_PERIPH_ALWAYS_ENABLE config SOC_I2C_NUM int - default 1 + default 2 config SOC_HP_I2C_NUM int @@ -555,6 +559,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 1 diff --git a/components/soc/esp32c5/include/soc/clk_tree_defs.h b/components/soc/esp32c5/include/soc/clk_tree_defs.h index 6c50e48480..178b7d125e 100644 --- a/components/soc/esp32c5/include/soc/clk_tree_defs.h +++ b/components/soc/esp32c5/include/soc/clk_tree_defs.h @@ -347,15 +347,15 @@ typedef enum { // TODO: [ESP32C5] IDF-8694, IDF-8696 (inherit from C6) /** * @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} +#define SOC_LP_I2C_CLKS {SOC_MOD_CLK_RC_FAST, SOC_MOD_CLK_XTAL_D2} /** * @brief Type of LP_I2C clock source. */ typedef enum { // TODO: [ESP32C5] IDF-8695 (inherit from C6) - LP_I2C_SCLK_LP_FAST = SOC_MOD_CLK_RTC_FAST, /*!< LP_I2C source clock is RTC_FAST */ + LP_I2C_SCLK_LP_FAST = SOC_MOD_CLK_RC_FAST, /*!< LP_I2C source clock is RC_FAST */ LP_I2C_SCLK_XTAL_D2 = SOC_MOD_CLK_XTAL_D2, /*!< LP_I2C source clock is XTAL_D2 */ - LP_I2C_SCLK_DEFAULT = SOC_MOD_CLK_RTC_FAST, /*!< LP_I2C source clock default choice is RTC_FAST */ + LP_I2C_SCLK_DEFAULT = SOC_MOD_CLK_RC_FAST, /*!< LP_I2C source clock default choice is RC_FAST */ } soc_periph_lp_i2c_clk_src_t; /////////////////////////////////////////////////SPI//////////////////////////////////////////////////////////////////// diff --git a/components/soc/esp32c5/include/soc/i2c_struct.h b/components/soc/esp32c5/include/soc/i2c_struct.h index 438c849ee4..cbf8ad0d29 100644 --- a/components/soc/esp32c5/include/soc/i2c_struct.h +++ b/components/soc/esp32c5/include/soc/i2c_struct.h @@ -1103,6 +1103,7 @@ typedef struct { } i2c_dev_t; extern i2c_dev_t I2C0; +extern i2c_dev_t LP_I2C; #ifndef __cplusplus _Static_assert(sizeof(i2c_dev_t) == 0x200, "Invalid size of i2c_dev_t structure"); diff --git a/components/soc/esp32c5/include/soc/soc_caps.h b/components/soc/esp32c5/include/soc/soc_caps.h index 05615e3fec..8b4340492a 100644 --- a/components/soc/esp32c5/include/soc/soc_caps.h +++ b/components/soc/esp32c5/include/soc/soc_caps.h @@ -63,7 +63,7 @@ #define SOC_LP_TIMER_SUPPORTED 1 // #define SOC_LP_AON_SUPPORTED 1 // TODO: [ESP32C5] IDF-8638 #define SOC_LP_PERIPHERALS_SUPPORTED 1 -// #define SOC_LP_I2C_SUPPORTED 1 // TODO: [ESP32C5] IDF-8634 +#define SOC_LP_I2C_SUPPORTED 1 #define SOC_ULP_LP_UART_SUPPORTED 1 #define SOC_CLK_TREE_SUPPORTED 1 // #define SOC_ASSIST_DEBUG_SUPPORTED 1 // TODO: [ESP32C5] IDF-8663 @@ -242,8 +242,7 @@ #define SOC_DEDIC_PERIPH_ALWAYS_ENABLE (1) /*!< The dedicated GPIO (a.k.a. fast GPIO) is featured by some customized CPU instructions, which is always enabled */ /*-------------------------- I2C CAPS ----------------------------------------*/ -// ESP32-C5 has 1 I2C -#define SOC_I2C_NUM (1U) +#define SOC_I2C_NUM (2U) #define SOC_HP_I2C_NUM (1U) #define SOC_I2C_FIFO_LEN (32) /*!< I2C hardware FIFO depth */ @@ -263,9 +262,9 @@ /*-------------------------- LP_I2C CAPS -------------------------------------*/ // ESP32-C5 has 1 LP_I2C -// #define SOC_LP_I2C_NUM (1U) +#define SOC_LP_I2C_NUM (1U) -// #define SOC_LP_I2C_FIFO_LEN (16) /*!< LP_I2C hardware FIFO depth */ +#define SOC_LP_I2C_FIFO_LEN (16) /*!< LP_I2C hardware FIFO depth */ /*-------------------------- I2S CAPS ----------------------------------------*/ #define SOC_I2S_NUM (1U) diff --git a/components/soc/esp32c6/include/soc/lp_i2c_struct.h b/components/soc/esp32c6/include/soc/lp_i2c_struct.h index 73b5491287..9cc478be82 100644 --- a/components/soc/esp32c6/include/soc/lp_i2c_struct.h +++ b/components/soc/esp32c6/include/soc/lp_i2c_struct.h @@ -881,7 +881,7 @@ typedef struct lp_i2c_dev_t { volatile lp_i2c_rxfifo_start_addr_reg_t rxfifo_start_addr; } lp_i2c_dev_t; -// We map the LP_I2C instance to the i2c_dev_t struct for convinience of using the same HAL/LL. See soc/i2c_struct.h +// We map the LP_I2C instance to the i2c_dev_t struct for convenience of using the same HAL/LL. See soc/i2c_struct.h //extern lp_i2c_dev_t LP_I2C; #ifndef __cplusplus diff --git a/components/ulp/lp_core/lp_core_i2c.c b/components/ulp/lp_core/lp_core_i2c.c index 0b5db5add8..154af3e38b 100644 --- a/components/ulp/lp_core/lp_core_i2c.c +++ b/components/ulp/lp_core/lp_core_i2c.c @@ -14,12 +14,7 @@ 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 +#if SOC_LP_GPIO_MATRIX_SUPPORTED #include "driver/lp_io.h" #include "soc/lp_gpio_sig_map.h" #endif /* !SOC_LP_GPIO_MATRIX_SUPPORTED */ @@ -94,11 +89,9 @@ static esp_err_t lp_i2c_set_pin(const lp_core_i2c_cfg_t *cfg) ESP_RETURN_ON_ERROR(lp_i2c_configure_io(sda_io_num, sda_pullup_en), LPI2C_TAG, "LP I2C SDA 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; + const i2c_signal_conn_t *p_i2c_pin = &i2c_periph_signal[LP_I2C_NUM_0]; + ret = rtc_gpio_iomux_func_sel(sda_io_num, p_i2c_pin->iomux_func); + ret = rtc_gpio_iomux_func_sel(scl_io_num, p_i2c_pin->iomux_func); #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); diff --git a/examples/system/.build-test-rules.yml b/examples/system/.build-test-rules.yml index ab21bb27be..96426294d8 100644 --- a/examples/system/.build-test-rules.yml +++ b/examples/system/.build-test-rules.yml @@ -301,7 +301,7 @@ examples/system/ulp/lp_core/interrupt: examples/system/ulp/lp_core/lp_i2c: enable: - - if: SOC_LP_I2C_SUPPORTED == 1 + - if: SOC_LP_I2C_SUPPORTED == 1 and SOC_DEEP_SLEEP_SUPPORTED == 1 disable: - if: IDF_TARGET == "esp32p4" temporary: true diff --git a/examples/system/ulp/lp_core/lp_i2c/README.md b/examples/system/ulp/lp_core/lp_i2c/README.md index 3dc7909464..8e5abefe33 100644 --- a/examples/system/ulp/lp_core/lp_i2c/README.md +++ b/examples/system/ulp/lp_core/lp_i2c/README.md @@ -7,13 +7,13 @@ ## Overview -This example demonstrates basic usage of the LP I2C driver from the LP core by reading to and writing from a sensor connected over I2C. +This example demonstrates the basic usage of the LP I2C driver from the LP core by reading to and writing from a sensor connected over I2C. ## How to use example ### Hardware Required -To run this example, you should have a ESP32-C6 based development board as well as a BH1750 sensor. BH1750 is an ambient light sensor. More information about it can be found in the [BH1750 datasheet](https://www.mouser.com/datasheet/2/348/bh1750fvi-e-186247.pdf). +To run this example, you should have an ESP based development board that supports the LP I2C peripheral on the LP Core as well as a BH1750 sensor. BH1750 is an ambient light sensor. More information about it can be found in the [BH1750 datasheet](https://www.mouser.com/datasheet/2/348/bh1750fvi-e-186247.pdf). #### Pin Assignment: @@ -22,9 +22,10 @@ To run this example, you should have a ESP32-C6 based development board as well | | SDA | SCL | | ----------------------- | ------| ------| | ESP32-C6 LP I2C Master | GPIO6 | GPIO7 | +| ESP32-C5 LP I2C Master | GPIO6 | GPIO7 | | BH1750 Sensor | SDA | SCL | -**Note:** There's no need to add an external pull-up resistors for SDA/SCL pin, because the driver enables the internal pull-up resistors. +**Note:** There's no need to add external pull-up resistors for SDA/SCL pin, because the driver enables the internal pull-up resistors. ### Build and Flash @@ -51,7 +52,7 @@ LP core woke up the main CPU Lux = 3 Entering deep sleep... -(When the BH1750 sensor is exposed to a direct light source, the Lux value should be larger and the LP core should wakup the main CPU) +(When the BH1750 sensor is exposed to a direct light source, the Lux value should be larger and the LP core should wakeup the main CPU) LP core woke up the main CPU Lux = 1222