Last active
January 15, 2023 00:52
-
-
Save azechi/b1a89ead90b9147adc64e4baf0b60c0c to your computer and use it in GitHub Desktop.
Raspberry Pi Pico MicroPython Logic Analyser
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] &= 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 |
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
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() |
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) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment