Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TW#13148] i2c timeout error #680

Closed
tdesmet opened this issue Jun 8, 2017 · 22 comments
Closed

[TW#13148] i2c timeout error #680

tdesmet opened this issue Jun 8, 2017 · 22 comments
Assignees

Comments

@tdesmet
Copy link

tdesmet commented Jun 8, 2017

I'm polling a i2c device every half second and after a while (sometimes 4 minutes, sometimes half an hour). The i2c_master_cmd_begin function returns ESP_ERR_TIMEOUT, and every next call to i2c_master_cmd_begin returns ESP_ERR_TIMEOUT.

I tried deleting the driver using i2c_driver_delete and then i2c_driver_install but it keeps giving the error.

At this time the SDA line remains low and the SCL line remains high. I also tried to delete the driver and then change the pins to output and change to no avail.

The device I am communicating with is a battery monitor (LC709203F). But I have the same problem with an accelerometer.

init code

    i2c_config_t conf;
    conf.mode = I2C_MODE_MASTER;
    conf.sda_io_num = I2C_MASTER_SDA_IO;
    conf.sda_pullup_en = GPIO_PULLUP_DISABLE;
    conf.scl_io_num = I2C_MASTER_SCL_IO;
    conf.scl_pullup_en = GPIO_PULLUP_DISABLE;
    conf.master.clk_speed = I2C_MASTER_FREQ_HZ;
    i2c_param_config(I2C_MASTER_NUM, &conf);
    i2c_driver_install(I2C_MASTER_NUM, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);

communication code

    int ret = 0;
    uint8_t crc = 0, crc_read, valh, vall;
    i2c_cmd_handle_t cmd;

    cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, ( FG_SLAVE_ADDR << 1 ) | WRITE_BIT, ACK_CHECK_EN);
    i2c_master_write_byte(cmd, command, ACK_CHECK_EN);
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, ( FG_SLAVE_ADDR << 1 ) | READ_BIT, ACK_CHECK_EN);
    i2c_master_read_byte(cmd, &vall, ACK_VAL);
    i2c_master_read_byte(cmd, &valh, ACK_VAL);
    i2c_master_read_byte(cmd, &crc_read, NACK_VAL);
    i2c_master_stop(cmd);
    ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_RATE_MS);
    i2c_cmd_link_delete(cmd);

