I2C times out when queueing multiple transaction

xryl669
Posts: 6
Joined: Tue Oct 09, 2018 4:31 pm

I2C times out when queueing multiple transaction

Postby xryl669 » Fri Aug 26, 2022 4:20 pm

Hi,

I'm trying to create a single object that's storing the transactions to happen on I2C bus by queueing all the operations and expecting the CPU to run them all correctly. Typically, I'm doing this (pseudo code):

Code: Select all

#define FilterError(x) ((x) == ESP_OK)

uint8 buffer[I2C_LINK_RECOMMENDED_SIZE(4)]; // Because 2 read transaction as documented
i2c_cmd_handle_t cmd = i2c_cmd_link_create_static(buffer, I2C_LINK_RECOMMENDED_SIZE(4));
uint8 devAddr = 0x76;  // For BMP210
uint8 regAddr[] = { 0xFA, 0xF7 };
uint8 dataBuffer[6] = {};
size_t numTrans = 2;

for (size_t index = 0; index < numTrans; i++) {
    if (!FilterError(i2c_master_start(cmd))) return false;
    if (!FilterError(i2c_master_write_byte(cmd, (uint8)((devAddr << 1) | I2C_MASTER_WRITE), true))) return false;
    // Set the register we are writing to
    if (!FilterError(i2c_master_write(cmd, (uint8*)&regAddr[index], 1, true))) return false;
    // Repeated start
    if (!FilterError(i2c_master_start(cmd))) return false;
    if (!FilterError(i2c_master_write_byte(cmd, (uint8)((devAddr << 1) | I2C_MASTER_READ), true))) return false;
    if (!FilterError(i2c_master_read(cmd, &dataBuffer[i * 3], 3, I2C_MASTER_LAST_NACK))) return false;
    // Tried with and without the following line (repeated start or not), but it doesn't work
    if (!FilterError(i2c_master_stop(cmd))) return false;
 }

// Later
if (!FilterError(i2c_master_cmd_begin(port, cmd, 1000 / portTICK_PERIOD_MS))) return false;
This code works perfectly for one transaction (numTrans = 1) and I can queue 2x 1 transaction and it's working. However, if I set numTrans = 2 (meaning that I'm appending 2 reads (and 4 writes) in the command list) then it fails with an I2C timeout error.

When it fails, it fails directly from the first time I'm running the transaction (first call of i2c_master_cmd_begin). When its working (one transaction case), I can run the transaction as many time as I want, and it's working as expected.

Any idea what I'm doing wrong, or is it an issue with current code in esp-idf ?

username
Posts: 538
Joined: Thu May 03, 2018 1:18 pm

Re: I2C times out when queueing multiple transaction

Postby username » Sun Aug 28, 2022 4:24 am

Since this is (pseudo code) I am assuming you are setting i=0; before the for loop starts.

I believe the problem is not enough buffer
uint8 dataBuffer[6] = {};

if (!FilterError(i2c_master_read(cmd, &dataBuffer[i * 3], 3, I2C_MASTER_LAST_NACK))) return false;

In your for loop
for (size_t index = 0; index < numTrans; i++)

When it completes this line and moves into the for loop, i will be 1.
Next time around index will be 1 and i will be 2. thus making &dataBuffer[2 * 3]. But you only set aside enough of a buffer of 6.
uint8 dataBuffer[6] = {};

So your telling it to store the next 3 bytes starting at loc 6, you dont have enough buffer.

xryl669
Posts: 6
Joined: Tue Oct 09, 2018 4:31 pm

Re: I2C times out when queueing multiple transaction

Postby xryl669 » Sat Sep 10, 2022 7:05 am

Sorry, I missed your answer. You're right, the

Code: Select all

&dataBuffer[i * 3]
should read

Code: Select all

&dataBuffer[index * 3]
. index will never be 2, so it's safe.

In fact I've made many progress on diagnosing the issue, see here. In short, the I2C HW crashes when queueing more than 2 transactions. Either we need to stop transaction and append a "end" command in between (but it can't be done from the esp-idf API), or wait until Espressif rewrite the I2C driver to be optimal.

I haven't finished the issue diagnosis yet.

Who is online

Users browsing this forum: Gaston1980 and 231 guests