I2C SCL frequency 10% less than it should be at 400kHz

Hans Dorn
Posts: 62
Joined: Tue Feb 21, 2017 2:21 am

Re: I2C SCL frequency 10% less than it should be at 400kHz

Postby Hans Dorn » Wed Apr 05, 2017 1:04 am

I'll try to update my arduino installation over the weekend.
Guess I'm already up to date w.r.t the I2C part right now though.

My changes didn't make the error rate any worse or better, I'm back at the fast version.

There might be some EMI issues with my setup. The wiring is rather messy and spans 2 breadboards.
I can trigger I2C errors by switching on my headphone amp :mrgreen:

I've ordered an I2C buffer chip, that should arrive later this week.
I'll integrate it into my setup and clean up the I2C wires.
The buffer might even help with the clock stretching issues. (knocks on wood)

I've got the long transfers working now I guess, but I'd rather let the new version run for a while before posting the changes.

Cheers

Hans Dorn
Posts: 62
Joined: Tue Feb 21, 2017 2:21 am

Re: I2C SCL frequency 10% less than it should be at 400kHz

Postby Hans Dorn » Thu Apr 06, 2017 10:29 pm

Things are slowly starting to improve in the I2C department.

While trying to figure out how to make long (>32 bytes) transfers work, I found there's a nicer way to send long frames.
I2_CMD_WRITE will actually take a byte_num paramater larger than 32 in FIFO mode.
All you have to do is keep the FIFO filled asynchronously until the transmission is done.
This is a bit simpler than segmented transfers, and faster too.

While trying to get i2c_send with sendStop=0 to work I found one of the problems that kept the original code from working.
The condition for "transmission done" must exactly match the condition you used to decide if to send STOP or END.
CMD_STOP : Wait for the CMD done bit
CMD_END: Wait until bus not busy

To get rid of the random lockups that occasionally happened I replaced 2 unbounded while loops with 1ms delays,
going by the theory that waiting any longer probably won't make the I2C bus work again. :mrgreen:
This is looking good so far, I've seen no more lockups.
I'm rebooting my ESP via software when I2C errors pop up. This hasn't worked reliably before, but now it seems to do.
Sometimes more than 1 reboot happens before the I2C goes error free again.

After making this last change, I haven't seen any unprovoked I2C errors anymore!
These used to happen every 2-3 hours. It's a bit early to say if they're really gone, but things are looking good so far.

I don't know how this last change would relate to random I2C errors, but I'll take the improvement anyway.

New Version of i2cWrite:

Code: Select all

