|
1 | 1 | /* |
2 | | - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD |
| 2 | + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD |
3 | 3 | * |
4 | 4 | * SPDX-License-Identifier: Apache-2.0 |
5 | 5 | */ |
@@ -68,6 +68,7 @@ static const char *I2C_TAG = "i2c"; |
68 | 68 | #define I2C_CMD_USER_ALLOC_ERR_STR "i2c command link allocation error: the buffer provided is too small." |
69 | 69 | #define I2C_TRANS_MODE_ERR_STR "i2c trans mode error" |
70 | 70 | #define I2C_MODE_ERR_STR "i2c mode error" |
| 71 | +#define I2C_CLEAR_BUS_ERR_STR "clear bus error" |
71 | 72 | #define I2C_SDA_IO_ERR_STR "sda gpio number error" |
72 | 73 | #define I2C_SCL_IO_ERR_STR "scl gpio number error" |
73 | 74 | #define I2C_SCL_SDA_EQUAL_ERR_STR "scl and sda gpio numbers are the same" |
@@ -126,6 +127,8 @@ static const char *I2C_TAG = "i2c"; |
126 | 127 | #define I2C_RCC_ATOMIC() |
127 | 128 | #endif |
128 | 129 |
|
| 130 | +#define I2C_CLR_BUS_TIMEOUT_MS (50) // 50ms is sufficient for clearing the bus |
| 131 | + |
129 | 132 | /** |
130 | 133 | * I2C bus are defined in the header files, let's check that the values are correct |
131 | 134 | */ |
@@ -657,6 +660,7 @@ esp_err_t i2c_get_data_mode(i2c_port_t i2c_num, i2c_trans_mode_t *tx_trans_mode, |
657 | 660 | **/ |
658 | 661 | static esp_err_t i2c_master_clear_bus(i2c_port_t i2c_num) |
659 | 662 | { |
| 663 | + esp_err_t ret = ESP_OK; |
660 | 664 | #if !SOC_I2C_SUPPORT_HW_CLR_BUS |
661 | 665 | const int scl_half_period = I2C_CLR_BUS_HALF_PERIOD_US; // use standard 100kHz data rate |
662 | 666 | int i = 0; |
@@ -685,11 +689,22 @@ static esp_err_t i2c_master_clear_bus(i2c_port_t i2c_num) |
685 | 689 | i2c_set_pin(i2c_num, sda_io, scl_io, 1, 1, I2C_MODE_MASTER); |
686 | 690 | #else |
687 | 691 | i2c_ll_master_clr_bus(i2c_context[i2c_num].hal.dev, I2C_CLR_BUS_SCL_NUM, true); |
| 692 | + // If the i2c master clear bus state machine got disturbed when working, it would go into error state. |
| 693 | + // The solution here is to use freertos tick counter to set a timeout threshold. If it doesn't return on time, |
| 694 | + // return invalid state and turn off the state machine as its always wrong. |
| 695 | + TickType_t start_tick = xTaskGetTickCount(); |
| 696 | + const TickType_t timeout_ticks = pdMS_TO_TICKS(I2C_CLR_BUS_TIMEOUT_MS); |
688 | 697 | while (i2c_ll_master_is_bus_clear_done(i2c_context[i2c_num].hal.dev)) { |
| 698 | + if ((xTaskGetTickCount() - start_tick) > timeout_ticks) { |
| 699 | + ESP_LOGE(I2C_TAG, I2C_CLEAR_BUS_ERR_STR); |
| 700 | + i2c_ll_master_clr_bus(i2c_context[i2c_num].hal.dev, 0, false); |
| 701 | + ret = ESP_ERR_INVALID_STATE; |
| 702 | + break; |
| 703 | + } |
689 | 704 | } |
690 | 705 | i2c_ll_update(i2c_context[i2c_num].hal.dev); |
691 | 706 | #endif |
692 | | - return ESP_OK; |
| 707 | + return ret; |
693 | 708 | } |
694 | 709 |
|
695 | 710 | /**if the power and SDA/SCL wires are in proper condition, everything works find with reading the slave. |
|
0 commit comments