@FayeY FayeY changed the title i2c timeout error [TW#13148] i2c timeout error Jun 9, 2017
@Curclamas
Copy link
Contributor

Maybe this could be related to espressif/arduino-esp32#349 . I've noticed similar things when I poll some I2C-GPIO-Expander every 20ms. At some point the request will either always fail or just lock up.

@tdesmet
Copy link
Author

tdesmet commented Jun 13, 2017

debugging a bit more it seems something locks up the lines. I tried disconnecting the device but the lines remain in their locked state.

This is really frustrating as the only solution seems to be to reset the device when this happens. But that means data loss since we use the esp32 to measure sensors continuously and report this data to the cloud.
Well we can continue our measurements but we will be missing all info we get via i2c (battery and accelerometer at this point).

Edit: This time during debugging both SCL and SDA remain low...

@Curclamas
Copy link
Contributor

Curclamas commented Jun 19, 2017

Also this kind of problem seams to be noticed in the forum:

I would guess this more widespread than one may think.

@tbnobody
Copy link

I think I have the same problem but with a DS3231 / DS1307. The interesting thing is, that I have exactly your behavior using the ESP-IDF. But if I use the ESP-Arduino SDK (as a component in IDF) it works without any problems.

@Sermus
Copy link

Sermus commented Sep 11, 2017

+1.
I experience this with ft6206 touch controller and mvh3002d temperature/humidity sensor.

@costaud
Copy link
Collaborator

costaud commented Sep 13, 2017

Weird, is there a soft reboot during reading the I2C slave?

@Sermus
Copy link

Sermus commented Sep 13, 2017

Nop, there is no soft reboot (until i force it)

@chegewara
Copy link
Contributor

I have no problem with I2C and MPU6050, even i can polling every 20ms, but im having problem with mcp23017.

@costaud
Copy link
Collaborator

costaud commented Oct 18, 2017

The patch will be merged into master branch soon

@Curclamas
Copy link
Contributor

Curclamas commented Oct 18, 2017 via email

@costaud
Copy link
Collaborator

costaud commented Oct 18, 2017

The state machine of I2C bus could be dead if the bus is influenced in some circumstance(for example, short the sda/scl to gnd for a while). The hardware would get stuck and be always sending clock on scl or only sending a single pulse on scl. We can only reset the I2C hardware to get the hardware back working.

To reset the hardware, we can call periph_module_disable then periph_module_enable, but all the register settings will be lost. We will try to merge this patch ASAP. In the next version of chips, we will find some way to void this situation.

@costaud costaud self-assigned this Oct 18, 2017
igrr pushed a commit that referenced this issue Oct 23, 2017
Reported from different sources from github or bbs:

#680

#922

We tested reading several sensor or other I2C slave devices, if the power and SDA/SCL wires are in proper condition, everything works find with reading the slave.
If we remove the power supply for the slave during I2C is reading, or directly connect SDA or SCL to ground, this would  cause the I2C FSM get stuck in wrong state, all we can do is the reset the I2C hardware in this case.
After this commit, no matter whether the power supply of I2C slave is removed or SDA / SCL are shorted to ground, the driver can recover from wrong state.

We are not sure whether this the save issue with the reported one yet, but to make the driver more robust.

Further information:

1. For I2C master mode, we have tested different situations, e.g., to short the SDA/SCL directly to GND/VCC, to short the SDA to SCL, to un-plug the slave device, to power off the slave device. Under all of those situations, this version of driver can recover and keep working.
2. Some slave device will die by accident and keep the SDA in low level, in this case, master should send several clock to make the slave release the bus.
3. Slave mode of ESP32 might also get in wrong state that held the SDA low, in this case, master device could send a stop signal to make esp32 slave release the bus.

Modifications:

1. Disable I2C_MASTER_TRAN_COMP interrupt to void extra interrupt.
2. Disable un-used timeout interrupt for slave.
3. Add bus reset if error detected for master mode.
4. Add bus clear if SDA level is low when error detected.
5. Modify the argument type of i2c_set_pin.
6. add API to set timeout value
7. add parameter check for timing APIs
@FayeY FayeY closed this as completed Nov 21, 2017
@AmrutaCh
Copy link

AmrutaCh commented Apr 22, 2019

I am facing the same issue with I2C example provided in idf.
ESP32 Arduino works as expected whereas esp-idf gives the following errors

  • timeout : 0x107 (generated by I2C_STATUS_TIMEOUT)
  • failed: -1 (generated by I2C_STATUS_ACK_ERROR)

The slave is an Arduino device.

ESP-idf version: v3.1
Code:

init

 int i2c_master_port = I2C_EXAMPLE_MASTER_NUM;
    i2c_config_t conf;
    conf.mode = I2C_MODE_MASTER;
    conf.sda_io_num = I2C_EXAMPLE_MASTER_SDA_IO;
    conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
    conf.scl_io_num = I2C_EXAMPLE_MASTER_SCL_IO;
    conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
    conf.master.clk_speed = I2C_EXAMPLE_MASTER_FREQ_HZ;
    esp_err_t err = i2c_param_config(i2c_master_port, &conf);
    if (ESP_OK == err)
    {
        err = i2c_driver_install(i2c_master_port, conf.mode,
                                 I2C_EXAMPLE_MASTER_RX_BUF_DISABLE,
                                 I2C_EXAMPLE_MASTER_TX_BUF_DISABLE, 0);
        printf("i2c_driver_install 0x%x \n", err);
    }
    else
    {
        printf("i2c_param_config fail 0x%x \n", err);
    }

read data from slave

    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (I2C_SLAVE_ADDR << 1) | READ_BIT, ACK_CHECK_EN);
    if (size > 1)
    {
        i2c_master_read(cmd, data_rd, size - 1, ACK_VAL);
    }
    i2c_master_read_byte(cmd, data_rd + size - 1, NACK_VAL);
    i2c_master_stop(cmd);
    err = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS);
    i2c_cmd_link_delete(cmd);

@arsinio
Copy link

arsinio commented Apr 22, 2019 via email

@AmrutaCh
Copy link

@arsinio can you share the changes which are working for you?
It would of great help.

@AmrutaCh
Copy link

I am facing the same issue with I2C example provided in idf.
ESP32 Arduino works as expected whereas esp-idf gives the following errors

* timeout : 0x107 (generated by I2C_STATUS_TIMEOUT)