i2c_err_t i2cWrite(i2c_t * i2c, uint16_t address, bool addr_10bit, uint8_t * data, uint8_t len, bool sendStop)
{
    int i;
    uint8_t index = 0;
    uint8_t dataLen = len + (addr_10bit?2:1);
    address = (address << 1);

    if(i2c == NULL){
        return I2C_ERROR_DEV;
    }

//    I2C_MUTEX_LOCK();

    i2cResetFiFo(i2c);
    i2cResetCmd(i2c);
    //Clear Interrupts
    i2c->dev->int_clr.val = 0xFFFFFFFF;

    //CMD START
    i2cSetCmd(i2c, 0, I2C_CMD_RSTART, 0, false, false, false);

    //CMD WRITE(ADDRESS + DATA)
    i2cSetCmd(i2c, 1, I2C_CMD_WRITE, dataLen, false, false, true);

    i2c->dev->fifo_data.data = address & 0xFF;
    dataLen--;
    if(addr_10bit) {
        i2c->dev->fifo_data.data = (address >> 8) & 0xFF;
        dataLen--;
    }

    //CMD STOP or CMD END
    if(!sendStop) {
        i2cSetCmd(i2c, 2, I2C_CMD_END, 0, false, false, false);
    } else {
        i2cSetCmd(i2c, 2, I2C_CMD_STOP, 0, false, false, false);
    }


    //START Transmission
    i2c->dev->ctr.trans_start = 1;

    //WAIT Transmission
    uint32_t startAt = millis();
    while(1) {
        
        // Keep FIFO stocked
        if ( (i2c->dev->status_reg.tx_fifo_cnt < 30) && (dataLen) ){
            i2c->dev->fifo_data.val = data[index++];
            dataLen--;
        }
        

        //have been looping for too long
        if((millis() - startAt)>50){
            //log_e("Timeout! Addr: %x", address >> 1);
//            I2C_MUTEX_UNLOCK();
            return I2C_ERROR_BUS;
        }

        //Bus failed (maybe check for this while waiting?
        if(i2c->dev->int_raw.arbitration_lost) {
            //log_e("Bus Fail! Addr: %x", address >> 1);
//          I2C_MUTEX_UNLOCK();
            return I2C_ERROR_BUS;
        }

        //Bus timeout
        if(i2c->dev->int_raw.time_out) {
            //log_e("Bus Timeout! Addr: %x", address >> 1);
//          I2C_MUTEX_UNLOCK();
            return I2C_ERROR_TIMEOUT;
        }

        //Transmission did not finish and ACK_ERR is set
        if(i2c->dev->int_raw.ack_err) {
            //log_w("Ack Error! Addr: %x", address >> 1);
//             while(i2c->dev->status_reg.bus_busy);
            delayMicroseconds(1000);
//          I2C_MUTEX_UNLOCK();
            return I2C_ERROR_ACK;
        }

        if((sendStop && i2c->dev->command[2].done) || (!sendStop && !i2c->dev->status_reg.bus_busy)){
            break;
        }
    }

//    I2C_MUTEX_UNLOCK();
    return I2C_ERROR_OK;
}
New version of i2cInitFix: (this contained another unbounded while loop)

Code: Select all

void i2cInitFix(i2c_t * i2c){
    if(i2c == NULL){
        return;
    }
    I2C_MUTEX_LOCK();
    i2cResetFiFo(i2c);
    i2cResetCmd(i2c);
    i2c->dev->int_clr.val = 0xFFFFFFFF;
    i2cSetCmd(i2c, 0, I2C_CMD_RSTART, 0, false, false, false);
    i2c->dev->fifo_data.data = 0;
    i2cSetCmd(i2c, 1, I2C_CMD_WRITE, 1, false, false, false);
    i2cSetCmd(i2c, 2, I2C_CMD_STOP, 0, false, false, false);
    i2c->dev->ctr.trans_start = 1;
//     while(!i2c->dev->command[2].done);
    delayMicroseconds(1000);
    I2C_MUTEX_UNLOCK();
}

Cheers

P.S:
I commented out the I2C_MUTEX in i2cWrite because it's really slow
You might or might not want to do this :mrgreen:

meowsqueak
Posts: 151
Joined: Thu Jun 15, 2017 4:54 am
Location: New Zealand

Re: I2C SCL frequency 10% less than it should be at 400kHz

Postby meowsqueak » Mon Jan 15, 2018 2:54 am

Interesting read. What's the status of this investigation in terms of ESP-IDF as of January 2018? Is there still a latent issue in the master branch of ESP-IDF? I ask because I've been having a lot of trouble with glitchy I2C for the last week, and although moving to the master branch (from 2.1.1) seemed to fix an issue with the master locking up - requiring a system reset - I'm still getting glitches on my HD44780 (via PCF8574A I2C I/O expander) LCD1602 display once every few minutes, even at very slow clock rates (20kHz). It's a 4-bit interface so I have a feeling it's dropping a nibble somewhere and getting the I/O expander out-of-sync with byte alignment.

I do have a long cable (4m) cable to my I2C device, which is why I'm using a very low clock rate. This is definitely contributing to the problem, since a short (10cm) cable makes it much more reliable, however with the longer cable the I2C operations are working, it's just the odd one that gets a glitch. Oddly, if I run at 100 kHz I don't see an increase in the incidence of the issue - the clock is more noticeably rounded due to extra capacitance on the longer cable, but it still rises to reach the correct I2C voltage at ~50% duty cycle. The incidence of the glitch happens about as often at 100 kHz as it does at 10 kHz.

