I2C debugging with a ₹650 logic analyser: the 5 bugs I find every month
Cheap tools, the rise time formula nobody uses, and the bus that stays stuck low
Contents
Every month somebody at work or on WhatsApp says "the sensor is not detecting". Nine times out of ten it is one of these five. Before you change the library or the sensor, look at the bus.
The tool
The cheap 24 MHz 8 channel "Saleae compatible" clone, ₹650 online. With sigrok PulseView (free) it works very well:
sudo apt install pulseview sigrok-firmware-fx2lafw
Sample at least 4× the bus speed, I use 8 MHz for 400 kHz I2C. Add the I2C protocol decoder, set SCL and SDA channels, and it shows you every address, ACK, NACK and byte.
One warning: a logic analyser only sees 0 or 1 against a threshold. It will show "clean" signals when the real waveform is ugly. For rise time problems you need a scope. More below.
Bug 1: 8-bit vs 7-bit address
Datasheet says the DS3231 or MPU6050 is at "0xD0". Arduino Wire wants the 7-bit address, 0x68. If you write Wire.beginTransmission(0xD0), the library shifts it left, the top bit falls off, and on the bus you send address 0x50. The decoder shows "Address write: 50", NACK. On a bad day there is some other device at 0x50 (an EEPROM, for example) and it answers, and now you are writing to the wrong chip.
Rule: if the datasheet address is above 0x7F, it is the 8-bit form. Shift right by one.
Bug 2: pull-ups (too weak, or too strong)
I2C lines are open drain, the pull-up resistor and the bus capacitance decide the rise time. Formula from the TI app note:
t_rise = 0.8473 × R_pullup × C_bus
Fast mode (400 kHz) allows max 300 ns rise time. With 10k pull-ups and 200 pF (long wires, many modules):
0.8473 × 10,000 × 200e-12 = 1.69 µs → 5x too slow
With 2.2k: ~373 ns, still a bit slow at 200 pF, fine with shorter wires. The other direction: every breakout module comes with its own 10k or 4.7k pull-ups. Six modules with 4.7k each in parallel is ~780 Ω. Minimum allowed at 3.3V is about (3.3 − 0.4) / 3 mA ≈ 970 Ω. Too strong, the devices can't pull the line low enough, random NACKs. Remove some pull-ups (most modules have solder jumpers or you cut a trace).
Bug 3: bus stuck low after reset
The MCU resets in the middle of a read. The slave is still sending a byte and holding SDA low, waiting for clocks that never come. Now every transaction fails until you power cycle the sensor. The fix is in the I2C spec itself: clock SCL up to 9 times until the slave releases SDA, then send a STOP.
void i2c_bus_recover(void) {
gpio_set_input(SDA); /* release SDA */
gpio_set_output_open_drain(SCL);
for (int i = 0; i < 9 && !gpio_read(SDA); i++) {
gpio_write(SCL, 0); delay_us(5);
gpio_write(SCL, 1); delay_us(5);
}
/* STOP: SDA goes low to high while SCL is high */
gpio_set_output_open_drain(SDA);
gpio_write(SDA, 0); delay_us(5);
gpio_write(SCL, 1); delay_us(5);
gpio_write(SDA, 1); delay_us(5);
}
Call it at boot, before you init the I2C peripheral. Names are generic, map them to your HAL.
Bug 4: clock stretching on Raspberry Pi
Some sensors (the BNO055 is the famous one) hold SCL low to say "wait". The Pi's I2C hardware has a long known problem with clock stretching, at least up to the Pi 4. Symptoms: garbage bytes, random errors. Options: lower the bus speed with dtparam=i2c_arm_baudrate=10000 in config.txt, or use the software I2C overlay on other pins:
dtoverlay=i2c-gpio,bus=3,i2c_gpio_delay_us=2,i2c_gpio_sda=23,i2c_gpio_scl=24
Bug 5: long wires
I2C was designed for inside one board. Someone runs 2 metres of ribbon cable from the controller to a sensor in the pump panel, next to the motor cables. Capacitance kills the rise time, and the motor puts noise on everything. If you really must go off-board: a differential I2C buffer like PCA9615, or better, don't use I2C over a cable. Put a small MCU near the sensor and talk RS-485.
Next time "sensor not detecting", don't touch the code. Look at the bus first.
Written by
Karthikeyan S
Embedded engineer, Coimbatore. STM32, ESP32, motor controllers for pumps (Kovai is pump city da). C, RTOS, oscilloscope, filter coffee. எம்பெடட் தான் உண்மையான கோடிங் 😄
Get the best of #raspberry_pi_lab weekly
One email each Monday with the most useful posts. No spam; unsubscribe in one click.
Comments
Sign in to join the conversation.
Sign in to comment