High speed SPI sweep

I’m trying to use the CW1200 in SPI listen mode by connecting it to an SPI channel. After detecting the trigger address/data, I perform a clock_xor glitch attack. However, the CW1200 fails to read the SPI data and ends up crashing—the LCD goes blank. The target device is also being clocked from the 50 MHz HS2 output.

APIs used :

  • cw.scope() — connect to CW1200
  • scope.clock.clkgen_freq + scope.io.hs2 = “clkgen” — start HS2 clock
  • SPI(scope._getNAEUSB(), cs_line=…) — SPI engine object
  • spi.enable(speed) — enable SPI hardware
  • spi.transfer(bytes) — read/write SPI
  • FPGA(scope._getNAEUSB()).INITBState() — check FPGA config state

However, INITB is low.
My question is, is it even possible to use the dedicated DI, CS, SCK pins to read SPI data ? at 17 - 20MHz.

Are you trying to use CW1200 to passively sniff SPI activity between another SPI master/slave?

That’s not what the SPI class is meant for: it’s meant to actively drive a SPI interface.

If I’ve misunderstood, can you share more precisely what you are doing, i.e. the actual Python code which leads to the crash.

That’s correct—that’s exactly what I’m trying to do. – sneak attack.

#!/usr/bin/env python3

“”"

spi_read_001.py

Very simple CW1200 SPI reader:

- Start HS2 clock

- Enable SPI

- Repeatedly issue 0x9F and read 3 bytes

- Log to logs/SPI.log (overwrite each run)

“”"

import os

import sys

import time

from datetime import datetime

CW_SRC = “/home/sen/WS_CW1200/chipwhisperer/software”

if os.path.isdir(CW_SRC) and CW_SRC not in sys.path:

sys.path.insert(0, CW_SRC)

import chipwhisperer as cw

from chipwhisperer.hardware.naeusb.fpga import FPGA

from chipwhisperer.hardware.naeusb.spi import SPI

LOG_PATH = “logs/SPI.log”

CLOCK_HZ = 50_000_000

SPI_HZ = 1_000_000

CMD = [0x9F]

READ_LEN = 3

def hexdump(buf):

return " ".join(f"{b:02X}" for b in buf)

def pick_cs(scope):

for name in ("tio1", "pdid", "tio2", "tio3", "tio4", "io1"):

    if hasattr(scope.io, name):

        return name

return None

def main():

os.makedirs(os.path.dirname(LOG_PATH), exist_ok=True)

with open(LOG_PATH, "w", encoding="utf-8") as log:

    log.write("timestamp,rx\\n")

    log.flush()



    scope = cw.scope()

    scope.clock.clkgen_freq = CLOCK_HZ

    time.sleep(0.2)

    try:

        scope.io.hs2 = "clkgen"

    except Exception:

        pass



    cs_attr = pick_cs(scope)

    cs_line = (scope.io, cs_attr) if cs_attr else None

    fpga = FPGA(scope.\_getNAEUSB())

    print(f"\[i\] FPGA programmed: {fpga.isFPGAProgrammed()}")

    print(f"\[i\] FPGA INITB: {fpga.INITBState()}")

    if not fpga.INITBState():

        print("\[!\] INITB low — FPGA not configured. SPI cannot start.")

        return



    spi = SPI(scope.\_getNAEUSB(), cs_line=cs_line, nrst_default="high")

    spi.enable(SPI_HZ)



    try:

        while True:

            tx = CMD + \[0x00\] \* READ_LEN

            rx = spi.transfer(tx)

            data = rx\[len(CMD):\] if rx else \[\]

            ts = datetime.now().strftime("%H:%M:%S.%f")\[:-3\]

            line = f"{ts},{hexdump(data)}"

            print(line)

            log.write(line + "\\n")

            log.flush()

            time.sleep(0.01)

    except KeyboardInterrupt:

        pass

    finally:

        try:

            spi.disable()

        except Exception:

            pass

        try:

            scope.dis()

        except Exception:

            pass

if _name_ == “_main_”:

main()

but theoretically, if the CW is the SPI slave, it should always sweep the bus.

yes, I am referring to that example, that is also the only available example.

I don’t think this will work as you intend it to. CW1200 is expecting to be a SPI master; it will not work as a SPI slave or passive observer. Did you find an example of using CW1200 to do what you are trying to do? If so, can you point me to where you found this.