EDIT: for my 4m cable I'm using CAT5 twisted pair, with a common ground paired with each signal wire. Reinitialising the display (as in going through the 4-bit initialisation sequence again) resolves the glitch and allows the display to continue functioning.

ESP_Angus
Posts: 2344
Joined: Sun May 08, 2016 4:11 am

Re: I2C SCL frequency 10% less than it should be at 400kHz

Postby ESP_Angus » Mon Jan 15, 2018 9:12 pm

meowsqueak wrote:I ask because I've been having a lot of trouble with glitchy I2C for the last week, and although moving to the master branch (from 2.1.1) seemed to fix an issue with the master locking up
There were some issues with recovering from I2C master bus timeouts that were fixed in v3.0-rc1 and current master. This sounds like what you were encountering here.
meowsqueak wrote: I'm still getting glitches on my HD44780 (via PCF8574A I2C I/O expander) LCD1602 display once every few minutes,
*snip*
a short (10cm) cable makes it much more reliable,
*snip*
Reinitialising the display (as in going through the 4-bit initialisation sequence again) resolves the glitch and allows the display to continue functioning.
This seem to be adequate explained by noise on the cable causing the occasional glitched I2C signal at the I/O expander end. There isn't anything that can be done about this at the I2C master driver level, unfortunately.

As it happens I posted some ideas about long I2C cable runs just now:
https://esp32.com/viewtopic.php?f=2&t=4203#p18966

You mention you have some twisted pair grounds to try and take out common-mode noise, but you may want to try some of the other things mentioned there as well.

Low pass filtering the I2C cable may also help, avoid noise-induced phantom clocks at the device end.

meowsqueak
Posts: 151
Joined: Thu Jun 15, 2017 4:54 am
Location: New Zealand

Re: I2C SCL frequency 10% less than it should be at 400kHz

Postby meowsqueak » Tue Jan 16, 2018 7:36 am

You're probably right. I'm doing some testing with very short cables to see if I can correctly correlate cable length to glitch incidence. EDIT: yes, cable length does affect it. A very short cable shows no errors over a 12 hour test.

BTW, when I enable WiFi with master ESP-IDF, I'm sometimes getting this I2C crash: https://github.com/espressif/esp-idf/issues/1503. I'm intending to roll back to 3.0rc1 soon to see if it happens there too.

dalbert
Posts: 5
Joined: Wed Nov 16, 2016 3:45 am

Re: I2C SCL frequency 10% less than it should be at 400kHz

Postby dalbert » Sun Apr 24, 2022 11:17 pm

I'm experiencing the same issue with an ESP32-WROOM-32 using the latest Arduino ESP32 core.
SDK:v4.4-dev-3569-g6a7d83af19-dirty
IDF:v4.4-dev-3569-g6a7d83af19-dirty

The ESP32 is the I2C master (IO21, IO22), communicating with an STM32G0 co-processor slave.
At standard speeds (100kbps), it works reasonably well, but at fast mode (400kbps), communications
become unreliable. I'm using 2K pull-ups on SCL and SDA and the waveform looks reasonable.
However there are at least two issues:

1) SCL is clocked significantly slower than the configured setting; for example, configuring for 450kbps results in SCL being clocked around 384kHz. (the focus of this thread)

2) Perhaps more importantly, the ESP32 appears not to be asserting SDA quickly enough following the clock after an ACK from the slave. This glitching of SDA happens after each ACK at 400kHz.
Attachments
ESP32_I2C_glitch_after_ACK.jpg
ESP32_I2C_glitch_after_ACK.jpg (198.34 KiB) Viewed 4732 times

Who is online

Users browsing this forum: No registered users and 60 guests