micropython-samples/rp2/spi/spi_master.py

47 wiersze
1.6 KiB
Python

# spi_mater.py A nonblocking SPI master for RP2040/RP2350
# Inspired by
# https://github.com/raspberrypi/pico-micropython-examples/blob/master/pio/pio_spi.py
# Released under the MIT License (MIT). See LICENSE.
# Copyright (c) 2025 Peter Hinch
import rp2
@rp2.asm_pio(autopull=True, pull_thresh=8, sideset_init=rp2.PIO.OUT_LOW, out_init=rp2.PIO.OUT_LOW)
def spi_out():
wrap_target()
set(x, 7).side(0x0)
label("bitloop")
out(pins, 1).side(0x0) # Stalls with CLK low while FIFO is empty
jmp(x_dec, "bitloop").side(0x1)
wrap()
# Get data request channel for a SM: RP2040 datasheet 2.5.3 RP2350 12.6.4.1
def dreq(sm, rx=False):
d = (sm & 3) + ((sm >> 2) << 3)
return 4 + d if rx else d
# The callback runs when DMA is complete. This may be up to four byte times prior to
# the SM running out of data (FIFO depth).
class SpiMaster:
def __init__(self, sm_num, freq, sck, mosi, callback):
self._sm_num = sm_num
self._dma = rp2.DMA()
self._dma.irq(handler=callback, hard=True) # Assign callback
dc = dreq(sm_num) # Data request channel
# Transfer bytes, don't increment the write address, irq at end, and pace the transfer.
self._ctrl = self._dma.pack_ctrl(size=0, inc_write=False, irq_quiet=False, treq_sel=dc)
f = 2 * freq # 2 clock cycles per bit
self._sm = rp2.StateMachine(sm_num, spi_out, freq=f, sideset_base=sck, out_base=mosi)
self._sm.active(1)
def deinit(self):
self._dma.active(0)
self._sm.active(0)
def write(self, data):
self._dma.config(read=data, write=self._sm, count=len(data), ctrl=self._ctrl, trigger=True)