Skip to content

Instantly share code, notes, and snippets.

@azechi
Last active January 15, 2023 00:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save azechi/b1a89ead90b9147adc64e4baf0b60c0c to your computer and use it in GitHub Desktop.
Save azechi/b1a89ead90b9147adc64e4baf0b60c0c to your computer and use it in GitHub Desktop.
Raspberry Pi Pico MicroPython Logic Analyser
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] &= uint(0xFFFF_FFC0)
@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
pin_count = const(2)
pin_in_base = 3
sample_count = 20000
freq = 3_000 # -1=125_000_000
pin_trigger = 3
from rp2 import *
from machine import Pin, mem32
from sys import byteorder
from uctypes import addressof, struct
from math import ceil
import pio
import dma
@micropython.viper
def dma_wait_for_finish(ch: uint):
csr_addr = uint(dma.DMA_BASE) + (uint(dma.DMA_CSR_LENGTH) * ch) + uint(dma.DMA_0_READ_ADDR)
csr = ptr32(csr_addr)
while uint(csr[2]):
pass
DREQ_PIO0_RX0 = 4
dma_ch = const(0)
pio_ch = const(0)
bits_packed_per_word = 32 - (32 % pin_count)
sample_per_word = 32 // pin_count
word_count = ceil(sample_count / sample_per_word)
print(f'{pin_count=}\n{bits_packed_per_word=}\n{sample_per_word=}')
print(f'{sample_count=}\n{word_count=}\nbuffer_size={word_count * 4}')
@asm_pio(
autopush=True,
fifo_join=PIO.JOIN_RX
)
def capture():
in_(pins, pin_count)
sm = StateMachine(
pio_ch,
capture,
freq=freq,
in_base=Pin(pin_in_base),
in_shiftdir=PIO.SHIFT_RIGHT,
push_thresh=bits_packed_per_word
)
buffer = bytearray(word_count * 4)
dma.pause(dma_ch)
dma.abort(dma_ch)
dma_addr = dma.DMA_BASE + (dma.DMA_CSR_LENGTH * dma_ch)
mem32[dma_addr + dma.DMA_0_READ_ADDR] = pio.PIO0_BASE + (pio.PIO_RXF0)
mem32[dma_addr + dma.DMA_0_WRITE_ADDR] = addressof(buffer)
mem32[dma_addr + dma.DMA_0_TRANS_COUNT] = word_count
ctrl = struct(dma_addr + dma.DMA_0_CTRL_TRIG, dma.DMA_CTRL_LAYOUT)
ctrl.TREQ_SEL = DREQ_PIO0_RX0
ctrl.INCR_WRITE = 1
ctrl.INCR_READ = 0
ctrl.DATA_SIZE = 0x2 # SIZE_WORD: 4 bytes
ctrl.EN = 1
sm.exec(f"wait(1, gpio, {pin_trigger})")
sm.active(1)
from time import sleep
dma_wait_for_finish(dma_ch)
dma.print_dma(dma_ch)
def print_capture():
@micropython.viper
def word(index:int) -> int:
return ptr32(buffer)[index]
sample_per_page = 60
for page in range(ceil(sample_count / sample_per_page)):
sample_idx = (page * sample_per_page)
print(f"sample index {sample_idx}")
for pin_idx in range(0, pin_count):
print(f'{int(pin_idx) + int(pin_in_base)}', end=": ")
for index_in_page in range(sample_per_page):
sample_idx = (page * sample_per_page) + index_in_page
if(sample_idx >= sample_count):
break
word_idx, sample_idx = divmod(sample_idx , sample_per_word)
bit_idx = (int(sample_idx) * pin_count) + pin_idx + 32 - int(bits_packed_per_word)
w = word(word_idx)
print(f'{"-" if w & (1 << bit_idx) else "_" }', end="")
print()
print()
print()
print_capture()
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)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment