I2C Glitches on the Logic Analyzer: A Taxonomy of Failure Modes
Pull-up too weak, clock stretch timeout, address collision — each failure leaves a distinct fingerprint on a 24 MHz capture. Here is what to look for.

Pull-up too weak, clock stretch timeout, address collision — each failure leaves a distinct fingerprint on a 24 MHz capture. Here is what to look for when I2C "works on the bench" and fails in the enclosure.
Lab note format
Equipment: Saleae Logic Pro 16, 24 MHz digital sample rate, analog on SDA/SCL when needed. Targets: TMP117 @ 0x48, BME680 @ 0x76, TCA9548A mux @ 0x70 on a wearable sensor hub (3.3 V, 400 kHz fast mode).
Taxonomy of failure modes
1. Weak pull-ups → rounded edges, partial ACK
Fingerprint: SDA/SCL rise times > 1 µs at 400 kHz; ACK bit doesn't reach Vil before SCL rising edge; decoder shows NACK sporadically.
Measure: Scope in high-Z, calculate tr from 30%–70%. Fast mode spec: tr max 300 ns typical design target < 200 ns.
Fix: Drop from 10 kΩ (EVB default) to 2.2 kΩ on short flex; 4.7 kΩ on 30 cm cable harness. Power budget cost: ~0.5 mA per line at idle — account in battery spec.
Hot tip: use oscilloscope pulse-width triggers on ACK low period when Saleae decode lies due to threshold.
2. Clock stretching timeout
Fingerprint: SCL held low by slave after byte 1; master gives up at ~25 ms (driver default) or hangs forever (bare-metal with no timeout).
Common culprits: BME680 during heater cycle; FM+ devices on mixed bus; firmware busy-wait in slave ISR.
Capture sign: stretched low time correlates with sensor conversion start register write.
Fix: i2c_master timeout in Linux/Zephyr; in bare-metal, I2C_CR2_NACK + abort sequence on STM32H7. Document max stretch per slave in BSP header.
3. Address collision / wrong 7-bit shift
Fingerprint: decode shows phantom addresses (0x24, 0x52) that are your 8-bit write addr shifted wrong.
Classic: #define ADDR 0x48 passed as 8-bit to HAL expecting 7-bit left-aligned. Works with one chip; breaks when second device shares upper bits.
Fix: one macro I2C_7BIT(0x48) used everywhere; unit test asserts (addr << 1) == 0x90.
4. Bus lock (SDA stuck low)
Fingerprint: SDA never releases high when SCL idles; often after MCU reset mid-transaction without slave reset.
Fix: clock nine pulses on SCL while monitoring SDA release; power-cycle slaves with enable FET; add TCA4307 hot-swap buffer on shared external connector.
5. Capacitive loading on long harness
Fingerprint: clean square waves at MCU pins; rounded at sensor pad; CRC errors on packetized protocols (not pure I2C but shows up on SMbus).
Fix: lower frequency to 100 kHz for bring-up; series 33 Ω at master SCL/SDA to damp ringing; compare with SPI debugging — same SI instincts, different protocol rules.
6. Multi-master contention
Rare on our boards, common on carrier + daughtercard setups. Two masters start within same setup time → arbitration loss invisible unless you capture both SCL sources.
Fingerprint: partial START, illegal STOP, decode desync.
Fix: hardware strapping for single master in field; software mailbox when two SoCs must talk to same EEPROM.
7. Level shifter dead zone
TXS0108E-style auto-direction shifters fail on I2C clock stretching. Fingerprint: works at 100 kHz, fails at 400 kHz, temperature dependent.
Fix: PCA9306 or discrete FET shifter; read AN10441 before copying SparkFun schematic.
Debug workflow
- Capture 500 ms idle + transaction — verify pull-ups with analog overlay.
- Trigger on START condition (Saleae I2C analyzer or scope serial trigger).
- Compare ACK slots — first failure byte tells you device vs. bus.
- If decode fails but eyes look fine, lower sample rate — paradoxically, 24 MHz on 100 kHz bus overshoots glitches; 10 MHz often decodes cleaner on noisy lines.
Real incident
Field returns: "temperature stuck." Logic log showed NACK on read after heater write — stretch to 12 ms, master timeout 5 ms. BME680 datasheet max 10 ms typical during measurement. Changed Zephyr i2c_stm32 timeout from 5000 µs to 25000 µs; failures dropped to zero over 6-month fleet data.
Not magic — just matching driver constants to datasheet max, which only showed up under concurrent bus traffic.
Saleae settings reference
| Setting | Value we use |
|---|---|
| Sample rate | 24 MHz digital |
| Glitch filter | Off for debug; 100 ns on noisy harness |
| Pull-up assumption | 2.2 kΩ for rise estimate |
| Display | Analog overlay on SDA when NACK unexplained |
Export .sal with annotation — attach to Jira; re-decode months later with same thresholds.
Scope vs logic analyzer
Use LA for protocol decode and long captures. Use scope when rise time and overshoot matter — weak pull-up diagnosis needs analog voltage, not digital threshold crossing. Budget: LA first; scope second if ACK looks marginal digitally.
Fleet correlation tip
When field failures are intermittent, log I2C error register snapshot (STM32 I2C_ISR BUSY, BERR, ARLO) to flash on failure. Returned units showed ARLO ( arbitration lost ) on 60% of "stuck temp" cases — mux address collision with uninitialized secondary MCU on dock connector.
What I'd do next
Build a one-page "I2C fingerprint" poster for the lab: oscilloscope screenshots per failure class. New engineers run unknown failures against the poster before swapping silicon.
Add automated capture on CI hardware-in-loop: golden Saleae trace compare for BSP releases.
Manish Bookreader
Electronics enthusiast, Embedded Systems Expert, Linux/Networking programmer, and Software Engineer passionate about AI, electronics, books, and cooking.

