Ramblings of an aging IT geek
← Ramblings of an aging IT geek
hardware

a cheap logic analyser and the moment the bus made sense

After weeks of guessing at why an I2C sensor wouldn't talk, an eight-channel logic analyser showed me the actual bytes on the wire in about ten minutes.

A soldering iron and a part-built circuit board

For weeks I had been debugging an I2C sensor the way you debug something you can't see: by changing one thing, reflashing, and squinting at whether the number that came back looked less wrong than before. The sensor would mostly work, then return zeros, then work again. My code was full of retries and delays I'd added on faith, none of which I could justify, all of which I was afraid to remove.

Then I bought a logic analyser. Not a nice one. One of the small clones of the Saleae Logic, eight channels, about a tenner, the kind you clip onto headers with little grabber leads. It speaks over USB to sigrok and PulseView on the laptop, and that combination turned out to be the single best money I have spent on this hobby.

seeing the wire instead of imagining it

The first capture was a revelation. I clipped onto SDA and SCL, set the trigger, ran one read, and there it was: the actual clock, the actual data, the start condition, the address byte, the ACK, the lot. PulseView even has an I2C decoder, so it doesn't just draw the squiggles, it annotates them. Start, Write 0x76, ACK, and so on, in plain text above the trace.

A close-up of a circuit board with the analyser leads clipped on

And immediately the problem was obvious in a way no amount of printf debugging had managed. My zeros weren't a sensor fault. They were a NAK. The device was not acknowledging its own address on those reads, which meant it wasn't ready, which meant my startup delay after power-on was too short for the cold device but fine once it had warmed up. The intermittency wasn't random at all. It was thermal, and the analyser handed me that conclusion on a plate.

the things I'd been getting wrong

A few sins surfaced once I could actually watch the bus.

  • My pull-up resistors were too weak. The rising edges on SCL were lazy, sloping curves rather than crisp steps, and at the clock speed I'd chosen the line wasn't reaching a clean logic high in time. Swapping 10k for 4.7k pull-ups sharpened them up nicely.
  • I was clocking faster than the cheap jumper wires liked. Dropping from 400kHz to 100kHz removed a whole class of marginal reads I'd been papering over with retries.
  • One of my "delays added on faith" was doing nothing useful and one was genuinely load-bearing. Without being able to see the bus, I had no way to tell which. Now I did, so I could delete the dead one and keep the real one with a comment explaining why.

The retries came out. The unexplained delays came out. The code got shorter and, for the first time, I understood every line that remained.

get one before you need one

The wider point is about feedback loops. I had spent weeks in a loop where my only signal was "did the right number come back," which is an almost uselessly low-bandwidth way to debug a serial protocol. The analyser changed the signal to "here is exactly what travelled down the wire, byte for byte, with timing." That is a different kind of debugging entirely. You stop guessing and start reading.

If you do anything with I2C, SPI, UART or even just poking at unknown signals, get a cheap analyser before you think you need one. It costs less than the parts you'll otherwise destroy out of frustration, and the first time you watch a transaction decode itself in front of you, the whole field of embedded work feels a little less like sorcery and a little more like engineering.