Debugging I²C
Inter-Integrated Circuit (I²C) uses two wires. No device on the bus can drive a line to the high level. Each device can only pull a line to the low level, or release it. The high level occurs when all devices release the line and a resistor pulls it up.
Almost every I²C failure in this lesson is a result of that one rule. Learn the rule first. The failures are then related, and not a list of separate problems.
Contents
- The electrical model
- Failure 1: no pull-up resistors, or incorrect values
- Failure 2: two devices with the same address
- Failure 3: a device holds the clock
- Failure 4: the probes are on the wrong pins
- The correct debug sequence
The electrical model
Both lines are open drain. The lines are SDA (serial data) and SCL (serial clock). Each device pin is a switch to ground. When the switch closes, the line goes low. When the switch opens, the device no longer drives the line. The pull-up resistor then sets the level.
Three results of this model occur in all the sections below:
- A low level always wins. One device that holds a line low prevents all other devices from setting the line high. This is intentional. It is how acknowledgement and arbitration operate.
- Without a pull-up resistor, there is no high level. The line floats. A floating line is not a high level. It has no defined level, and noise can change it.
- One device can stop the full bus. If one device holds SDA low and does not release it, all other communication on that bus stops.
The third result explains why I²C failures have large effects. One incorrect sensor stops the full bus. The symptom then occurs in software that has no relation to that sensor.
Failure 1: no pull-up resistors, or incorrect values
The failure: you connect SDA and SCL directly between the microcontroller unit (MCU) and the sensor. Nothing operates. A bus scan finds no devices.
The cause: without a pull-up resistor there is no defined high level. The bus does not receive a valid start condition.
This failure is a property of the wiring, so a rule can find it before you run the simulation. The LabWired electrical rule check examines each net. It finds the I²C nets from the device pins that have an SDA or SCL function. It then makes sure that each net has a path to a positive supply. If there is no path, the check reports I2C_NO_PULLUP and gives the name of the net.
Two conditions cause errors in opposite directions:
Many breakout boards have pull-up resistors. The Adafruit SHT31-D and MPU-6050 boards have 10 kΩ resistors to Vin. If you add more resistors, the resistors operate in parallel and the total resistance decreases. Two 10 kΩ resistors in parallel give 5 kΩ. Four boards with 10 kΩ each give 2.5 kΩ. Each device must then sink more current than its data sheet permits.
Use these rules:
- use one pull-up path for each line on the bus;
- examine the breakout board to find if it has pull-up resistors; and
- if more than one board has pull-up resistors, cut the solder jumpers on all boards except one.
A high resistance and a low resistance cause different symptoms. A high resistance (for example 47 kΩ on a long bus) increases the rise time of the line. The bus operates at 100 kHz and fails at 400 kHz, because the line does not get to the high level before the sample time. A low resistance (for example 1 kΩ) prevents the devices from pulling the line fully low. If the bus fails only at high speed, examine the rise time. If the bus never operates, examine the levels.
Failure 2: two devices with the same address
The failure: two sensors operate correctly one at a time. Together they give incorrect data, or one sensor does not reply.
The cause: an I²C address has 7 bits. The manufacturer sets the address, and many devices have the same default address. If two devices have the same address, both devices acknowledge and both devices drive the data line. The master reads the bitwise AND of the two replies. The bus reports no error. The data looks correct but is wrong.
Use these solutions in this sequence:
- The address-select pin. Most sensors have one or two address pins. Connect each pin to the high or low level to select between 2 or 4 addresses. An ADXL345 uses address 0x53 or 0x1D as a function of one pin.
- A second bus. Many MCUs have more than one I²C peripheral. Two buses remove the conflict and need no additional components.
- A multiplexer. A TCA9548A gives eight isolated buses behind one address. Use a multiplexer when you must connect eight identical sensors.
LabWired prevents this failure during design. The topology model does not permit two devices to use the same address on the same bus. A multiplexer is the correct way to connect identical devices.
Failure 3: a device holds the clock
A slave device that is not ready can hold SCL low. The master releases the clock to start the next cycle, but the line stays low because the slave holds it. The master must wait. This function is clock stretching. It is a permitted part of the protocol.
Clock stretching causes two different failures.
The master does not obey the stretch. Software I²C implementations frequently set the clock pin on a timer. They do not examine the line after they release it. This method operates correctly with a device that does not stretch the clock. With a device that stretches the clock, the master continues to send clock pulses and reads incorrect data. Many electrically erasable programmable read-only memory (EEPROM) devices stretch the clock during a write cycle. Many sensors stretch the clock during a measurement. The symptom is that the same software and the same wiring operate with one sensor and fail with a different sensor.
The slave stretches the clock longer than expected. The bus stops for that time, and all other devices on the bus stop. The slowest device then sets the response time of your control loop.
LabWired models this behavior. The ESP32-C3 I²C controller uses a bit-level engine. If the transmit buffer becomes empty during a write, the controller holds SCL low and waits. The logic analyzer shows a clock that stops in the middle of a byte.
Use the line levels to identify the condition. Clock stretching gives SCL low, SDA inactive, and no data movement. A device that holds the bus gives SDA low continuously. The two conditions use different lines and need different corrections.
Failure 4: the probes are on the wrong pins
The failure: the capture is empty, or the decoded data is incorrect. The bus operates correctly.
The cause: a protocol decoder needs both lines of the same bus. SDA alone cannot be decoded, because the clock defines when each data bit is valid. If you connect one probe to the SDA line of one bus and one probe to the SCL line of a different bus, the decoder gives bytes. Those bytes are incorrect, which is worse than no data.
The same condition applies to different chips. A decoder reads one bus on one chip. If the probes are on two different MCUs, there is no single bus to decode. The LabWired analyzer finds this condition and reports it. It does not decode the data.
If a decode gives no data, examine these conditions before you examine the firmware:
- are both probes on the same bus?
- are both probes on the same chip? and
- does the peripheral use the pins that you probed?
The last condition is important on chips that have a general-purpose input/output (GPIO) matrix. On the ESP32 family, almost any pin can carry almost any signal. The I²C pins are a firmware setting, and not a property of the package.
The correct debug sequence
Use this sequence. It finds the most frequent failures first.
- Examine the wiring and the power supply. Make sure that the device has power, that the ground connects to the MCU ground, and that SDA and SCL connect to the correct pins. Incorrect pins cause more I²C failures than protocol errors.
- Examine the line levels. With no data on the bus, both lines must be high. If one line is low, stop. There is a missing pull-up resistor, or a device holds the line. Do not continue until both lines are high.
- Scan the bus. If the scan finds no devices, there is a wiring or pull-up failure. If the scan finds an unexpected address, the address-select pin is in the wrong position. If the scan finds fewer devices than you installed, refer to Failure 2.
- Decrease the clock frequency to 100 kHz. If the failure stops, the cause is the rise time. The pull-up resistance is too high, or the bus capacitance is too high for the frequency. This test needs ten seconds and separates electrical failures from protocol failures.
- Examine the protocol. Incorrect register addresses, incorrect byte sequence, and a missing repeated start condition are real failures. They are the last items to examine, and not the first.
Steps 1 to 4 are electrical. Most I²C debugging is electrical debugging.
Try it yourself
The lab below operates in the browser. It needs no board and no toolchain, and it starts automatically.
The lab runs a BME280 driver on an STM32F103. The firmware reads the factory calibration data from the sensor over I²C. It then calculates the compensated temperature, humidity, and pressure. The bus uses two pins: SDA on PB7 and SCL on PB6.
The lab includes a logic analyzer. Channel CH0 connects to SCL and channel CH1 connects to SDA. Both probes are on the same bus and on the same chip, as Failure 4 requires.
To read the captured data, click Open in LabWired, then double-click the logic analyzer on the canvas. The analyzer shows each transaction: the address 0x76, the read/write bit, and the data bytes. It shows the SCL and SDA waveforms above the table.
Then change the decoder from I²C to Raw. The analyzer does not show a waveform. It shows this message:
Raw pin capture can’t see I2C1 traffic — these pins are driven by the peripheral (alternate function), not GPIO.
This message is Failure 4 from the instrument. Raw mode reads the GPIO pad. While the I²C peripheral controls the pins, the pad is not the source of the signal. A raw capture would show a constant level, and you could make the incorrect conclusion that the bus does not operate. The analyzer reports that it cannot see the data instead.
Do you have an I²C failure to report — a bus that one sensor stopped, or an address conflict that took a week to find? Tell us on r/labwired. We add the best examples to this lesson.