For about a fortnight I'd been losing to a BME280 sensor that mostly worked. It read temperature and humidity perfectly for an hour, then returned all zeroes until I power-cycled the board. The kind of bug that makes you doubt the wiring, the library, the chip, and eventually yourself. I'd been debugging it the only way I knew, which is to say by printing things over serial and squinting, and getting nowhere.
So I gave up on cleverness and bought the tool I should have bought years ago: a cheap eight-channel logic analyser, one of the little blue ones that present themselves as a Saleae clone and cost less than a takeaway. About a tenner. I half expected it to be junk.
It is not junk. With sigrok and PulseView driving it, I clipped two probes onto SDA and SCL, set the sample rate to 1 MHz, and triggered on the falling edge of SDA. For the first time in this whole saga I could actually see the bus rather than imagine it.
The protocol decoder is the part that earns the money. PulseView doesn't just draw you wiggly lines, it overlays the decoded I2C on top: start condition, the 7-bit address, the read/write bit, ACK or NACK, the data bytes, stop. You watch the conversation happen in plain hex.
And there it was. When the sensor was healthy, every transaction ended in a clean ACK. When it went sour, the address byte came back with a NACK and the master just gave up. The chip wasn't responding at all. Which meant it wasn't a software bug or a register I'd misconfigured, it was the device falling off the bus.
The cause turned out to be embarrassingly physical. I had the sensor on the end of about 30cm of dupont jumper wire, with no pull-ups beyond the weak internal ones, and a slightly marginal 3V3 rail that sagged whenever the wifi radio transmitted. The capacitance of that run plus the soft rail meant the rising edge on SDA was too slow, and every so often a bit got sampled in the grey zone and the whole transaction corrupted. You can see it on the capture: the edges that fail are visibly lazier than the ones that work.
[I2C] Start
[I2C] Address write: 76
[I2C] NACK <- here
[I2C] Stop
The fix was boring. A pair of proper 4k7 pull-ups to a stable 3V3, and a much shorter wire. Zero failures since.
What I actually learned isn't about I2C. It's that I spent a fortnight guessing at something a five-minute capture would have told me on day one. A logic analyser is to a microcontroller what a debugger is to a program, and I'd been doing the equivalent of debugging with print statements through a letterbox. The next time a bus goes quiet, I'm reaching for the probes first.