PIO 的 OSR 与 ISR
前言
使用树莓派 Pico 的 PIO 模块时,我们经常会接触到两个特殊的寄存器:OSR(Output Shift Register) 和 ISR(Input Shift Register)。它们是数据在 Python 层和 PIO 程序之间交互的桥梁。
这一篇我们就带大家全面了解 OSR 与 ISR 的用途、区别、典型应用场景,并配合代码实战讲清楚背后的机制。
OSR & ISR 是什么?
PIO 是一个指令极少、资源有限的小型状态机,它没有常规意义上的 RAM 或寄存器堆。为了收发数据,它使用两个特别的寄存器:
寄存器 | 全称 | 用途 |
---|---|---|
OSR | Output Shift Register | 主程序(Python)→ PIO -----发数据! |
ISR | Input Shift Register | PIO → 主程序(Python)-----收数据! |
OSR:发送数据到 PIO 的桥梁
数据流方向
Python → FIFO → OSR → PIO 程序
常用指令
-
pull(): 从 FIFO 中拉一条数据进 OSR。
-
mov(pins, osr): 将 OSR 中的数据移动到 GPIO 引脚输出。
-
mov(x, osr):将 OSR 的值写入 X 寄存器等。
示例代码
@asm_pio(out_init=rp2.PIO.OUT_LOW, out_shiftdir=rp2.PIO.SHIFT_LEFT, autopull=True)
def push_out():mov(pins, osr) # 把 OSR 的值直接输出到引脚
-
autopull=True 表示 OSR 消耗完就自动从 FIFO 拉数据;
-
你可以在 Python 中用 sm.put(0xAA) 推送数据给 PIO。
ISR:从 PIO 接收数据的管道
数据流方向
PIO 程序 → ISR → FIFO → Python
常用指令
-
in(pins, 1): 从某个 GPIO 引脚读取 1 bit 到 ISR。
-
push(): 将 ISR 的值推送到 FIFO,让 Python 层读取。
-
mov(isr, x): 将寄存器值手动放入 ISR。
示例代码
@asm_pio(in_shiftdir=rp2.PIO.SHIFT_LEFT, autopush=True, push_thresh=8)
def pull_in():in_(pins, 1) # 每次读取1位,累积到 ISR
-
autopush=True:当 ISR 累积够 push_thresh(如8位)后,自动推送到 FIFO;
-
Python 端可用 sm.get() 获取数据。
OSR & ISR的应用场景
场景 | 使用寄存器 | 说明 |
---|---|---|
串口发送 | OSR + mov(pins, osr) | 把要发的字节写入 OSR,逐位输出 |
串口接收 | ISR + in(pins, 1) + push() | 将输入逐位移入 ISR,达到位数后推送 |
多值缓存 | ISR + mov(isr, x) | 临时在 ISR 中存多位数据再发送 |
控制输出模式 | OSR + jmp(pin, label) | 用 OSR 控制逻辑流转 |
Python 与 OSR/ISR 的桥梁:FIFO
-
每个状态机都有两个 4 项深度的 FIFO:
TX FIFO(OSR 发送)
RX FIFO(ISR 接收)
-
Python 端用:
sm.put(val) 将数据送入 OSR(TX FIFO)
sm.get() 从 ISR(RX FIFO)接收数据
注意事项:
-
如果 pull() 时 FIFO 为空,状态机会挂起等待
-
如果 push() 时 FIFO 满了,状态机会暂停直到 FIFO 腾空
总结
名称 | 用途 | Python 接口 | PIO 指令 |
---|---|---|---|
OSR | 输出移位寄存器(Python → PIO)[发送!] | sm.put() | pull, mov(pins, osr) |
ISR | 输入移位寄存器(PIO → Python)[接收!] | sm.get() | in, push, mov(isr, x) |