Testing the PIO for SPI on RP2350 - I think: such a PIO SPI cannot be faster as 25MHz (even lower with external slave devices and "round trip delay").
My suspicion: this limitation is related to a huge delay on GPIO input signals. It seems to limit also the maximum SPI speed on "native" (regular) SPI interfaces.
Technically: 75MHz (as SYSCLK/2) could be possible - but I have never achieved this speed with a synchronous, full-duplex interface (such as SPI).
The reason: the delay on inputs into the internal logic (where the synchronous SPI SCLK is generated and used internally also for sampling MISO) is too large (see also the E9 errata with issues on input pins). An input seems to be delayed by >30ns (before it reaches the internal logic, independent of pull-up or pull-down enabled).
Here is a simple PIO SPI test program to force this issue:
My suspicion: this limitation is related to a huge delay on GPIO input signals. It seems to limit also the maximum SPI speed on "native" (regular) SPI interfaces.
Technically: 75MHz (as SYSCLK/2) could be possible - but I have never achieved this speed with a synchronous, full-duplex interface (such as SPI).
The reason: the delay on inputs into the internal logic (where the synchronous SPI SCLK is generated and used internally also for sampling MISO) is too large (see also the E9 errata with issues on input pins). An input seems to be delayed by >30ns (before it reaches the internal logic, independent of pull-up or pull-down enabled).
Here is a simple PIO SPI test program to force this issue:
Code:
import rp2from machine import Pin#PIO SPI - maximum is 25 MHz!@rp2.asm_pio(out_shiftdir=1, in_shiftdir=1, autopull=True, pull_thresh=8, autopush=True, push_thresh=8, sideset_init=(rp2.PIO.OUT_LOW), out_init=rp2.PIO.OUT_LOW)def spi_cpha0(): global DELAY wrap_target() out(pins, 1) [4].side(0)#change all the [4] into [3] - it starts FAILING! in_(pins, 1) [0].side(1) out(pins, 1) [4].side(0)#change all the [4] into [2] - it FAILS completely! in_(pins, 1) [0].side(1) out(pins, 1) [4].side(0) in_(pins, 1) [0].side(1) out(pins, 1) [4].side(0) in_(pins, 1) [0].side(1) out(pins, 1) [4].side(0) in_(pins, 1) [0].side(1) out(pins, 1) [4].side(0) in_(pins, 1) [0].side(1) out(pins, 1) [4].side(0) in_(pins, 1) [0].side(1) out(pins, 1) [4].side(0) in_(pins, 1) [0].side(1) wrap()class PIOSPI: def __init__(self, sm_id, pin_mosi, pin_miso, pin_sclk, cpha=False, cpol=False, freq=1000000): assert(not(cpol or cpha)) #MISO input must be configured as input! MISO = Pin(pin_miso, Pin.IN) #no pull-resistors enabled! Enabling a pull-up = no speed difference self._sm = rp2.StateMachine(sm_id, spi_cpha0, freq=1*freq, sideset_base=Pin(pin_sclk), out_base=Pin(pin_mosi), in_base=Pin(pin_miso)) self._sm.active(1) def write_read_blocking(self, wdata): rdata = [] nCS.value(0) for b in wdata: #dependent on shift_dir: LSB or MSB first #--shift_dir=0 = MSB #self._sm.put(b << 24) #rdata.append(self._sm.get() & 0xff) #--shift_dir=1 = LSB self._sm.put(b) rdata.append((self._sm.get() >> 24) & 0xff) nCS.value(1) return rdata print("PIO SPI")machine.freq(150000000)print(machine.freq())nCS = Pin(13, Pin.OUT, value=1)# ID MOSI MISO SCLK#max. PIO clock is 125MHz - why not 150? 125 MHz is the old RP2040 SYSCLK speed!spi = PIOSPI(0, 11, 12, 10, freq=125000000) #while True:#athe max. working SCLK is below 25 MHz: faster generates bit errors on MISOnCS.value(0)wdata = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]rdata = spi.write_read_blocking(wdata)nCS.value(1)print(rdata)
Statistics: Posted by tjaekel — Wed Oct 09, 2024 5:18 am