diff --git a/components/driver/i2c/i2c.c b/components/driver/i2c/i2c.c index 89e016454c..bd0475017c 100644 --- a/components/driver/i2c/i2c.c +++ b/components/driver/i2c/i2c.c @@ -129,13 +129,13 @@ static const char *I2C_TAG = "i2c"; /** * I2C bus are defined in the header files, let's check that the values are correct */ -#if SOC_I2C_NUM >= 2 +#if SOC_HP_I2C_NUM >= 2 _Static_assert(I2C_NUM_1 == 1, "I2C_NUM_1 must be equal to 1"); -#endif // SOC_I2C_NUM >= 2 +#endif // SOC_HP_I2C_NUM >= 2 #if SOC_LP_I2C_SUPPORTED -_Static_assert(I2C_NUM_MAX == (SOC_I2C_NUM + SOC_LP_I2C_NUM), "I2C_NUM_MAX must be equal to SOC_I2C_NUM + SOC_LP_I2C_NUM"); +_Static_assert(I2C_NUM_MAX == (SOC_HP_I2C_NUM + SOC_LP_I2C_NUM), "I2C_NUM_MAX must be equal to SOC_HP_I2C_NUM + SOC_LP_I2C_NUM"); #else -_Static_assert(I2C_NUM_MAX == SOC_I2C_NUM, "I2C_NUM_MAX must be equal to SOC_I2C_NUM"); +_Static_assert(I2C_NUM_MAX == SOC_HP_I2C_NUM, "I2C_NUM_MAX must be equal to SOC_HP_I2C_NUM"); #endif /* SOC_LP_I2C_SUPPORTED */ typedef struct { @@ -225,7 +225,7 @@ static i2c_context_t i2c_context[I2C_NUM_MAX] = { I2C_CONTEX_INIT_DEF(I2C_NUM_0), /* Now that I2C_NUM_MAX is part of an enum (i2c_port_t), we cannot use * it anomore in the preprocessor! */ -#if SOC_I2C_NUM > 1 +#if SOC_HP_I2C_NUM > 1 I2C_CONTEX_INIT_DEF(I2C_NUM_1), #endif }; diff --git a/components/driver/test_apps/legacy_i2c_driver/main/test_i2c.c b/components/driver/test_apps/legacy_i2c_driver/main/test_i2c.c index 26fe72b1e3..6dc5967b0a 100644 --- a/components/driver/test_apps/legacy_i2c_driver/main/test_i2c.c +++ b/components/driver/test_apps/legacy_i2c_driver/main/test_i2c.c @@ -47,11 +47,11 @@ #define READ_BIT I2C_MASTER_READ /*!< I2C master read */ #define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/ -static DRAM_ATTR i2c_dev_t *const I2C[SOC_I2C_NUM] = { &I2C0, -#if SOC_I2C_NUM > 1 - &I2C1, +static DRAM_ATTR i2c_dev_t *const I2C[SOC_HP_I2C_NUM] = { &I2C0, +#if SOC_HP_I2C_NUM > 1 + &I2C1, #endif - }; + }; #define ACK_VAL 0 #define NACK_VAL 1 @@ -503,7 +503,7 @@ static void i2c_slave_repeat_read(void) TEST_CASE_MULTIPLE_DEVICES("I2C repeat write test", "[i2c][test_env=generic_multi_device][timeout=150]", i2c_master_repeat_write, i2c_slave_repeat_read); -#if SOC_I2C_NUM > 1 +#if SOC_HP_I2C_NUM > 1 static void i2c_master_write_test_more_ports(void) { diff --git a/components/esp_driver_i2c/i2c_common.c b/components/esp_driver_i2c/i2c_common.c index cdc6c18dd2..fea6f4d139 100644 --- a/components/esp_driver_i2c/i2c_common.c +++ b/components/esp_driver_i2c/i2c_common.c @@ -27,6 +27,12 @@ #include "esp_clk_tree.h" #include "clk_ctrl_os.h" #include "esp_private/gpio.h" +#if SOC_LP_I2C_SUPPORTED +#include "hal/rtc_io_ll.h" +#include "driver/rtc_io.h" +#include "soc/rtc_io_channel.h" +#include "driver/lp_io.h" +#endif #if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP #include "esp_private/sleep_retention.h" #endif @@ -69,22 +75,38 @@ static esp_err_t s_i2c_bus_handle_acquire(i2c_port_num_t port_num, i2c_bus_handl bus->port_num = port_num; bus->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; bus->bus_mode = mode; + bus->is_lp_i2c = (bus->port_num < SOC_HP_I2C_NUM) ? false : true; #if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && !CONFIG_IDF_TARGET_ESP32P4 // TODO: IDF-9353 - sleep_retention_module_init_param_t init_param = { - .cbs = { .create = { .handle = s_i2c_sleep_retention_init, .arg = (void *)bus } } - }; - ret = sleep_retention_module_init(I2C_SLEEP_RETENTION_MODULE(port_num), &init_param); - if (ret == ESP_OK) { - sleep_retention_module_allocate(I2C_SLEEP_RETENTION_MODULE(port_num)); + if (bus->is_lp_i2c == false) { + sleep_retention_module_init_param_t init_param = { + .cbs = { .create = { .handle = s_i2c_sleep_retention_init, .arg = (void *)bus } } + }; + ret = sleep_retention_module_init(I2C_SLEEP_RETENTION_MODULE(port_num), &init_param); + if (ret == ESP_OK) { + sleep_retention_module_allocate(I2C_SLEEP_RETENTION_MODULE(port_num)); + } + } else { + ESP_LOGW(TAG, "Detected PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP is enabled while LP_I2C is used. Sleep retention is not supported on LP I2C. Please use it properly"); } #endif // Enable the I2C module - I2C_RCC_ATOMIC() { - i2c_ll_enable_bus_clock(bus->port_num, true); - i2c_ll_reset_register(bus->port_num); + if (!bus->is_lp_i2c) { + I2C_RCC_ATOMIC() { + i2c_ll_enable_bus_clock(bus->port_num, true); + i2c_ll_reset_register(bus->port_num); + } } +#if SOC_LP_I2C_SUPPORTED + else { + LP_I2C_BUS_CLK_ATOMIC() { + lp_i2c_ll_enable_bus_clock(bus->port_num - SOC_HP_I2C_NUM, true); + lp_i2c_ll_reset_register(bus->port_num - SOC_HP_I2C_NUM); + } + } +#endif + I2C_CLOCK_SRC_ATOMIC() { i2c_hal_init(&bus->hal, port_num); } @@ -117,7 +139,7 @@ esp_err_t i2c_acquire_bus_handle(i2c_port_num_t port_num, i2c_bus_handle_t *i2c_ esp_err_t ret = ESP_OK; _lock_acquire(&s_i2c_platform.mutex); if (port_num == -1) { - for (int i = 0; i < SOC_I2C_NUM; i++) { + for (int i = 0; i < SOC_HP_I2C_NUM; i++) { bus_occupied = i2c_bus_occupied(i); if (bus_occupied == false) { ret = s_i2c_bus_handle_acquire(i, i2c_new_bus, mode); @@ -154,9 +176,11 @@ esp_err_t i2c_release_bus_handle(i2c_bus_handle_t i2c_bus) do_deinitialize = true; s_i2c_platform.buses[port_num] = NULL; #if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && !CONFIG_IDF_TARGET_ESP32P4 // TODO: IDF-9353 - esp_err_t err = sleep_retention_module_free(I2C_SLEEP_RETENTION_MODULE(port_num)); - if (err == ESP_OK) { - err = sleep_retention_module_deinit(I2C_SLEEP_RETENTION_MODULE(port_num)); + if (i2c_bus->is_lp_i2c == false) { + esp_err_t err = sleep_retention_module_free(I2C_SLEEP_RETENTION_MODULE(port_num)); + if (err == ESP_OK) { + err = sleep_retention_module_deinit(I2C_SLEEP_RETENTION_MODULE(port_num)); + } } #endif if (i2c_bus->intr_handle) { @@ -166,9 +190,18 @@ esp_err_t i2c_release_bus_handle(i2c_bus_handle_t i2c_bus) ESP_RETURN_ON_ERROR(esp_pm_lock_delete(i2c_bus->pm_lock), TAG, "delete pm_lock failed"); } // Disable I2C module - I2C_RCC_ATOMIC() { - i2c_ll_enable_bus_clock(port_num, false); + if (!i2c_bus->is_lp_i2c) { + I2C_RCC_ATOMIC() { + i2c_ll_enable_bus_clock(port_num, false); + } } +#if SOC_LP_I2C_SUPPORTED + else { + LP_I2C_BUS_CLK_ATOMIC() { + lp_i2c_ll_enable_bus_clock(port_num - SOC_HP_I2C_NUM, false); + } + } +#endif free(i2c_bus); } } @@ -192,7 +225,7 @@ esp_err_t i2c_release_bus_handle(i2c_bus_handle_t i2c_bus) return ESP_OK; } -esp_err_t i2c_select_periph_clock(i2c_bus_handle_t handle, i2c_clock_source_t clk_src) +esp_err_t i2c_select_periph_clock(i2c_bus_handle_t handle, soc_module_clk_t clk_src) { esp_err_t ret = ESP_OK; ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "I2C empty controller handle"); @@ -211,7 +244,7 @@ esp_err_t i2c_select_periph_clock(i2c_bus_handle_t handle, i2c_clock_source_t cl // TODO: [clk_tree] to use a generic clock enable/disable or acquire/release function for all clock source #if SOC_I2C_SUPPORT_RTC - if (clk_src == I2C_CLK_SRC_RC_FAST) { + if (clk_src == (soc_module_clk_t)I2C_CLK_SRC_RC_FAST) { // RC_FAST clock is not enabled automatically on start up, we enable it here manually. // Note there's a ref count in the enable/disable function, we must call them in pair in the driver. periph_rtc_dig_clk8m_enable(); @@ -229,19 +262,24 @@ esp_err_t i2c_select_periph_clock(i2c_bus_handle_t handle, i2c_clock_source_t cl esp_pm_lock_type_t pm_lock_type = ESP_PM_NO_LIGHT_SLEEP; #if SOC_I2C_SUPPORT_RTC - if (clk_src == I2C_CLK_SRC_RC_FAST) { + if (clk_src == (soc_module_clk_t)I2C_CLK_SRC_RC_FAST) { // I2C use fifo, which connected to APB, so we cannot use I2C either when in light sleep. - need_pm_lock = ESP_PM_NO_LIGHT_SLEEP; + pm_lock_type = ESP_PM_NO_LIGHT_SLEEP; } #endif // SOC_I2C_SUPPORT_RTC #if SOC_I2C_SUPPORT_APB - if (clk_src == I2C_CLK_SRC_APB) { + if (clk_src == (soc_module_clk_t)I2C_CLK_SRC_APB) { // APB clock frequency can be changed during DFS pm_lock_type = ESP_PM_APB_FREQ_MAX; } #endif // SOC_I2C_SUPPORT_APB + if (handle->is_lp_i2c) { + // Even for LP I2C, the clock will also be powered down when going into light sleep. + pm_lock_type = ESP_PM_NO_LIGHT_SLEEP; + } + if (need_pm_lock) { sprintf(handle->pm_lock_name, "I2C_%d", handle->port_num); // e.g. PORT_0 ret = esp_pm_lock_create(pm_lock_type, 0, handle->pm_lock_name, &handle->pm_lock); @@ -253,10 +291,8 @@ esp_err_t i2c_select_periph_clock(i2c_bus_handle_t handle, i2c_clock_source_t cl return ret; } -esp_err_t i2c_common_set_pins(i2c_bus_handle_t handle) +static esp_err_t s_hp_i2c_pins_config(i2c_bus_handle_t handle) { - esp_err_t ret = ESP_OK; - ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "I2C empty controller handle"); int port_id = handle->port_num; // SDA pin configurations @@ -286,5 +322,71 @@ esp_err_t i2c_common_set_pins(i2c_bus_handle_t handle) gpio_func_sel(handle->scl_num, PIN_FUNC_GPIO); esp_rom_gpio_connect_out_signal(handle->scl_num, i2c_periph_signal[port_id].scl_out_sig, 0, 0); esp_rom_gpio_connect_in_signal(handle->scl_num, i2c_periph_signal[port_id].scl_in_sig, 0); + + return ESP_OK; +} + +#if SOC_LP_I2C_SUPPORTED + +static esp_err_t s_lp_i2c_pins_config(i2c_bus_handle_t handle) +{ + ESP_RETURN_ON_ERROR(!rtc_gpio_is_valid_gpio(handle->sda_num), TAG, "LP I2C SDA GPIO invalid"); + ESP_RETURN_ON_ERROR(!rtc_gpio_is_valid_gpio(handle->scl_num), 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 */ + ESP_RETURN_ON_FALSE((handle->sda_num == LP_I2C_SDA_IOMUX_PAD), ESP_ERR_INVALID_ARG, TAG, LP_I2C_SDA_PIN_ERR_LOG); + ESP_RETURN_ON_FALSE((handle->scl_num == LP_I2C_SCL_IOMUX_PAD), ESP_ERR_INVALID_ARG, TAG, LP_I2C_SCL_PIN_ERR_LOG); +#endif /* !SOC_LP_GPIO_MATRIX_SUPPORTED */ + int port_id = handle->port_num; + + rtc_gpio_init(handle->sda_num); + rtc_gpio_set_direction(handle->sda_num, RTC_GPIO_MODE_INPUT_OUTPUT_OD); + rtc_gpio_pulldown_dis(handle->sda_num); + if (handle->pull_up_enable) { + rtc_gpio_pullup_en(handle->sda_num); + } else { + rtc_gpio_pullup_dis(handle->sda_num); + } +#if !SOC_LP_GPIO_MATRIX_SUPPORTED + rtc_gpio_iomux_func_sel(handle->sda_num, i2c_periph_signal[port_id].iomux_func); +#else + lp_gpio_connect_out_signal(handle->sda_num, i2c_periph_signal[port_id].scl_out_sig, 0, 0); + lp_gpio_connect_in_signal(handle->sda_num, i2c_periph_signal[port_id].scl_in_sig, 0); +#endif + + rtc_gpio_init(handle->scl_num); + rtc_gpio_set_direction(handle->scl_num, RTC_GPIO_MODE_INPUT_OUTPUT_OD); + rtc_gpio_pulldown_dis(handle->scl_num); + if (handle->pull_up_enable) { + rtc_gpio_pullup_en(handle->scl_num); + } else { + rtc_gpio_pullup_dis(handle->scl_num); + } +#if !SOC_LP_GPIO_MATRIX_SUPPORTED + rtc_gpio_iomux_func_sel(handle->scl_num, i2c_periph_signal[port_id].iomux_func); +#else + lp_gpio_connect_out_signal(handle->scl_num, i2c_periph_signal[port_id].sda_out_sig, 0, 0); + lp_gpio_connect_in_signal(handle->scl_num, i2c_periph_signal[port_id].sda_in_sig, 0); +#endif + + return ESP_OK; +} + +#endif // SOC_LP_I2C_SUPPORTED + +esp_err_t i2c_common_set_pins(i2c_bus_handle_t handle) +{ + esp_err_t ret = ESP_OK; + + if (handle->is_lp_i2c == false) { + ESP_RETURN_ON_ERROR(s_hp_i2c_pins_config(handle), TAG, "config i2c pins failed"); + } +#if SOC_LP_I2C_SUPPORTED + else { + ESP_RETURN_ON_ERROR(s_lp_i2c_pins_config(handle), TAG, "config i2c lp pins failed"); + } +#endif + return ret; } diff --git a/components/esp_driver_i2c/i2c_master.c b/components/esp_driver_i2c/i2c_master.c index ea2d4e614b..4fe138d4eb 100644 --- a/components/esp_driver_i2c/i2c_master.c +++ b/components/esp_driver_i2c/i2c_master.c @@ -40,6 +40,12 @@ static const char *TAG = "i2c.master"; #define I2C_ADDRESS_TRANS_WRITE(device_address) (((device_address) << 1) | 0) #define I2C_ADDRESS_TRANS_READ(device_address) (((device_address) << 1) | 1) +#if SOC_LP_I2C_SUPPORTED +#define I2C_FIFO_LEN(port_num) (((port_num) < SOC_HP_I2C_NUM) ? SOC_I2C_FIFO_LEN : SOC_LP_I2C_FIFO_LEN) +#else +#define I2C_FIFO_LEN(port_num) (SOC_I2C_FIFO_LEN) +#endif + static esp_err_t s_i2c_master_clear_bus(i2c_bus_handle_t handle) { #if !SOC_I2C_SUPPORT_HW_CLR_BUS @@ -136,7 +142,7 @@ static bool s_i2c_write_command(i2c_master_bus_handle_t i2c_master, i2c_operatio uint8_t data_fill = 0; // data_fill refers to the length to fill the data - data_fill = MIN(remaining_bytes, SOC_I2C_FIFO_LEN - *address_fill); + data_fill = MIN(remaining_bytes, I2C_FIFO_LEN(i2c_master->base->port_num) - *address_fill); write_pr = i2c_operation->data + i2c_operation->bytes_used; i2c_operation->bytes_used += data_fill; hw_cmd.byte_num = data_fill + *address_fill; @@ -216,13 +222,13 @@ static bool s_i2c_read_command(i2c_master_bus_handle_t i2c_master, i2c_operation i2c_bus_handle_t handle = i2c_master->base; i2c_ll_hw_cmd_t hw_cmd = i2c_operation->hw_cmd; - *fifo_fill = MIN(remaining_bytes, SOC_I2C_FIFO_LEN - i2c_master->read_len_static); + *fifo_fill = MIN(remaining_bytes, I2C_FIFO_LEN(i2c_master->base->port_num) - i2c_master->read_len_static); i2c_master->rx_cnt = *fifo_fill; hw_cmd.byte_num = *fifo_fill; i2c_master->contains_read = true; #if !SOC_I2C_STOP_INDEPENDENT - if (remaining_bytes < SOC_I2C_FIFO_LEN - 1) { + if (remaining_bytes < I2C_FIFO_LEN(i2c_master->base->port_num) - 1) { if (i2c_operation->hw_cmd.ack_val == ACK_VAL) { if (remaining_bytes != 0) { i2c_ll_master_write_cmd_reg(hal->dev, hw_cmd, i2c_master->cmd_idx); @@ -531,8 +537,20 @@ static esp_err_t s_i2c_transaction_start(i2c_master_dev_handle_t i2c_dev, int xf i2c_master->read_len_static = 0; i2c_hal_master_set_scl_timeout_val(hal, i2c_dev->scl_wait_us, i2c_master->base->clk_src_freq_hz); + + if (!i2c_master->base->is_lp_i2c) { + I2C_CLOCK_SRC_ATOMIC() { + i2c_ll_set_source_clk(hal->dev, i2c_master->base->clk_src); + } + } +#if SOC_LP_I2C_SUPPORTED + else { + LP_I2C_SRC_CLK_ATOMIC() { + lp_i2c_ll_set_source_clk(hal->dev, i2c_master->base->clk_src); + } + } +#endif I2C_CLOCK_SRC_ATOMIC() { - i2c_ll_set_source_clk(hal->dev, i2c_master->base->clk_src); i2c_hal_set_bus_timing(hal, i2c_dev->scl_speed_hz, i2c_master->base->clk_src, i2c_master->base->clk_src_freq_hz); } i2c_ll_master_set_fractional_divider(hal->dev, 0, 0); @@ -692,7 +710,8 @@ static esp_err_t i2c_param_master_config(i2c_bus_handle_t handle, const i2c_mast i2c_hal_context_t *hal = &handle->hal; ESP_RETURN_ON_ERROR(i2c_common_set_pins(handle), TAG, "i2c master set pin failed"); - ESP_RETURN_ON_ERROR(i2c_select_periph_clock(handle, i2c_conf->clk_source), TAG, "i2c select clock failed"); + soc_module_clk_t clk_source = i2c_conf->clk_source; + ESP_RETURN_ON_ERROR(i2c_select_periph_clock(handle, clk_source), TAG, "i2c select clock failed"); handle->clk_src = i2c_conf->clk_source; portENTER_CRITICAL(&handle->spinlock); i2c_hal_master_init(hal); diff --git a/components/esp_driver_i2c/i2c_private.h b/components/esp_driver_i2c/i2c_private.h index 58a07b376c..8cf6b3b680 100644 --- a/components/esp_driver_i2c/i2c_private.h +++ b/components/esp_driver_i2c/i2c_private.h @@ -36,6 +36,11 @@ extern "C" { #define I2C_RCC_ATOMIC() #endif +#if SOC_LP_I2C_SUPPORTED +#define LP_I2C_SRC_CLK_ATOMIC() PERIPH_RCC_ATOMIC() +#define LP_I2C_BUS_CLK_ATOMIC() PERIPH_RCC_ATOMIC() +#endif + #if CONFIG_I2C_ISR_IRAM_SAFE #define I2C_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) #else @@ -100,9 +105,10 @@ typedef struct { struct i2c_bus_t { i2c_port_num_t port_num; // Port(Bus) ID, index from 0 + bool is_lp_i2c; // true if current port is lp_i2c. false is hp_i2c portMUX_TYPE spinlock; // To protect pre-group register level concurrency access i2c_hal_context_t hal; // Hal layer for each port(bus) - i2c_clock_source_t clk_src; // Record the port clock source + soc_module_clk_t clk_src; // Record the port clock source uint32_t clk_src_freq_hz; // Record the clock source frequency int sda_num; // SDA pin number int scl_num; // SCL pin number @@ -232,7 +238,7 @@ esp_err_t i2c_release_bus_handle(i2c_bus_handle_t i2c_bus); * - ESP_ERR_INVALID_STATE: Set clock source failed because the clk_src is different from other I2C controller * - ESP_FAIL: Set clock source failed because of other error */ -esp_err_t i2c_select_periph_clock(i2c_bus_handle_t handle, i2c_clock_source_t clk_src); +esp_err_t i2c_select_periph_clock(i2c_bus_handle_t handle, soc_module_clk_t clk_src); /** * @brief Set I2C SCL/SDA pins diff --git a/components/esp_driver_i2c/i2c_slave.c b/components/esp_driver_i2c/i2c_slave.c index 99d821c286..6b000ef66e 100644 --- a/components/esp_driver_i2c/i2c_slave.c +++ b/components/esp_driver_i2c/i2c_slave.c @@ -188,7 +188,10 @@ esp_err_t i2c_new_slave_device(const i2c_slave_config_t *slave_config, i2c_slave i2c_slave_dev_t *i2c_slave = NULL; ESP_RETURN_ON_FALSE(slave_config && ret_handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); ESP_RETURN_ON_FALSE(GPIO_IS_VALID_GPIO(slave_config->sda_io_num) && GPIO_IS_VALID_GPIO(slave_config->scl_io_num), ESP_ERR_INVALID_ARG, TAG, "invalid SDA/SCL pin number"); - ESP_RETURN_ON_FALSE(slave_config->i2c_port < SOC_I2C_NUM || slave_config->i2c_port == -1, ESP_ERR_INVALID_ARG, TAG, "invalid i2c port number"); +#if SOC_LP_I2C_SUPPORTED + ESP_RETURN_ON_FALSE(slave_config->i2c_port != (SOC_I2C_NUM - 1), ESP_ERR_NOT_SUPPORTED, TAG, "LP i2c is not supported in I2C slave"); +#endif + ESP_RETURN_ON_FALSE(slave_config->i2c_port < SOC_HP_I2C_NUM || slave_config->i2c_port == -1, ESP_ERR_INVALID_ARG, TAG, "invalid i2c port number"); ESP_RETURN_ON_FALSE((slave_config->send_buf_depth > 0), ESP_ERR_INVALID_ARG, TAG, "invalid SCL speed"); #if SOC_I2C_SLAVE_SUPPORT_BROADCAST ESP_RETURN_ON_FALSE(((slave_config->addr_bit_len != I2C_ADDR_BIT_LEN_10) || (!slave_config->flags.broadcast_en)), ESP_ERR_INVALID_STATE, TAG, "10bits address cannot used together with broadcast"); diff --git a/components/esp_driver_i2c/include/driver/i2c_master.h b/components/esp_driver_i2c/include/driver/i2c_master.h index 0375f2283d..795493f25d 100644 --- a/components/esp_driver_i2c/include/driver/i2c_master.h +++ b/components/esp_driver_i2c/include/driver/i2c_master.h @@ -19,10 +19,15 @@ extern "C" { * @brief I2C master bus specific configurations */ typedef struct { - i2c_port_num_t i2c_port; /*!< I2C port number, `-1` for auto selecting */ + i2c_port_num_t i2c_port; /*!< I2C port number, `-1` for auto selecting, (not include LP I2C instance) */ gpio_num_t sda_io_num; /*!< GPIO number of I2C SDA signal, pulled-up internally */ gpio_num_t scl_io_num; /*!< GPIO number of I2C SCL signal, pulled-up internally */ - i2c_clock_source_t clk_source; /*!< Clock source of I2C master bus, channels in the same group must use the same clock source */ + union { + i2c_clock_source_t clk_source; /*!< Clock source of I2C master bus */ +#if SOC_LP_I2C_SUPPORTED + lp_i2c_clock_source_t lp_source_clk; /*!< LP_UART source clock selection */ +#endif + }; uint8_t glitch_ignore_cnt; /*!< If the glitch period on the line is less than this value, it can be filtered out, typically value is 7 (unit: I2C module clock cycle)*/ int intr_priority; /*!< I2C interrupt priority, if set to 0, driver will select the default priority (1,2,3). */ size_t trans_queue_depth; /*!< Depth of internal transfer queue, increase this value can support more transfers pending in the background, only valid in asynchronous transaction. (Typically max_device_num * per_transaction)*/ diff --git a/components/esp_driver_i2c/test_apps/i2c_test_apps/main/CMakeLists.txt b/components/esp_driver_i2c/test_apps/i2c_test_apps/main/CMakeLists.txt index c49b446df4..2f653da9ae 100644 --- a/components/esp_driver_i2c/test_apps/i2c_test_apps/main/CMakeLists.txt +++ b/components/esp_driver_i2c/test_apps/i2c_test_apps/main/CMakeLists.txt @@ -21,6 +21,10 @@ if(CONFIG_SOC_I2C_SUPPORT_10BIT_ADDR AND CONFIG_SOC_I2C_SUPPORT_SLAVE) list(APPEND srcs "test_i2c_10bit.c") endif() +if(CONFIG_SOC_LP_I2C_SUPPORTED) + list(APPEND srcs "test_lp_i2c.c") +endif() + # Only build this file with `CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP` and `CONFIG_IEEE802154_ENABLED` enabled # Enable `CONFIG_IEEE802154_ENABLED` is for modem domain really power down. # This reliable can be removed if the sleep retention got finished. diff --git a/components/esp_driver_i2c/test_apps/i2c_test_apps/main/test_board.h b/components/esp_driver_i2c/test_apps/i2c_test_apps/main/test_board.h index e420180d5a..4a48f624f4 100644 --- a/components/esp_driver_i2c/test_apps/i2c_test_apps/main/test_board.h +++ b/components/esp_driver_i2c/test_apps/i2c_test_apps/main/test_board.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -25,6 +25,11 @@ extern "C" { #define I2C_MASTER_SDA_IO 2 /*!< gpio number for I2C master data */ #endif +#if SOC_LP_I2C_SUPPORTED +#define LP_I2C_SCL_IO 7 +#define LP_I2C_SDA_IO 6 +#endif + #define ESP_SLAVE_ADDR 0x28 /*!< ESP_I2C slave address, you can set any 7bit value */ #define TEST_I2C_PORT 0 #define DATA_LENGTH 100 diff --git a/components/esp_driver_i2c/test_apps/i2c_test_apps/main/test_i2c_common.c b/components/esp_driver_i2c/test_apps/i2c_test_apps/main/test_i2c_common.c index 843f8de715..d9991248bd 100644 --- a/components/esp_driver_i2c/test_apps/i2c_test_apps/main/test_i2c_common.c +++ b/components/esp_driver_i2c/test_apps/i2c_test_apps/main/test_i2c_common.c @@ -55,7 +55,7 @@ TEST_CASE("I2C bus install-uninstall test", "[i2c]") }; i2c_master_bus_handle_t i2c_mst_handle1; -#if SOC_I2C_NUM > 1 +#if SOC_HP_I2C_NUM > 1 i2c_master_bus_config_t i2c_mst_config_2 = { .clk_source = I2C_CLK_SRC_DEFAULT, .i2c_port = 1, @@ -68,7 +68,7 @@ TEST_CASE("I2C bus install-uninstall test", "[i2c]") // Install master bus 0 ESP_LOGI(TAG, "Initialize bus0"); TEST_ESP_OK(i2c_new_master_bus(&i2c_mst_config_1, &i2c_mst_handle1)); -#if SOC_I2C_NUM > 1 +#if SOC_HP_I2C_NUM > 1 // Install master bus 1 ESP_LOGI(TAG, "Initialize bus1"); TEST_ESP_OK(i2c_new_master_bus(&i2c_mst_config_2, &i2c_mst_handle2)); @@ -78,7 +78,7 @@ TEST_CASE("I2C bus install-uninstall test", "[i2c]") TEST_ESP_ERR(ESP_ERR_INVALID_STATE, i2c_new_master_bus(&i2c_mst_config_1, &i2c_mst_handle1)); ESP_LOGI(TAG, "Delete bus0"); TEST_ESP_OK(i2c_del_master_bus(i2c_mst_handle1)); -#if SOC_I2C_NUM > 1 +#if SOC_HP_I2C_NUM > 1 ESP_LOGI(TAG, "Delete bus1"); TEST_ESP_OK(i2c_del_master_bus(i2c_mst_handle2)); #endif diff --git a/components/esp_driver_i2c/test_apps/i2c_test_apps/main/test_i2c_multi.c b/components/esp_driver_i2c/test_apps/i2c_test_apps/main/test_i2c_multi.c index 13004ef1ef..652bd53793 100644 --- a/components/esp_driver_i2c/test_apps/i2c_test_apps/main/test_i2c_multi.c +++ b/components/esp_driver_i2c/test_apps/i2c_test_apps/main/test_i2c_multi.c @@ -613,7 +613,7 @@ static void slave_init_for_probe(void) TEST_CASE_MULTIPLE_DEVICES("I2C master probe slave test", "[i2c][test_env=generic_multi_device][timeout=150]", master_probe_slave, slave_init_for_probe); -#if SOC_I2C_NUM > 1 +#if SOC_HP_I2C_NUM > 1 // Now chips with multiple I2C controllers are up to 2, can test more ports when we have more I2C controllers. static void i2c_master_write_test_more_port(void) { diff --git a/components/esp_driver_i2c/test_apps/i2c_test_apps/main/test_lp_i2c.c b/components/esp_driver_i2c/test_apps/i2c_test_apps/main/test_lp_i2c.c new file mode 100644 index 0000000000..c9701e41b7 --- /dev/null +++ b/components/esp_driver_i2c/test_apps/i2c_test_apps/main/test_lp_i2c.c @@ -0,0 +1,154 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#include +#include +#include "sdkconfig.h" +#include "unity.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "esp_err.h" +#include "soc/gpio_periph.h" +#include "soc/clk_tree_defs.h" +#include "soc/soc_caps.h" +#include "hal/gpio_hal.h" +#include "hal/uart_ll.h" +#include "esp_private/periph_ctrl.h" +#include "driver/gpio.h" +#include "driver/i2c_master.h" +#include "driver/i2c_slave.h" +#include "esp_rom_gpio.h" +#include "esp_log.h" +#include "test_utils.h" +#include "test_board.h" + +#define DATA_LENGTH 100 + +static QueueHandle_t s_receive_queue; + +TEST_CASE("LP I2C initialize on i2c slave", "[i2c]") +{ + i2c_slave_config_t i2c_slv_config = { + .addr_bit_len = I2C_ADDR_BIT_LEN_7, + .clk_source = LP_I2C_SCLK_DEFAULT, + .i2c_port = LP_I2C_NUM_0, + .send_buf_depth = 256, + .scl_io_num = LP_I2C_SCL_IO, + .sda_io_num = LP_I2C_SDA_IO, + .slave_addr = 0x58, + }; + + i2c_slave_dev_handle_t slave_handle; + TEST_ESP_ERR(ESP_ERR_NOT_SUPPORTED, i2c_new_slave_device(&i2c_slv_config, &slave_handle)); +} + +#if CONFIG_IDF_TARGET_ESP32C6 + +TEST_CASE("LP I2C initialize with wrong IO", "[i2c]") +{ + i2c_master_bus_config_t i2c_mst_config = { + .lp_source_clk = LP_I2C_SCLK_DEFAULT, + .i2c_port = LP_I2C_NUM_0, + .scl_io_num = 5, + .sda_io_num = 6, + .flags.enable_internal_pullup = true, + }; + i2c_master_bus_handle_t bus_handle; + + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, i2c_new_master_bus(&i2c_mst_config, &bus_handle)); +} + +#endif + +static IRAM_ATTR bool test_i2c_rx_done_callback(i2c_slave_dev_handle_t channel, const i2c_slave_rx_done_event_data_t *edata, void *user_data) +{ + BaseType_t high_task_wakeup = pdFALSE; + QueueHandle_t receive_queue = (QueueHandle_t)user_data; + xQueueSendFromISR(receive_queue, edata, &high_task_wakeup); + return high_task_wakeup == pdTRUE; +} + +static void lp_i2c_master_write_test(void) +{ + uint8_t data_wr[DATA_LENGTH] = { 0 }; + int i; + + i2c_master_bus_config_t i2c_mst_config = { + .lp_source_clk = LP_I2C_SCLK_DEFAULT, + .i2c_port = LP_I2C_NUM_0, + .scl_io_num = LP_I2C_SCL_IO, + .sda_io_num = LP_I2C_SDA_IO, + .flags.enable_internal_pullup = true, + }; + i2c_master_bus_handle_t bus_handle; + + TEST_ESP_OK(i2c_new_master_bus(&i2c_mst_config, &bus_handle)); + + i2c_device_config_t dev_cfg = { + .dev_addr_length = I2C_ADDR_BIT_LEN_7, + .device_address = 0x58, + .scl_speed_hz = 100000, + }; + + i2c_master_dev_handle_t dev_handle; + TEST_ESP_OK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle)); + + unity_wait_for_signal("i2c slave init finish"); + + unity_send_signal("master write"); + for (i = 0; i < DATA_LENGTH; i++) { + data_wr[i] = i; + } + + disp_buf(data_wr, i); + TEST_ESP_OK(i2c_master_transmit(dev_handle, data_wr, DATA_LENGTH, -1)); + unity_wait_for_signal("ready to delete"); + TEST_ESP_OK(i2c_master_bus_rm_device(dev_handle)); + + TEST_ESP_OK(i2c_del_master_bus(bus_handle)); +} + +static void hp_i2c_slave_read_test(void) +{ + uint8_t data_rd[DATA_LENGTH] = {0}; + + i2c_slave_config_t i2c_slv_config = { + .addr_bit_len = I2C_ADDR_BIT_LEN_7, + .clk_source = I2C_CLK_SRC_DEFAULT, + .i2c_port = TEST_I2C_PORT, + .send_buf_depth = 256, + .scl_io_num = LP_I2C_SCL_IO, + .sda_io_num = LP_I2C_SDA_IO, + .slave_addr = 0x58, + }; + + i2c_slave_dev_handle_t slave_handle; + TEST_ESP_OK(i2c_new_slave_device(&i2c_slv_config, &slave_handle)); + + s_receive_queue = xQueueCreate(1, sizeof(i2c_slave_rx_done_event_data_t)); + i2c_slave_event_callbacks_t cbs = { + .on_recv_done = test_i2c_rx_done_callback, + }; + ESP_ERROR_CHECK(i2c_slave_register_event_callbacks(slave_handle, &cbs, s_receive_queue)); + + i2c_slave_rx_done_event_data_t rx_data; + TEST_ESP_OK(i2c_slave_receive(slave_handle, data_rd, DATA_LENGTH)); + + unity_send_signal("i2c slave init finish"); + + unity_wait_for_signal("master write"); + xQueueReceive(s_receive_queue, &rx_data, pdMS_TO_TICKS(10000)); + disp_buf(data_rd, DATA_LENGTH); + for (int i = 0; i < DATA_LENGTH; i++) { + TEST_ASSERT(data_rd[i] == i); + } + vQueueDelete(s_receive_queue); + unity_send_signal("ready to delete"); + TEST_ESP_OK(i2c_del_slave_device(slave_handle)); +} + +TEST_CASE_MULTIPLE_DEVICES("LP_I2C master write slave test", "[i2c][test_env=generic_multi_device][timeout=150]", lp_i2c_master_write_test, hp_i2c_slave_read_test); diff --git a/components/hal/esp32c6/include/hal/i2c_ll.h b/components/hal/esp32c6/include/hal/i2c_ll.h index 303f47bd7f..5d0ce895d3 100644 --- a/components/hal/esp32c6/include/hal/i2c_ll.h +++ b/components/hal/esp32c6/include/hal/i2c_ll.h @@ -77,6 +77,14 @@ typedef enum { #define I2C_LL_RESET_SLV_SCL_PULSE_NUM_DEFAULT (9) #define I2C_LL_SCL_WAIT_US_VAL_DEFAULT (2000) // 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 + // I2C sleep retention module #define I2C_SLEEP_RETENTION_MODULE(i2c_num) (SLEEP_RETENTION_MODULE_I2C0) @@ -619,7 +627,7 @@ static inline void i2c_ll_get_stop_timing(i2c_dev_t *hw, int *setup_time, int *h * * @param hw Beginning address of the peripheral registers * @param ptr Pointer to data buffer - * @param len Amount of data needs to be writen + * @param len Amount of data needs to be written * * @return None. */ @@ -654,7 +662,7 @@ static inline void i2c_ll_read_rxfifo(i2c_dev_t *hw, uint8_t *ptr, uint8_t len) * @param hw Beginning address of the peripheral registers * @param ram_offset Offset value of I2C RAM. * @param ptr Pointer to data buffer - * @param len Amount of data needs to be writen + * @param len Amount of data needs to be written */ static inline void i2c_ll_write_by_nonfifo(i2c_dev_t *hw, uint8_t ram_offset, const uint8_t *ptr, uint8_t len) { @@ -754,7 +762,7 @@ static inline void i2c_ll_master_clr_bus(i2c_dev_t *hw, uint32_t slave_pulses) hw->scl_sp_conf.scl_rst_slv_num = slave_pulses; hw->scl_sp_conf.scl_rst_slv_en = 1; hw->ctr.conf_upgate = 1; - // hardward will clear scl_rst_slv_en after sending SCL pulses, + // hardware will clear scl_rst_slv_en after sending SCL pulses, // and we should set conf_upgate bit to synchronize register value. while (hw->scl_sp_conf.scl_rst_slv_en); hw->ctr.conf_upgate = 1; @@ -1003,7 +1011,7 @@ typedef enum { * @brief Configure I2C SCL timing * * @param hw Beginning address of the peripheral registers - * @param high_period The I2C SCL hight period (in core clock cycle, hight_period > 2) + * @param high_period The I2C SCL height period (in core clock cycle, hight_period > 2) * @param low_period The I2C SCL low period (in core clock cycle, low_period > 1) * @param wait_high_period The I2C SCL wait rising edge period. * @@ -1191,7 +1199,7 @@ static inline void i2c_ll_slave_disable_rx_it(i2c_dev_t *hw) * @brief Configure I2C SCL timing * * @param hw Beginning address of the peripheral registers - * @param hight_period The I2C SCL hight period (in core clock cycle, hight_period > 2) + * @param hight_period The I2C SCL height period (in core clock cycle, hight_period > 2) * @param low_period The I2C SCL low period (in core clock cycle, low_period > 1) * * @return None. diff --git a/components/hal/include/hal/i2c_types.h b/components/hal/include/hal/i2c_types.h index e264b2aff2..6a0d685ac7 100644 --- a/components/hal/include/hal/i2c_types.h +++ b/components/hal/include/hal/i2c_types.h @@ -21,9 +21,9 @@ extern "C" { */ typedef enum { I2C_NUM_0 = 0, /*!< I2C port 0 */ -#if SOC_I2C_NUM >= 2 +#if SOC_HP_I2C_NUM >= 2 I2C_NUM_1, /*!< I2C port 1 */ -#endif /* SOC_I2C_NUM >= 2 */ +#endif /* SOC_HP_I2C_NUM >= 2 */ #if SOC_LP_I2C_NUM >= 1 LP_I2C_NUM_0, /*< LP_I2C port 0 */ #endif /* SOC_LP_I2C_NUM >= 1 */ @@ -44,9 +44,9 @@ typedef enum { * @brief Data structure for calculating I2C bus timing. */ typedef struct { - uint16_t clkm_div; /*!< I2C core clock devider */ + uint16_t clkm_div; /*!< I2C core clock divider */ uint16_t scl_low; /*!< I2C scl low period */ - uint16_t scl_high; /*!< I2C scl hight period */ + uint16_t scl_high; /*!< I2C scl high period */ uint16_t scl_wait_high; /*!< I2C scl wait_high period */ uint16_t sda_hold; /*!< I2C scl low period */ uint16_t sda_sample; /*!< I2C sda sample time */ @@ -103,6 +103,14 @@ typedef enum { * @brief I2C group clock source */ typedef soc_periph_i2c_clk_src_t i2c_clock_source_t; + +#if SOC_LP_I2C_SUPPORTED +/** + * @brief LP_UART source clock + */ +typedef soc_periph_lp_i2c_clk_src_t lp_i2c_clock_source_t; +#endif + #else /** * @brief Default type diff --git a/components/soc/esp32/include/soc/Kconfig.soc_caps.in b/components/soc/esp32/include/soc/Kconfig.soc_caps.in index 681a6ad4c6..74c4785aa7 100644 --- a/components/soc/esp32/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32/include/soc/Kconfig.soc_caps.in @@ -355,6 +355,10 @@ config SOC_I2C_NUM int default 2 +config SOC_HP_I2C_NUM + int + default 2 + config SOC_I2C_FIFO_LEN int default 32 diff --git a/components/soc/esp32/include/soc/soc_caps.h b/components/soc/esp32/include/soc/soc_caps.h index 56c66ff9ce..75f7c65f86 100644 --- a/components/soc/esp32/include/soc/soc_caps.h +++ b/components/soc/esp32/include/soc/soc_caps.h @@ -193,7 +193,8 @@ /*-------------------------- I2C CAPS ----------------------------------------*/ // ESP32 has 2 I2C -#define SOC_I2C_NUM (2) +#define SOC_I2C_NUM (2U) +#define SOC_HP_I2C_NUM (2) #define SOC_I2C_FIFO_LEN (32) /*!< I2C hardware FIFO depth */ #define SOC_I2C_CMD_REG_NUM (16) /*!< Number of I2C command registers */ diff --git a/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in index 53065ab507..6ec5f77a73 100644 --- a/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in @@ -327,6 +327,10 @@ config SOC_I2C_NUM int default 1 +config SOC_HP_I2C_NUM + int + default 1 + config SOC_I2C_FIFO_LEN int default 16 diff --git a/components/soc/esp32c2/include/soc/soc_caps.h b/components/soc/esp32c2/include/soc/soc_caps.h index 2603de1fdc..5c37049f98 100644 --- a/components/soc/esp32c2/include/soc/soc_caps.h +++ b/components/soc/esp32c2/include/soc/soc_caps.h @@ -148,6 +148,7 @@ /*-------------------------- I2C CAPS ----------------------------------------*/ // ESP32-C2 has 1 I2C #define SOC_I2C_NUM (1U) +#define SOC_HP_I2C_NUM (1U) #define SOC_I2C_FIFO_LEN (16) /*!< I2C hardware FIFO depth */ #define SOC_I2C_CMD_REG_NUM (8) /*!< Number of I2C command registers */ diff --git a/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in index 13eb7f41f8..768f815ee0 100644 --- a/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in @@ -419,6 +419,10 @@ config SOC_I2C_NUM int default 1 +config SOC_HP_I2C_NUM + int + default 1 + config SOC_I2C_FIFO_LEN int default 32 diff --git a/components/soc/esp32c3/include/soc/soc_caps.h b/components/soc/esp32c3/include/soc/soc_caps.h index f28180e086..bf66d1a0d1 100644 --- a/components/soc/esp32c3/include/soc/soc_caps.h +++ b/components/soc/esp32c3/include/soc/soc_caps.h @@ -186,6 +186,7 @@ /*-------------------------- I2C CAPS ----------------------------------------*/ // ESP32-C3 has 1 I2C #define SOC_I2C_NUM (1U) +#define SOC_HP_I2C_NUM (1U) #define SOC_I2C_FIFO_LEN (32) /*!< I2C hardware FIFO depth */ #define SOC_I2C_CMD_REG_NUM (8) /*!< Number of I2C command registers */ diff --git a/components/soc/esp32c5/beta3/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/beta3/include/soc/Kconfig.soc_caps.in index 340a8367e3..842a9a6363 100644 --- a/components/soc/esp32c5/beta3/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/beta3/include/soc/Kconfig.soc_caps.in @@ -263,6 +263,10 @@ config SOC_I2C_NUM int default 1 +config SOC_HP_I2C_NUM + int + default 1 + config SOC_I2C_FIFO_LEN int default 32 diff --git a/components/soc/esp32c5/beta3/include/soc/soc_caps.h b/components/soc/esp32c5/beta3/include/soc/soc_caps.h index c08f107938..c75b8a0a7c 100644 --- a/components/soc/esp32c5/beta3/include/soc/soc_caps.h +++ b/components/soc/esp32c5/beta3/include/soc/soc_caps.h @@ -234,7 +234,8 @@ /*-------------------------- I2C CAPS ----------------------------------------*/ // ESP32-C5 has 1 I2C -#define SOC_I2C_NUM (1UL) +#define SOC_I2C_NUM (1U) +#define SOC_HP_I2C_NUM (1U) #define SOC_I2C_FIFO_LEN (32) /*!< I2C hardware FIFO depth */ #define SOC_I2C_CMD_REG_NUM (8) /*!< Number of I2C command registers */ diff --git a/components/soc/esp32c5/mp/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/mp/include/soc/Kconfig.soc_caps.in index 509e443f1c..8a35af3366 100644 --- a/components/soc/esp32c5/mp/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/mp/include/soc/Kconfig.soc_caps.in @@ -131,6 +131,10 @@ config SOC_I2C_NUM int default 1 +config SOC_HP_I2C_NUM + int + default 1 + config SOC_LEDC_SUPPORT_PLL_DIV_CLOCK bool default y diff --git a/components/soc/esp32c5/mp/include/soc/soc_caps.h b/components/soc/esp32c5/mp/include/soc/soc_caps.h index 9a2b1760ca..ff5b0531a3 100644 --- a/components/soc/esp32c5/mp/include/soc/soc_caps.h +++ b/components/soc/esp32c5/mp/include/soc/soc_caps.h @@ -208,7 +208,7 @@ // Support to hold a single digital I/O when the digital domain is powered off #define SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP (1) -// The Clock Out singnal is route to the pin by GPIO matrix +// The Clock Out signal is route to the pin by GPIO matrix // #define SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX (1) /*-------------------------- RTCIO CAPS --------------------------------------*/ @@ -227,7 +227,8 @@ /*-------------------------- I2C CAPS ----------------------------------------*/ // ESP32-C5 has 1 I2C -#define SOC_I2C_NUM (1UL) +#define SOC_I2C_NUM (1U) +#define SOC_HP_I2C_NUM (1U) // #define SOC_I2C_FIFO_LEN (32) /*!< I2C hardware FIFO depth */ // #define SOC_I2C_CMD_REG_NUM (8) /*!< Number of I2C command registers */ @@ -501,7 +502,7 @@ // #define SOC_PM_SUPPORT_BEACON_WAKEUP (1) // #define SOC_PM_SUPPORT_BT_WAKEUP (1) // #define SOC_PM_SUPPORT_EXT1_WAKEUP (1) -// #define SOC_PM_SUPPORT_EXT1_WAKEUP_MODE_PER_PIN (1) /*! *I2C Controller (I2C)* > *Features* [`PDF <{IDF_TARGET_TRM_EN_URL}#i2c>`__]. + + You can use LP I2C peripheral when HP I2C is not sufficient for users' usage. But please note again the LP I2C does not support all HP I2C functions. Please read docs before you use it. Typically, an I2C slave device has a 7-bit address or 10-bit address. {IDF_TARGET_NAME} supports both I2C Standard-mode (Sm) and Fast-mode (Fm) which can go up to 100KHz and 400KHz respectively. @@ -134,6 +140,38 @@ Once the :cpp:type:`i2c_device_config_t` structure is populated with mandatory p i2c_master_dev_handle_t dev_handle; ESP_ERROR_CHECK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle)); +.. only:: SOC_LP_I2C_SUPPORTED + + Install I2C master bus with LP I2C Peripheral + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Install I2C master bus with LP I2C peripheral is almost as same as how HP I2C peripheral is installed. However, there are still some difference user should take focus on including IOs, clock sources, i2c port number, etc. Following code will show you how to install I2C master bus with LP_I2C. + + .. code:: c + + #include "driver/i2c_master.h" + + i2c_master_bus_config_t i2c_mst_config = { + .clk_source = LP_I2C_SCLK_DEFAULT, // clock source for LP i2c, might different from HP I2C + .i2c_port = LP_I2C_NUM_0, // Assign to LP I2C port + .scl_io_num = 7, // SCL IO number. Please refer to technical reference manual + .sda_io_num = 6, // SDA IO number. Please refer to technical reference manual + .glitch_ignore_cnt = 7, + .flags.enable_internal_pullup = true, + }; + + i2c_master_bus_handle_t bus_handle; + ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_mst_config, &bus_handle)); + + i2c_device_config_t dev_cfg = { + .dev_addr_length = I2C_ADDR_BIT_LEN_7, + .device_address = 0x58, + .scl_speed_hz = 100000, + }; + + i2c_master_dev_handle_t dev_handle; + ESP_ERROR_CHECK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle)); + Uninstall I2C master bus and device ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -292,7 +330,7 @@ Simple example for writing and reading from slave: ESP_ERROR_CHECK(i2c_master_bus_add_device(I2C_PORT_NUM_0, &dev_cfg, &dev_handle)); uint8_t buf[20] = {0x20}; uint8_t buffer[2]; - ESP_ERROR_CHECK(i2c_master_transmit_receive(i2c_bus_handle, buf, sizeof(buf), buffer, 2, -1)); + ESP_ERROR_CHECK(i2c_master_transmit_receive(dev_handle, buf, sizeof(buf), buffer, 2, -1)); I2C Master Probe ~~~~~~~~~~~~~~~~