diff --git a/components/ulp/lp_core/lp_core_i2c.c b/components/ulp/lp_core/lp_core_i2c.c index 0d41f7fba1..0b5db5add8 100644 --- a/components/ulp/lp_core/lp_core_i2c.c +++ b/components/ulp/lp_core/lp_core_i2c.c @@ -53,9 +53,10 @@ static esp_err_t lp_i2c_gpio_is_cfg_valid(gpio_num_t sda_io_num, gpio_num_t scl_ static esp_err_t lp_i2c_configure_io(gpio_num_t io_num, bool pullup_en) { + /* Set the IO pin to high to avoid them from toggling from Low to High state during initialization. This can register a spurious I2C start condition. */ + ESP_RETURN_ON_ERROR(rtc_gpio_set_level(io_num, 1), LPI2C_TAG, "LP GPIO failed to set level to high for %d", io_num); /* Initialize IO Pin */ ESP_RETURN_ON_ERROR(rtc_gpio_init(io_num), LPI2C_TAG, "LP GPIO Init failed for GPIO %d", io_num); - /* Set direction to input+output open-drain mode */ ESP_RETURN_ON_ERROR(rtc_gpio_set_direction(io_num, RTC_GPIO_MODE_INPUT_OUTPUT_OD), LPI2C_TAG, "LP GPIO Set direction failed for %d", io_num); /* Disable pulldown on the io pin */ @@ -82,12 +83,16 @@ static esp_err_t lp_i2c_set_pin(const lp_core_i2c_cfg_t *cfg) /* Verify that the LP I2C GPIOs are valid */ ESP_RETURN_ON_ERROR(lp_i2c_gpio_is_cfg_valid(sda_io_num, scl_io_num), LPI2C_TAG, "LP I2C GPIO config invalid"); - /* Initialize SDA Pin */ - ESP_RETURN_ON_ERROR(lp_i2c_configure_io(sda_io_num, sda_pullup_en), LPI2C_TAG, "LP I2C SDA pin config failed"); + // NOTE: We always initialize the SCL pin first, then the SDA pin. + // This order of initialization is important to avoid any spurious + // I2C start conditions on the bus. /* 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"); + /* Initialize SDA Pin */ + 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; @@ -123,7 +128,7 @@ static esp_err_t lp_i2c_config_clk(const lp_core_i2c_cfg_t *cfg) } } - /* Fetch the clock source fequency */ + /* Fetch the clock source frequency */ ESP_RETURN_ON_ERROR(esp_clk_tree_src_get_freq_hz(source_clk, ESP_CLK_TREE_SRC_FREQ_PRECISION_APPROX, &source_freq), LPI2C_TAG, "Invalid LP I2C source clock selected"); /* Verify that the I2C_SCLK operates at a frequency 20 times larger than the requested SCL bus frequency */ @@ -162,6 +167,9 @@ esp_err_t lp_core_i2c_master_init(i2c_port_t lp_i2c_num, const lp_core_i2c_cfg_t i2c_hal_init(&i2c_hal, lp_i2c_num); } + /* Clear any pending interrupts */ + i2c_ll_clear_intr_mask(i2c_hal.dev, UINT32_MAX); + /* Initialize LP I2C Master mode */ i2c_hal_master_init(&i2c_hal); diff --git a/components/ulp/ulp_riscv/ulp_riscv_i2c.c b/components/ulp/ulp_riscv/ulp_riscv_i2c.c index 3d73b22e37..138d479642 100644 --- a/components/ulp/ulp_riscv/ulp_riscv_i2c.c +++ b/components/ulp/ulp_riscv/ulp_riscv_i2c.c @@ -72,6 +72,8 @@ static esp_err_t i2c_gpio_is_cfg_valid(gpio_num_t sda_io_num, gpio_num_t scl_io_ static esp_err_t i2c_configure_io(gpio_num_t io_num, bool pullup_en) { + /* Set the IO pin to high to avoid them from toggling from Low to High state during initialization. This can register a spurious I2C start condition. */ + ESP_RETURN_ON_ERROR(rtc_gpio_set_level(io_num, 1), RTCI2C_TAG, "RTC GPIO failed to set level to high for %d", io_num); /* Initialize IO Pin */ ESP_RETURN_ON_ERROR(rtc_gpio_init(io_num), RTCI2C_TAG, "RTC GPIO Init failed for GPIO %d", io_num); /* Set direction to input+output */ @@ -98,12 +100,16 @@ static esp_err_t i2c_set_pin(const ulp_riscv_i2c_cfg_t *cfg) /* Verify that the I2C GPIOs are valid */ ESP_RETURN_ON_ERROR(i2c_gpio_is_cfg_valid(sda_io_num, scl_io_num), RTCI2C_TAG, "RTC I2C GPIO config invalid"); - /* Initialize SDA Pin */ - ESP_RETURN_ON_ERROR(i2c_configure_io(sda_io_num, sda_pullup_en), RTCI2C_TAG, "RTC I2C SDA pin config failed"); + // NOTE: We always initialize the SCL pin first, then the SDA pin. + // This order of initialization is important to avoid any spurious + // I2C start conditions on the bus. /* Initialize SCL Pin */ ESP_RETURN_ON_ERROR(i2c_configure_io(scl_io_num, scl_pullup_en), RTCI2C_TAG, "RTC I2C SCL pin config failed"); + /* Initialize SDA Pin */ + ESP_RETURN_ON_ERROR(i2c_configure_io(sda_io_num, sda_pullup_en), RTCI2C_TAG, "RTC I2C SDA pin config failed"); + /* Route SDA IO signal to the RTC subsystem */ rtc_io_dev->touch_pad[sda_io_num].mux_sel = 1; @@ -471,6 +477,12 @@ esp_err_t ulp_riscv_i2c_master_init(const ulp_riscv_i2c_cfg_t *cfg) WRITE_PERI_REG(RTC_I2C_CTRL_REG, 0); WRITE_PERI_REG(SENS_SAR_I2C_CTRL_REG, 0); + /* Verify that the input cfg param is valid */ + ESP_RETURN_ON_FALSE(cfg, ESP_ERR_INVALID_ARG, RTCI2C_TAG, "RTC I2C configuration is NULL"); + + /* Configure RTC I2C GPIOs */ + ESP_RETURN_ON_ERROR(i2c_set_pin(cfg), RTCI2C_TAG, "Failed to configure RTC I2C GPIOs"); + /* Reset RTC I2C */ #if CONFIG_IDF_TARGET_ESP32S2 i2c_dev->ctrl.i2c_reset = 1; @@ -484,12 +496,6 @@ esp_err_t ulp_riscv_i2c_master_init(const ulp_riscv_i2c_cfg_t *cfg) CLEAR_PERI_REG_MASK(SENS_SAR_PERI_RESET_CONF_REG, SENS_RTC_I2C_RESET); #endif // CONFIG_IDF_TARGET_ESP32S2 - /* Verify that the input cfg param is valid */ - ESP_RETURN_ON_FALSE(cfg, ESP_ERR_INVALID_ARG, RTCI2C_TAG, "RTC I2C configuration is NULL"); - - /* Configure RTC I2C GPIOs */ - ESP_RETURN_ON_ERROR(i2c_set_pin(cfg), RTCI2C_TAG, "Failed to configure RTC I2C GPIOs"); - /* Enable internal open-drain mode for SDA and SCL lines */ #if CONFIG_IDF_TARGET_ESP32S2 i2c_dev->ctrl.sda_force_out = 0; @@ -519,6 +525,9 @@ esp_err_t ulp_riscv_i2c_master_init(const ulp_riscv_i2c_cfg_t *cfg) /* Configure RTC I2C timing parameters */ ESP_RETURN_ON_ERROR(i2c_set_timing(cfg), RTCI2C_TAG, "Failed to configure RTC I2C timing"); + /* Clear any pending interrupts */ + WRITE_PERI_REG(RTC_I2C_INT_CLR_REG, UINT32_MAX); + /* Enable RTC I2C interrupts */ SET_PERI_REG_MASK(RTC_I2C_INT_ENA_REG, RTC_I2C_RX_DATA_INT_ENA | RTC_I2C_TX_DATA_INT_ENA |