kopia lustrzana https://github.com/peterhinch/micropython-samples
RP2: Bidirectional SPI release.
rodzic
c5dc32b9a2
commit
f22acb644b
30
rp2/RP2.md
30
rp2/RP2.md
|
@ -81,10 +81,19 @@ acquired (MISO):
|
|||
* `ibuf` A `bytearray` for MISO data. If the quantity of data exceeds the length
|
||||
of the buffer it will be truncated.
|
||||
|
||||
Using MISO affects the maximum achievable baudrate. This is because the incoming
|
||||
signal is delayed by two system clock periods by the input synchronisers (RP2040
|
||||
manual 3.5.6.3), plus up to one additional system clock period because the slave
|
||||
and master are mutually asynchronous. The latency becomes even worse when using
|
||||
the asynchronous slave because the slave's `sck` is further delayed relative to
|
||||
the master's by the slave's input synchronisers. In testing even 10MHz was too
|
||||
high a rate for reliable reception.
|
||||
|
||||
## 1.3 Methods
|
||||
|
||||
* `write(data : bytes)` arg a `bytes` or `bytearray` of data to transmit. Return
|
||||
is rapid with transmission running in the background. Returns `None`.
|
||||
is rapid, returns `None`. The data is queued for transmission. The oldest object
|
||||
is transmitted when the master next initiates a transfer.
|
||||
* `deinit()` Disables the DMA and the SM. Returns `None`.
|
||||
|
||||
## 1.4 CS/
|
||||
|
@ -97,12 +106,14 @@ between power-up and application start-up. A value of a few KΩ is suggested.
|
|||
## 1.5 Callback
|
||||
|
||||
This runs when the DMA is complete. It takes no args and runs in a hard IRQ
|
||||
context. Typical use is to set a `ThreadSafeFlag`, allowing a pending task to
|
||||
resume. Typically this will deassert `CS/` and initiate processing of received
|
||||
data. Note that the DMA completes before transmission ends due to bytes stored
|
||||
in the SM FIFO. This is unlikely to have practical consequences because of
|
||||
MicroPython latency: the master executes several MP instructions before the
|
||||
callback runs, and the response to a `ThreadSafeFlag` typically takes >200μs.
|
||||
context. It should deassert `CS/`. Typical use is to set a `ThreadSafeFlag`,
|
||||
allowing a pending task to resume, to initiate processing of received data.
|
||||
|
||||
Users of low baudrates (<1MHz) should note that the DMA completes before
|
||||
transmission ends due to three bytes stored in the SM FIFO. This is unlikely to
|
||||
have practical consequences because of MicroPython latency: where the callback
|
||||
deasserts `CS/` the time between the last edge of `clk` and the trailing edge
|
||||
of `CS/` was 93μs (RP2040 @125MHz).
|
||||
|
||||
# 2. Nonblocking SPI slave
|
||||
|
||||
|
@ -252,6 +263,11 @@ The slave will ignore all interface activity until CS/ is driven low. It then
|
|||
receives data with the end of message identified by a low to high transition on
|
||||
CS/.
|
||||
|
||||
The input pins are very sensitive to electrical noise: wiring to the master must
|
||||
be kept very short. This is because of the very high speed of the RP2 internal
|
||||
logic (clock rates >=125MHz). Pulses of a few ns duration can cause the state
|
||||
machine to respond, or can cause an IRQ to be raised.
|
||||
|
||||
# 3. Pulse Measurement
|
||||
|
||||
The file `measure_pulse.py` is a simple demo of using the PIO to measure a pulse
|
||||
|
|
|
@ -3,15 +3,12 @@
|
|||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2025 Peter Hinch
|
||||
|
||||
# Performs SPI output: check on scope or LA.
|
||||
# TODO:
|
||||
# Fails if baudrate >= 9MHz
|
||||
# Performs SPI I/O.
|
||||
|
||||
# Bidirectional test fails if baudrate >= 9MHz: see RP2.md for reason.
|
||||
|
||||
# Problem with pin nos?
|
||||
# 11 Sept slave works bidirectionally with tx.py, but with this code slave receives
|
||||
# nothing, but responds with correct data. Waveforms look identical. MOSI data looks correct.
|
||||
# Slave gets correct data with unidirectional setup (no ibuf)
|
||||
# 45us after last clock edge, clk emits a 250ns pulse. CS/ goes high 724us after last clock
|
||||
# I think spurious clk is screwing RX SM.
|
||||
|
||||
from machine import Pin
|
||||
import asyncio
|
||||
from .spi_master import SpiMaster
|
||||
|
@ -25,12 +22,15 @@ tsf = asyncio.ThreadSafeFlag()
|
|||
|
||||
|
||||
def callback(): # Hard ISR
|
||||
pin_cs(1) # Decrease deassert time from 724us to 93us but still fails
|
||||
pin_cs(1) # Decrease deassert time from 724us to 93us
|
||||
tsf.set() # Flag user code that transfer is complete
|
||||
|
||||
|
||||
buf = bytearray(100)
|
||||
# Bidirectional test:
|
||||
spi = SpiMaster(6, 1_000_000, pin_sck, pin_mosi, callback, miso=pin_miso, ibuf=buf)
|
||||
# For unidirectional test issue:
|
||||
# spi = SpiMaster(6, 1_000_000, pin_sck, pin_mosi, callback))
|
||||
|
||||
|
||||
async def send(data):
|
||||
|
@ -42,7 +42,7 @@ async def send(data):
|
|||
|
||||
|
||||
async def main():
|
||||
src_data = bytearray(b"\xFF\x55\xAA\x00the quick brown fox jumps over the lazy dog")
|
||||
src_data = bytearray(b"\x00 The quick brown fox jumps over the lazy dog")
|
||||
n = 0
|
||||
while True:
|
||||
await send(src_data)
|
||||
|
|
|
@ -16,7 +16,7 @@ alloc_emergency_exception_buf(100)
|
|||
# 2 CS\
|
||||
|
||||
|
||||
@rp2.asm_pio(autopull=True)
|
||||
@rp2.asm_pio(autopush=True, autopull=True)
|
||||
def spi_in():
|
||||
label("escape") # Just started, transfer ended or overrun attempt.
|
||||
out(y, 32) # Get maximum byte count (blocking wait)
|
||||
|
@ -37,14 +37,13 @@ def spi_in():
|
|||
jmp("overrun")
|
||||
label("continue")
|
||||
jmp(x_dec, "bit") # Post decrement
|
||||
push()
|
||||
# push()
|
||||
wrap() # Next byte
|
||||
label("done") # ISR has sent data
|
||||
out(x, 32) # Discard it
|
||||
in_(y, 30) # Return amount of unfilled buffer truncated to 30 bits
|
||||
push()
|
||||
# TODO Is this valid given that push_thresh==8?
|
||||
# Truncation ensures that overrun returns a short int
|
||||
# push()
|
||||
jmp("escape")
|
||||
|
||||
|
||||
|
@ -95,7 +94,7 @@ class SpiSlave:
|
|||
sm_num,
|
||||
spi_in,
|
||||
in_shiftdir=rp2.PIO.SHIFT_LEFT,
|
||||
# push_thresh=8,
|
||||
push_thresh=8,
|
||||
in_base=mosi,
|
||||
jmp_pin=sck,
|
||||
)
|
||||
|
@ -187,7 +186,7 @@ class SpiSlave:
|
|||
return # ISR runs on trailing edge but SM is not running. Nothing to do.
|
||||
# See above comment re memfails on next line
|
||||
sp = self._sm.get() >> 3 # Bits->bytes: space left in buffer or 7ffffff on overflow
|
||||
self._nbytes = self._buflen - sp if sp != 0x7FFFFFF else self._buflen
|
||||
self._nbytes = self._buflen - sp if sp != 0x07FF_FFFF else self._buflen
|
||||
self._dma.active(0)
|
||||
self._sm.active(0)
|
||||
self._tsf.set()
|
||||
|
|
Ładowanie…
Reference in New Issue