For years my approach to debugging anything talking over a wire was to stare at it, then stare at the datasheet, then add a print statement and hope. With anything digital that's not slow and forgiving, this is roughly as effective as it sounds. A sensor that worked nine times out of ten and then didn't, an I2C device that ACKed sometimes and ghosted me others. I'd been guessing for weeks. Last month I finally bought a logic analyser, and I'm cross with myself for waiting so long.
It cost me about twelve quid. One of the ubiquitous little blue boards with a Cypress chip on it that the whole hobby market quietly relabels as a Saleae clone. It is not a precision instrument. It does not need to be. For poking at a 100kHz I2C bus it is more than enough, and paired with sigrok and PulseView it turned a fortnight of guesswork into an afternoon of actually knowing.
the problem I'd been avoiding
I had a temperature and humidity sensor on an I2C bus with a couple of other devices. Most of the time it read fine. Intermittently it returned nonsense, or the bus would just lock and the whole thing wedged until I power-cycled it. I'd tried the usual incantations. Slower clock. Different library. Shorter wires. Each change seemed to help for an hour, which is exactly the sort of false signal that keeps you flailing, because intermittent faults reward whatever you happened to do last.
What I never did was look at the actual signals. I had no idea whether the problem was electrical, a timing violation, address contention, or a genuinely broken device. I was debugging blind and calling it intuition.
getting sigrok to talk to the thing
The cheap clones ship with firmware that pretends to be a Saleae Logic, which sigrok doesn't love. The fix is to flash them with the fx2lafw firmware that the sigrok project ships, after which they show up as a generic Cypress FX2 device. On my machine that was a matter of installing the package and pointing PulseView at it:
$ sudo apt install sigrok pulseview
$ sigrok-cli --scan
The following devices were found:
fx2lafw - Saleae Logic with 8 channels: D0 D1 D2 D3 D4 D5 D6 D7
Two wires onto SDA and SCL, ground to ground, and I had channels. The first capture was a small revelation purely because I could see edges. Actual rising and falling edges, with timing, on a screen. After years of inferring all this from behaviour, seeing it felt almost rude.
the protocol decoder is the whole point
Raw edges are nice but the magic is the protocol decoder. PulseView has an I2C decoder built in. You tell it which channel is SCL and which is SDA, and it overlays the actual transaction on top of the waveform: start condition, address, read or write bit, the ACK or NACK, each data byte, the stop. Suddenly I wasn't looking at squiggles. I was reading a conversation.
And the conversation told me exactly what was wrong within about ten minutes. On the good reads, the sequence was clean: start, address, write, ACK, register, ACK, repeated start, read, data, NACK, stop. Textbook. On the bad reads, the master sent the address and got a NACK. No ACK at all. The device simply wasn't answering.
That single fact killed half my theories instantly. It wasn't corruption, it wasn't a timing violation on the data, it wasn't a flaky library. The device was failing to acknowledge its own address, intermittently. That's an electrical or a device-level problem, not a software one.
I zoomed in on the address phase of a failing transaction and the smoking gun was right there. The clock and data lines weren't getting cleanly back up to the rail between bytes. The rise time was sluggish, lazy curves instead of crisp edges, and on the marginal occasions SDA hadn't recovered to a clean high before the next sample. Classic weak pull-ups. I had two devices on the bus, each with its own internal pull-ups disabled, and the single external resistor pair I'd fitted was too weak for the capacitance of the wiring I'd ended up with.
the fix was a resistor
I swapped the pull-ups from 10k down to 4.7k. The edges snapped up sharp. The NACKs vanished. I ran it overnight in a loop and it didn't drop a single read.
It is faintly embarrassing that a fortnight of frustration came down to a resistor value, the most boring fault on the I2C troubleshooting list. But that's not really the lesson. The lesson is that I'd been arguing with a black box. The moment I could see the bus, the diagnosis took minutes and was certain, where before every fix was a guess that the next failure would disprove.
The tool paid for itself on its first afternoon, and twelve quid is nothing against the evenings I'd burned. If you do anything with SPI, I2C, UART or any other digital signalling and you've been inferring behaviour from the outside, buy the cheap analyser. You don't need the expensive one. You need to stop guessing, and a tool this cheap that turns a black box into a transcript is the best money I've spent on the bench in a long time. I only wish I'd been embarrassed into it years ago.