Page 1 of 1

Solved: I2C with ESP32, SDA dead silent

Posted: Mon Nov 20, 2023 12:13 am
by jasubot
Hi,

I can't get my ESP32-WROOM-32 to send any data over SDA with the I2C libraries.
I'm using GPIO 21 for SDA, and GPIO 22 for SCL.

First, I wrote the functionality with the Arduino library, using just the pinMode(), digitalWrite(), etc.
That worked perfectly fine, and I could easily communicate with the slave device.
So, the pins SDA (21) and SCL (22) both work.

Then, I tried implementing that with the Arduino supplied library Wire.
The code was, in a nutshell, more or less this:

Code: Select all

#include <Wire.h>

Wire.begin();
Wire.beginTransmission(0x43);
Wire.write(0x0A);
Wire.endTransmission();
Checking it with the scope, we can see SDA (blue) is just dead - except for that stop condition.
But the SCL (yellow) seems alright.

Not so visible in the image, but in the end of transmission SDA falls LOW before SCL raises HIGH.
Even that they seem to overlap, when zoomed out to this scale.

photo1700436772.jpeg
photo1700436772.jpeg (212.49 KiB) Viewed 4965 times

Now, I tried to implement it with the espidf framework (assuming that would help).
But I'm getting the exact same signal as output as with the Arduino Wire library.

platformio.ini

Code: Select all

[env:esp32dev]
platform = espressif32 # Version 6.4.0
board = esp32dev # ESP32 Dev Kit C V4, from AZdelivery
framework = espidf # Version 3.50101.230828
The code, in a nutshell:

Code: Select all

#include <stdint.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/i2c.h"

#define PIN_SDA 21
#define PIN_SCL 22

void main() {
  i2c_config_t conf = {
    .mode = I2C_MODE_MASTER,
    .sda_io_num = PIN_SDA,
    .scl_io_num = PIN_SCL,
    .sda_pullup_en = GPIO_PULLUP_ENABLE,
    .scl_pullup_en = GPIO_PULLUP_ENABLE,
    .master = { .clk_speed = 10000 }, // 10k, and I've tried also 100k
  };

  esp_err_t err1 = i2c_param_config(I2C_NUM_0, &conf);
  esp_err_t err2 = i2c_driver_install(I2C_NUM_0, I2C_MODE_MASTER, 0, 0, 0);
  // No errors, both err1 and err2 were OK

  i2c_cmd_handle_t cmd = i2c_cmd_link_create();
  esp_err_t err1 = i2c_master_start(cmd);
  esp_err_t err2 = i2c_master_write_byte(cmd, 0x55, false); // 0x55, or any uint8_t
  esp_err_t err3 = i2c_master_stop(cmd);
  esp_err_t err4 = i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000 / portTICK_PERIOD_MS);
  i2c_cmd_link_delete(cmd);

  // err1, err2, err3 were all OK
  // TIMEOUT with err4
   // I tried adding various delays between the calls above, but no help
}
I'm quite new to ESP32 and IoT development, and pretty much running out of ideas.
It seems to me the issue is in essence that the SDA is not able to write the data out.
Or that, instead, it would just always write 0xFF out.

I would really appreciate help, if someone could point me to the right direction here. :)
If there was something more I could do to debug it further...?

Re: I2C with ESP32, SDA dead silent

Posted: Mon Nov 20, 2023 6:20 am
by ESP_Sprite
That is odd, I2C is tested and tried as it's in a lot of projects. Are you sure you're measuring the correct pins?

Re: I2C with ESP32, SDA dead silent

Posted: Mon Nov 20, 2023 5:32 pm
by MicroController
I think I have seen this specific I2C waveform before.
Specifically, after there was a problem on the bus the I2C controller seemed to be confused and from then on only sent, IIRC, a couple of SCL's and a STOP, probably attempting the 'clear bus' operation again and again.

Re: I2C with ESP32, SDA dead silent

Posted: Wed Nov 22, 2023 12:00 am
by jasubot
ESP_Sprite wrote:
Mon Nov 20, 2023 6:20 am
That is odd, I2C is tested and tried as it's in a lot of projects. Are you sure you're measuring the correct pins?

If it wasn't the correct pins, I'm not sure what could explain for that stop condition (with SDA). Also, there's nothing else running on the ESP, except to this I2C code that I isolated to a new program. But this being one of those 4 a.m. projects, there's always the chance! :)

MicroController wrote: I think I have seen this specific I2C waveform before.
Specifically, after there was a problem on the bus the I2C controller seemed to be confused and from then on only sent, IIRC, a couple of SCL's and a STOP, probably attempting the 'clear bus' operation again and again.

I think you're right on it! Found a datasheet based on which the waveform matches the I2C reset for a hung bus. Not sure though, why the transmission would just end up to that state.

Also, a while after those signals seen in the image, both the SDL and SCL fall low and raise high, once. I can't remember in which order, but with this new information it seems something relevant that I'll need to investigate.

I've tried running the code on 3 different ESP32s now. Even that they're likely from the same batch, I'm quite sure the issue is not with the hardware - but more likely with their user.

I'm not sure if the roots of the issue could be in my circuit, as electronics is not among my strongest assets. I have a 4.7k pull-up for both SDA and SCL. Then, they're grounded to the ESP with 220 ohm resistors. The probes of the scope I've got then around that 220 ohm resistor. Could it be the probes that mess up the I2C controller?

The circuit:

+3.3V -- [4.7k] -- [SDA] -- [ProbeIn] -- [0.2k] -- [ProbeOut] -- [ GND ]
+3.3V -- [4.7k] -- [SCL] -- [ProbeIn] -- [0.2k] -- [ProbeOut] -- [ GND ]

I guess I'll be reading the I2C datasheet next weekend, as the signals do seem to make some sense after all. Not just sure yet how to continue with the debugging, but at least I have something to work on again!

Re: I2C with ESP32, SDA dead silent

Posted: Mon Nov 27, 2023 12:35 am
by jasubot
Problem solved!

The waveform was an I2C reset, which signals a hung bus.
This happens when the bus is actively driven low.

Now, I had grounded the bus with only 200 ohm, which drove it low.
Increasing the resistance to 4.7k, it all started working as expected.

As the I2C spec says, it should use open-drain/open-collector.
Which I understand is similar to the bus being able to "float".
And with that added resistance, it should now be more or less the case.

Big thanks to MicroController, for pointing me to the right direction! 8-)
Just needed that lesson on I2C, and looking beyond only the SDA output.