* failed: -1 (generated by I2C_STATUS_ACK_ERROR)

The slave is an Arduino device.

ESP-idf version: v3.1
Code:

init

 int i2c_master_port = I2C_EXAMPLE_MASTER_NUM;
    i2c_config_t conf;
    conf.mode = I2C_MODE_MASTER;
    conf.sda_io_num = I2C_EXAMPLE_MASTER_SDA_IO;
    conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
    conf.scl_io_num = I2C_EXAMPLE_MASTER_SCL_IO;
    conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
    conf.master.clk_speed = I2C_EXAMPLE_MASTER_FREQ_HZ;
    esp_err_t err = i2c_param_config(i2c_master_port, &conf);
    if (ESP_OK == err)
    {
        err = i2c_driver_install(i2c_master_port, conf.mode,
                                 I2C_EXAMPLE_MASTER_RX_BUF_DISABLE,
                                 I2C_EXAMPLE_MASTER_TX_BUF_DISABLE, 0);
        printf("i2c_driver_install 0x%x \n", err);
    }
    else
    {
        printf("i2c_param_config fail 0x%x \n", err);
    }

read data from slave

    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (I2C_SLAVE_ADDR << 1) | READ_BIT, ACK_CHECK_EN);
    if (size > 1)
    {
        i2c_master_read(cmd, data_rd, size - 1, ACK_VAL);
    }
    i2c_master_read_byte(cmd, data_rd + size - 1, NACK_VAL);
    i2c_master_stop(cmd);
    err = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS);
    i2c_cmd_link_delete(cmd);

More details:

On Arduino slave side, it gives TW_BUS_ERROR

@arsinio
Copy link

arsinio commented Apr 24, 2019

@AmrutaCh
You'll need to modify components/driver/i2c.c...I'm not up-to-date with the latest version so I'll just walk you through the change:

In esp_err_t i2c_param_config(i2c_port_t i2c_num, const i2c_config_t* i2c_conf) there is an if block...something like:

if (i2c_conf->mode == I2C_MODE_SLAVE) {  //slave mode
...    
} else {
...        
}

You'll need to modify the else clause changing

I2C[i2c_num]->timeout.tout = cycle * I2C_MASTER_TOUT_CNUM_DEFAULT;

To

I2C[i2c_num]->timeout.tout = 1048575;

That number was picked because, to the best of my knowledge, it's the largest supported by the hardware.

That being said there is a "newer" function that may help:
i2c_set_timeout

When first introduced I found that it did not resolve my issue, but I should really give it another try.

@AmrutaCh
Copy link

i2c_set_timeout worked

Thanks @arsinio

@saeidimajid
Copy link

Hi

I tried to read SHT20 registers with I2C tool with "i2cget" command, but it has error
"ESP_ERR_TIMEOUT Operation timeout because the bus is busy"
esp_err_t = 0x107
what does it mean?
Maybe it depends on the timout setting. (i2c_set_timeout)
I trid to set timeout in multi value but it doesn't work

@IvanAkiy
Copy link

Hi

I tried to read SHT20 registers with I2C tool with "i2cget" command, but it has error "ESP_ERR_TIMEOUT Operation timeout because the bus is busy" esp_err_t = 0x107 what does it mean? Maybe it depends on the timout setting. (i2c_set_timeout) I trid to set timeout in multi value but it doesn't work

Hi
Wondering if you solved this issue, because I'm facing the same problem with esp32-s3-pico and pn532. If yes, can you provide the solution that worked for you?

@saeidimajid
Copy link

Hi Wondering if you solved this issue, because I'm facing the same problem with esp32-s3-pico and pn532. If yes, can you provide the solution that worked for you?

I couldn't solve this problem, but with a program that I wrote myself based on the SHT20 datasheet, it worked easily. I also used a DS1307 module with the i2c tool, which worked properly as well. I was able to read and write to the registers perfectly. I think in some i2c devices, there's a need for a short response time for the device to respond and send data, which hasn't been considered in the i2c tool code.

@yallico
Copy link

yallico commented Jul 17, 2024

Also having the same issue in v5.2.2, having said that I'm using the legacy driver I think. I will git it a go with the new driver in i2c_master.c

@yallico
Copy link

yallico commented Oct 23, 2024

I defaulted to using v5.1.4, (legacy driver) hybrid approach. Port 0 on IDF and port 1 in Arduino wire function!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests