SPI sniffer feature

Is there a SPI sniffer feature yet?
Can I increase the terminal baudrate to capture more traffic? Or even sniff to flash?

1 Like

Not yet, but I think I can make something with the PIO that would sniff up to 62.5 (or maybe half that).

I have an application where I have 4MHz SPI clock, so that should be more than sufficient

1 Like

It’s on my list. I love the PIO and am getting better at it. I’ll try to make something demo-able tomorrow.

Very cool, thanks. Would be very useful for debugging for me.

It’s starting to work. There’s some weirdness about the startup state of the CS pin when the sniffer engages. I’m looking into that.

So, there’s always a catch with the PIO and there’s a decision to be made.

PIO input pins are consecutive. The clock has to come after the data pins.

  • DATA0
  • DATA1
  • CS

It can’t match the order of the hardware SPI pins, so I added it to the top four IO pins.

There’s two way to get both data lines. First is two separate PIO programs handling one data pin each. The other is a single program that grabs both data pins and we sort other the every-other-bit data in software. I’m leaning towards the second because we can stream to RAM with a single DMA setup, instead of two.

Better. I’m going to push this as a kind of preview, but don’t expect much yet.

Somewhere someone mentioned we could probably get around clock/6 for speed. 125/6=~20MHz. It works reliably for me at 15.6MHz, but at 30MHz it starts loosing bits. That’s probably as fast as we get without overclocking the pico to 200mhz.

1 Like

Gee, that was fast. Excellent service, thanks. I will be back in the lab on Monday, do you think I could have a build for testing by then?
So how can I keep up with the data coming in? Can I crank up UART speed? Or is there a way to write to flash?

This is just a tiny proof of concept because it sounded like a fun project.

There’s currently no way determine CS change from the data coming from the PIO, that’s going to take some thought.

UART speed has no effect on USB CDC generally speaking.

Logging to flash is easy, but what format should it be? If binary, is it a 8bits+8bits+csbits long format? If in clear text, can we keep up while doing the ASCII conversions?

For now I’m going to try to get full duplex going and maybe see if there’s an easy way to track cs changes

1 Like


There’s a new build with full duplex sniffing. It’s using two PIO programs, one for each data pin. You can see from the (0) before the 1 2 that now it’s needed to determine which byte pairs go together. Perhaps the single program with intermingled bits is a better approach.

; This program is a simple SPI sniffer that captures the data on the SPI bus
; inspired by https://github.com/raspberrypi/pico-examples/issues/104
; data must be first pin, clock n pins after

    mov isr, null       ; bad data, empty ISR
    jmp is_cs_low       ; check if CS is low
public entry_point:
    wait 0 pin 2        ; wait for clock to go low
    wait 1 pin 2        ; wait for clock to go high
    in pins, 1          ; sample data WE CAN CHANGE THIS TO 2 TO INTERLEAVE BITS
    jmp pin, no_data    ; if CS is high, ignore data

The PIO program is really slick. It always samples bits, but if CS is high we just flush the buffer on every cycle. Changing in pins, 1 to in pins, 2 would allow a single program to handle both data pins, but the bits will be interleaved.

At the moment I don’t see any obvious way to flag that the CS pin changed. If the bits are interleaved we can use a 16bit shift register size to get both bytes. maybe add an extra bit to signal the first byte in a new frame. But we probably need to mark first and last byte, which is going to eat into our max speed.

Anyone have thoughts on this? It’s an interesting problem. I’ll ponder it over and pick it back up in a few days.

1 Like

Very nice, thanks. I will report my results.