Created
October 27, 2022 00:21
-
-
Save azechi/aac55d88538a3427e71d78b08a8c291d to your computer and use it in GitHub Desktop.
MicroPython, Raspberry Pi Pico PIO, DMA, 74HC595, 8 LED Chaser
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from uctypes import BF_POS, BF_LEN, BFUINT32, addressof, struct | |
# control register structure | |
DMA_CTRL_LAYOUT = { | |
"AHB_ERROR": 31<<BF_POS | 1<<BF_LEN | BFUINT32, | |
"READ_ERROR": 30<<BF_POS | 1<<BF_LEN | BFUINT32, | |
"WRITE_ERROR": 29<<BF_POS | 1<<BF_LEN | BFUINT32, | |
"BUSY": 24<<BF_POS | 1<<BF_LEN | BFUINT32, | |
"SNIFF_EN": 23<<BF_POS | 1<<BF_LEN | BFUINT32, | |
"BSWAP": 22<<BF_POS | 1<<BF_LEN | BFUINT32, | |
"IRQ_QUIET": 21<<BF_POS | 1<<BF_LEN | BFUINT32, | |
"TREQ_SEL": 15<<BF_POS | 6<<BF_LEN | BFUINT32, | |
"CHAIN_TO": 11<<BF_POS | 4<<BF_LEN | BFUINT32, | |
"RING_SEL": 10<<BF_POS | 1<<BF_LEN | BFUINT32, | |
"RING_SIZE": 6<<BF_POS | 4<<BF_LEN | BFUINT32, | |
"INCR_WRITE": 5<<BF_POS | 1<<BF_LEN | BFUINT32, | |
"INCR_READ": 4<<BF_POS | 1<<BF_LEN | BFUINT32, | |
"DATA_SIZE": 2<<BF_POS | 2<<BF_LEN | BFUINT32, | |
"HIGH_PRIORITY": 1<<BF_POS | 1<<BF_LEN | BFUINT32, | |
"EN": 0<<BF_POS | 1<<BF_LEN | BFUINT32 | |
} | |
DMA_BASE = const(0x5000_0000) | |
# alias CSRs offset address | |
DMA_CSR_LENGTH = const(0x040) | |
DMA_0_READ_ADDR = const(0x000) | |
DMA_0_WRITE_ADDR = const(0x004) | |
DMA_0_TRANS_COUNT = const(0x008) | |
DMA_0_CTRL_TRIG = const(0x00c) | |
DMA_1_CTRL = const(0x010) | |
DMA_1_TRANS_COUNT_TRIG = const(0x01c) | |
DMA_3_READ_ADD_TRIG = const(0x03c) | |
# ... ch 0..11 (CH11_ALIAS_3_READ_ADD_TRIG = 0x2fc) | |
DMA_CHAN_ABORT = const(0x444) | |
# DMA_BASE + (DMA_DGB_LENGTH * ch) + DMA_DBG_(CTDREQ | TCR) | |
DMA_DBG_LENGTH = const(0x040) | |
DMA_DBG_CTDREQ = const(0x800) | |
DMA_DBG_TCR = const(0x804) | |
DREQ_PIO0_TX0 = const(0) | |
DREQ_PIO0_TX1 = const(1) | |
@micropython.viper | |
def print_dma(channel: uint): | |
csr_addr = uint(DMA_BASE) + (DMA_CSR_LENGTH * channel) + DMA_0_READ_ADDR | |
dbg_addr = uint(DMA_BASE) + (DMA_DBG_LENGTH * channel) + DMA_DBG_CTDREQ | |
csr = ptr32(csr_addr) | |
dbg = ptr32(dbg_addr) | |
ctrl = csr[3] | |
print(f'''\ | |
DMA {channel=} CSRs 0x{csr_addr:04x} DBG 0x{dbg_addr:04x} | |
Read=0x{csr[0]:04x} Write=0x{csr[1]:04x} | |
Trans={uint(csr[2])}({uint(dbg[1])}) | |
ERROR={ctrl>>29 & 0b111:03b} BUSY={ctrl>>24 & 1} EN={ctrl&0b1} | |
DREQ count={dbg[0] & 0b11_1111} | |
''') | |
@micropython.viper | |
def clear_dreq(channel: uint): | |
dbg = ptr32(uint(DMA_BASE) + (DMA_DBG_LENGTH * channel) + DMA_DBG_CTDREQ) | |
dbg[0] = 0b11_1111 | |
@micropython.viper | |
def abort(channel: uint): | |
p = ptr32(DMA_BASE + DMA_CHAN_ABORT) | |
p[0] = (1 << channel) | |
while True: | |
if p[0] == 0: | |
return | |
@micropython.viper | |
def pause(channel: uint): | |
p = ptr32(uint(DMA_BASE) + (DMA_CSR_LENGTH * channel) + DMA_1_CTRL) | |
p[0] &= uint(0xFFFF_FFFE) | |
@micropython.viper | |
def unpause(channel:uint): | |
p = ptr32(uint(DMA_BASE) + (DMA_CSR_LENGTH * channel) + DMA_1_CTRL) | |
p[0] |= 1 | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from rp2 import PIO, asm_pio, StateMachine | |
from time import sleep_ms, sleep, sleep_us | |
from machine import Pin, mem32 | |
from sys import byteorder | |
from uctypes import addressof, struct | |
import pio | |
import dma | |
@micropython.viper | |
def data(): | |
data = bytes(10 * 4) | |
p = ptr32(data) | |
p[8] = uint(0xFFFF_FFFF) | |
p[9] = uint(0xAAAA_AAAA) | |
for i in range(8): | |
p[i] = ((1 << i) << 24) | |
return data | |
@micropython.viper | |
def data2(): | |
data = bytes(10 * 4) | |
p = ptr32(data) | |
p[8] = uint(0xFFFF_FFFF) | |
p[9] = uint(0xAAAA_AAAA) | |
for i in range(8): | |
p[i] = ((1 << (7 - i)) << 24) | |
return data | |
@asm_pio( | |
set_init=(PIO.OUT_LOW, PIO.OUT_LOW) | |
) | |
def timer(): | |
# Cycles: 1 + 1 + 6 + 32 * (30 + 1) = 1000 | |
irq(4) | |
set(pins, 0b11) | |
set(x, 31) [5] | |
label("delay_high") | |
nop() [29] | |
jmp(x_dec, "delay_high") | |
# Cycles: 1 + 7 + 32 * (30 + 1) = 1000 | |
set(pins, 0) | |
set(x, 31) [6] | |
label("delay_low") | |
nop() [29] | |
jmp(x_dec, "delay_low") | |
@asm_pio( | |
sideset_init=PIO.OUT_LOW, | |
out_init=PIO.OUT_LOW, | |
#fifo_join=PIO.JOIN_TX, | |
pull_thresh=8 | |
) | |
def tx(): | |
wait(1, irq, 4) | |
pull() | |
# CLK pulse width > 5 cycle | |
# SER setup > 6 cycle | |
out(pins, 1).side(0) [5] | |
label("loop") | |
nop().side(1) | |
out(pins, 1) [3] | |
jmp(not_osre, "loop").side(0) [4] | |
nop().side(1) [4] | |
led = Pin(25, Pin.OUT, value=0) | |
storage_clock = Pin(26, Pin.OUT, value=0) | |
serial_clock = Pin(15) | |
serial_input = Pin(14) | |
dma_ch_data = 9 | |
dma_ch_config = 10 | |
# clear dma channel state | |
dma.pause(dma_ch_data) | |
dma.abort(dma_ch_data) | |
dma.pause(dma_ch_config) | |
dma.abort(dma_ch_config) | |
timer = StateMachine(0, timer, freq=8000, set_base=led) | |
tx = StateMachine(1, tx, sideset_base=serial_clock, out_base=serial_input) | |
config = bytearray(4) | |
f = True | |
data = data() | |
data2 = data2() | |
def turn(): | |
global config, f | |
config[:] = addressof(data if f else data2).to_bytes(4, byteorder) | |
f = not f | |
turn() | |
addr_dma_ch_data = dma.DMA_BASE + (dma.DMA_CSR_LENGTH * dma_ch_data) | |
addr_dma_ch_config = dma.DMA_BASE + (dma.DMA_CSR_LENGTH * dma_ch_config) | |
mem32[addr_dma_ch_config + dma.DMA_0_READ_ADDR] = addressof(config) | |
mem32[addr_dma_ch_config + dma.DMA_0_WRITE_ADDR] = addr_dma_ch_data + dma.DMA_3_READ_ADD_TRIG | |
mem32[addr_dma_ch_config + dma.DMA_0_TRANS_COUNT] = 1 | |
ctrl = struct(addr_dma_ch_config + dma.DMA_1_CTRL, dma.DMA_CTRL_LAYOUT) | |
ctrl.TREQ_SEL = 0x3f # permanent request | |
ctrl.CHAIN_TO = dma_ch_data | |
ctrl.INCR_WRITE = 0 | |
ctrl.INCR_READ = 0 | |
ctrl.DATA_SIZE = 0x2 # SIZE_WORD: 4 bytes | |
ctrl.EN = 1 | |
mem32[addr_dma_ch_data + dma.DMA_0_READ_ADDR] = addressof(data) | |
mem32[addr_dma_ch_data + dma.DMA_0_WRITE_ADDR] = pio.PIO0_BASE + (pio.PIO_TXF0 + 4) | |
mem32[addr_dma_ch_data + dma.DMA_0_TRANS_COUNT] = 8 | |
ctrl = struct(addr_dma_ch_data + dma.DMA_0_CTRL_TRIG, dma.DMA_CTRL_LAYOUT) | |
ctrl.TREQ_SEL = dma.DREQ_PIO0_TX1 | |
ctrl.CHAIN_TO = dma_ch_config | |
ctrl.INCR_WRITE = 0 | |
ctrl.INCR_READ = 1 | |
ctrl.DATA_SIZE = 0x2 # SIZE_WORD: 4 bytes | |
ctrl.EN = 1 | |
tx.active(1) | |
timer.active(1) | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
PIO0_BASE = const(0x5020_0000) | |
PIO1_BASE = const(0x5030_0000) | |
PIO_CTRL = const(0x000) | |
PIO_FSTAT = const(0x004) | |
PIO_FDEBUG = const(0x008) | |
PIO_FLEVEL = const(0x00c) | |
# tx fifo0 ... tx fifo3 | |
PIO_TXF0 = const(0x010) | |
# rx fifo0 ... rx firl3 | |
PIO_RXF0 = const(0x020) | |
PIO_IRQ = const(0x030) | |
PIO_IRQ_FORCE = const(0x034) | |
# sm0 ... sm3 | |
PIO_SM_CTRL_LENGTH = const(0x018) | |
PIO_SM0_CLKDIV = const(0x0c8) | |
PIO_SM0_EXECTRL = const(0x0cc) | |
PIO_SM0_SHIFTCTRL = const(0x0d0) | |
PIO_SM0_ADDR = const(0x0d4) | |
PIO_SM0_INSTR = const(0x0d8) | |
PIO_SM0_PINCTRL = const(0x0dc) | |
@micropython.viper | |
def print_sm(stateMachineNumber: int): | |
pio = 0 if stateMachineNumber < 4 else 1 | |
base = uint(PIO0_BASE if pio == 0 else PIO1_BASE) | |
sm = uint(stateMachineNumber % 4) | |
p = ptr32(base + PIO_CTRL) | |
irq = ptr32(base + PIO_IRQ) | |
smctrl = ptr32(base + (PIO_SM_CTRL_LENGTH * sm) + PIO_SM0_CLKDIV) | |
instr = smctrl[4] & 0xFFFF | |
print(f'''\ | |
IRQ {(irq[0] >> 4) & 0xf:04b} {irq[0] & 0xf:04b} | |
PIO{pio}_SM{sm} enable={(p[0] >> sm) & 1} \ | |
stalled={smctrl[1] >> 31} | |
WRAP TOP={smctrl[1] >> 12 & 0b1_1111} \ | |
BOTTOM={smctrl[1] >> 7 & 0b1_1111} \ | |
CURRENT={smctrl[3] & 0b1_1111} | |
INSTR=0x{instr:04x} {instr >> 13:03b} {instr>>8&0b1_1111:05b} {instr & 0xFF:08b} | |
TX LEVEL={(p[3] >> (sm * 8)) & 1} \ | |
EMPTY={(p[1] >> 24 + sm) & 1} \ | |
FULL={(p[1] >> 16 + sm) & 1} \ | |
STALL={(p[2] >> 24 + sm) & 1} \ | |
OVER={(p[2] >> 16 + sm) & 1} | |
RX LEVEL={(p[3] >> (sm * 8) + 4) & 1} \ | |
EMPTY={(p[1] >> 8 + sm) & 1} \ | |
FULL={(p[1] >> sm) & 1} \ | |
UNDER={(p[2] >> 8 + sm) & 1} \ | |
STALL={(p[2] >> sm) & 1}\ | |
''') | |
@micropython.viper | |
def pio_sm(stateMachineNumber: int): | |
pio = 0 if stateMachineNumber < 4 else 1 | |
sm = uint(stateMachineNumber % 4) | |
return pio, sm | |
@micropython.viper | |
def restart(stateMachineNumber: int): | |
pio = 0 if stateMachineNumber < 4 else 1 | |
base = uint(PIO0_BASE if pio == 0 else PIO1_BASE) | |
sm = uint(stateMachineNumber % 4) | |
ctrl = ptr32(base + PIO_CTRL) | |
ctrl[0] = 1 << (4 + sm) | |
@micropython.viper | |
def pause(stateMachineNumber: int): | |
pio = 0 if stateMachineNumber < 4 else 1 | |
base = uint(PIO0_BASE if pio == 0 else PIO1_BASE) | |
sm = uint(stateMachineNumber % 4) | |
ctrl = ptr32(base + PIO_CTRL) | |
ctrl[0] &= (1 << sm) ^ 0b1111 | |
@micropython.viper | |
def unpause(stateMachineNumber: int): | |
pio = 0 if stateMachineNumber < 4 else 1 | |
base = uint(PIO0_BASE if pio == 0 else PIO1_BASE) | |
sm = uint(stateMachineNumber % 4) | |
ctrl = ptr32(base + PIO_CTRL) | |
ctrl[0] |= 1 << sm | |
@micropython.viper | |
def clear_irq(pio: int, irq: int): | |
base = uint(PIO0_BASE if pio == 0 else PIO1_BASE) | |
p = ptr32(base + PIO_IRQ) | |
p[0] = 1 << irq | |
@micropython.viper | |
def force_irq(pio: int, irq:int): | |
base = uint(PIO0_BASE if pio == 0 else PIO1_BASE) | |
p = ptr32(base + PIO_IRQ_FORCE) | |
p[0] = 1 << irq | |
@micropython.viper | |
def clear_fifos(stateMachineNumber: int): | |
pio = 0 if stateMachineNumber < 4 else 1 | |
base = uint(PIO0_BASE if pio == 0 else PIO1_BASE) | |
sm = uint(stateMachineNumber % 4) | |
shiftctrl = ptr32(base + (PIO_SM_CTRL_LENGTH * sm) + PIO_SM0_SHIFTCTRL) | |
shiftctrl[0] ^= uint(1 << 31) | |
shiftctrl[0] ^= uint(1 << 31) |
Author
azechi
commented
Oct 27, 2022
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment