mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
fix(lp-i2c): Fixed the generation of spurious I2C start with lp-i2c
This commit fixes an issue with LP I2C and RTC I2C where in the peripherals generated a spurious I2C start condition when initialized. This caused some sensors to not respond properly to the following read or write request. Closes https://github.com/espressif/esp-idf/issues/14043 Closes https://github.com/espressif/esp-idf/issues/11608
This commit is contained in:
parent
17a18e8849
commit
2d331c0413
@ -45,9 +45,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)
|
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 */
|
/* Initialize IO Pin */
|
||||||
ESP_RETURN_ON_ERROR(rtc_gpio_init(io_num), LPI2C_TAG, "LP GPIO Init failed for GPIO %d", io_num);
|
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 */
|
/* 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);
|
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 */
|
/* Disable pulldown on the io pin */
|
||||||
@ -72,12 +73,16 @@ static esp_err_t lp_i2c_set_pin(const lp_core_i2c_cfg_t *cfg)
|
|||||||
/* Verify that the LP I2C GPIOs are valid */
|
/* 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");
|
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 */
|
// NOTE: We always initialize the SCL pin first, then the SDA pin.
|
||||||
ESP_RETURN_ON_ERROR(lp_i2c_configure_io(sda_io_num, sda_pullup_en), LPI2C_TAG, "LP I2C SDA pin config failed");
|
// This order of initialization is important to avoid any spurious
|
||||||
|
// I2C start conditions on the bus.
|
||||||
|
|
||||||
/* Initialize SCL Pin */
|
/* 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");
|
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");
|
||||||
|
|
||||||
/* Select LP I2C function for the SDA Pin */
|
/* Select LP I2C function for the SDA Pin */
|
||||||
lp_io_dev->gpio[sda_io_num].mcu_sel = 1;
|
lp_io_dev->gpio[sda_io_num].mcu_sel = 1;
|
||||||
|
|
||||||
@ -103,7 +108,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");
|
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 */
|
/* Verify that the I2C_SCLK operates at a frequency 20 times larger than the requested SCL bus frequency */
|
||||||
@ -141,6 +146,9 @@ esp_err_t lp_core_i2c_master_init(i2c_port_t lp_i2c_num, const lp_core_i2c_cfg_t
|
|||||||
/* Initialize LP I2C HAL */
|
/* Initialize LP I2C HAL */
|
||||||
i2c_hal_init(&i2c_hal, lp_i2c_num);
|
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 */
|
/* Initialize LP I2C Master mode */
|
||||||
i2c_hal_master_init(&i2c_hal);
|
i2c_hal_master_init(&i2c_hal);
|
||||||
|
|
||||||
|
@ -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)
|
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 */
|
/* Initialize IO Pin */
|
||||||
ESP_RETURN_ON_ERROR(rtc_gpio_init(io_num), RTCI2C_TAG, "RTC GPIO Init failed for GPIO %d", io_num);
|
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 */
|
/* 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 */
|
/* 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");
|
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 */
|
// NOTE: We always initialize the SCL pin first, then the SDA pin.
|
||||||
ESP_RETURN_ON_ERROR(i2c_configure_io(sda_io_num, sda_pullup_en), RTCI2C_TAG, "RTC I2C SDA pin config failed");
|
// This order of initialization is important to avoid any spurious
|
||||||
|
// I2C start conditions on the bus.
|
||||||
|
|
||||||
/* Initialize SCL Pin */
|
/* Initialize SCL Pin */
|
||||||
ESP_RETURN_ON_ERROR(i2c_configure_io(scl_io_num, scl_pullup_en), RTCI2C_TAG, "RTC I2C SCL pin config failed");
|
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 */
|
/* Route SDA IO signal to the RTC subsystem */
|
||||||
rtc_io_dev->touch_pad[sda_io_num].mux_sel = 1;
|
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(RTC_I2C_CTRL_REG, 0);
|
||||||
WRITE_PERI_REG(SENS_SAR_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 */
|
/* Reset RTC I2C */
|
||||||
#if CONFIG_IDF_TARGET_ESP32S2
|
#if CONFIG_IDF_TARGET_ESP32S2
|
||||||
i2c_dev->ctrl.i2c_reset = 1;
|
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);
|
CLEAR_PERI_REG_MASK(SENS_SAR_PERI_RESET_CONF_REG, SENS_RTC_I2C_RESET);
|
||||||
#endif // CONFIG_IDF_TARGET_ESP32S2
|
#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 */
|
/* Enable internal open-drain mode for SDA and SCL lines */
|
||||||
#if CONFIG_IDF_TARGET_ESP32S2
|
#if CONFIG_IDF_TARGET_ESP32S2
|
||||||
i2c_dev->ctrl.sda_force_out = 0;
|
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 */
|
/* Configure RTC I2C timing parameters */
|
||||||
ESP_RETURN_ON_ERROR(i2c_set_timing(cfg), RTCI2C_TAG, "Failed to configure RTC I2C timing");
|
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 */
|
/* Enable RTC I2C interrupts */
|
||||||
SET_PERI_REG_MASK(RTC_I2C_INT_ENA_REG, RTC_I2C_RX_DATA_INT_ENA |
|
SET_PERI_REG_MASK(RTC_I2C_INT_ENA_REG, RTC_I2C_RX_DATA_INT_ENA |
|
||||||
RTC_I2C_TX_DATA_INT_ENA |
|
RTC_I2C_TX_DATA_INT_ENA |
|
||||||
|
Loading…
Reference in New Issue
Block a user