从数据手册出发:RP2040 PIO 指令集详解
PIO 指令集
PIO 指令集共包含 9 条指令,每条指令均为 16 位长度,按功能分为 3 个固定字段(对应指令编码表):
- 指令编码段(Bit15~13):3 位,用于区分不同指令(如 JMP 对应
000、WAIT 对应001); - 侧集 / 延时段(Bit12~8):5 位,存储侧集操作值和延时周期数,具体分配规则依赖状态机的
SIDESET_COUNT配置(最多 5 位,其中SIDESET_COUNT位用于侧集,剩余位用于延时); - 指令参数段(Bit7~0):8 位,存储指令的条件、地址、源 / 目标、位数等具体参数。

所有 PIO 指令的执行时间都是一个时钟周期。
5 位长的 Delay/side-set 字段的含义依赖于状态机的 SIDESET_COUNT 配置:
- 最多 5 个 LSB 位长(位长为 5 - SIDESET_COUNT)为当前指令和下一条指令之间插入的 Delay 延迟周期数
- 最多 5 个 MSB 位长(位长为 SIDESET_COUNT)为 side-set 侧集操作,可以在该指令执行的同时,将某些 GPIO 管脚设置为某个常量
这里,延时操作可以在我们需要精确定时和或信号同步时应用,而 side-set 侧集操作允许我们在执行指令同时额外设置引脚。这对于时钟和使能等控制信号很有用,side-set 侧集操作用于控制引脚,而 OUT、MOV等指令用于处理数据。
下面对每个指令的具体含义进行介绍。
1.JMP 跳转指令
JMP 跳转指令用于根据条件判断是否执行指令跳转,改变当前程序的顺序执行流。

根据 Condition 条件判断是否修改程序计数器(PC):若条件为真,将 PC 设置为 Address 对应的指令地址;否则保持 PC 自增。无论条件是否满足,指令均消耗 1 个时钟周期,延时在条件求值后执行。
JMP 指令执行时无论 Condition 是否为真都会消耗一个时钟周期。Delay 延迟在 Condition 被求值、程序计数器被更新后发生。
参数含义如下:
Condition:Condition 是一个 3 位的二进制值(对应 000~111),决定了 “什么时候才跳转”。你可以把它理解成 “跳不跳的开关”,每个开关对应不同的判断规则;Address:Address 是一个 5 位的二进制值,对应 0~31 的整数,表示目标指令在 PIO 指令内存中的绝对地址(可以理解成 “指令的编号”)。
Condition 取值和含义如下:

Address 取值和含义如下:
- PIO 的指令内存最多能存 32 条指令,所以地址只能是 0(第一条指令)到 31(最后一条指令);
- 你不用手动算这个地址,写程序时用标签(比如 loop)代替就行,SDK 会自动把标签转换成绝对地址(新手不用管转换过程,记住用标签就行)。
汇编语法为:jmp (<cond>) <target>
其中:
<cond>是上节列出的可选的条件。如果未指定条件,则总是跳转。<target>是一个程序标签或值,表示程序内部的指令偏移量(第一条指令的偏移量为 0)。- 注意,由于 PIO JMP 指令使用 PIO 指令内存之内的绝对地址,JMP 需要在运行时根据程序的加载偏移量进行调整。
- 这一步在加载程序时由 SDK 负责,但在编码 JMP 指令供
OUT EXEC使用时需要留意这一点。
2.WAIT 延时指令
WAIT 延迟指令用于等待各种事件,例如引脚状态更改或中断发生。

WAIT 延迟指令持续等待 Source 指定的事件满足 Pol 极性条件,条件满足前状态机暂停执行;Delay 延时在等待完成后执行。
参数含义如下:
Polarity:Polarity 是一个 1 位的二进制值(只有 0 或 1),决定了 “等待的事件要处于什么状态才满足条件”,可以理解成 “等的是 0 还是 1”。Source:Source 是一个 2 位的二进制值(00~11),决定了 “我们要等什么类型的事件”,这是 WAIT 指令的核心选择项。Index:Index 是一个 5 位的二进制值,对应 0~31 的整数,表示 “在选定的事件类型中,具体等哪一个对象”。
Polarity 可选值如下所示:

Source 可选值如下所示:

Index 可选值如下所示:

汇编语法为:
wait <polarity> gpio <gpio_num>wait <polarity> pin <pin_num>wait <polarity> irq <irq_num> (rel)
其中:
<polarity>是一个值,指定极性(0 或 1);<pin_num>是一个值,指定输入管脚的编号(在状态机输入管脚映射中的编号);<gpio_num>是一个值,指定实际的 GPIO 管脚编号;<irq_num> (rel)是一个值,指定要等待的 IRQ 编号(0 ~ 7)。如果设置了rel,则实际的 IRQ 编号的计算方式为,将 IRQ 编号的最低两个数据位(irq_num(10))替换成和的最低两个数据位(irq_num(10) +sm_num(10)),其中sm_num(10) 为状态机编号;
3.IN 数据读出指令
IN 数据读出指令用于从引脚输入或 X 或 Y 暂存寄存器等数据输入源将数据转移到 ISR 中。

从 Source 移位 Bit count 个数据位(最大到 32)到输入移位寄存器(ISR)中。移位方向由各个状态机的 SHIFTCTRL_IN_SHIFTDIR 决定。
参数含义如下:
Source::数据取出的源地址,Source 是 3 位二进制值,对应不同的数据源;Bit count:Bit count 是 5 位二进制值,对应要从数据源取的位数,规则很简单:- 取值范围:
1~32位(比如拿 1 位、8 位、32 位); - 特殊编码:32 位对应的二进制是
00000(因为 5 位最多表示 31,所以用 0 代表 32)。
- 取值范围:
Source可选值如下所示
如果启用了自动推出(autopush),可以把 autopush 理解成 ISR 的 “自动存盘” 功能:
- 先给 ISR 设一个 “存盘阈值”(
SHIFTCTRL_PUSH_THRES,比如 8 位); - 每次执行 IN 指令,ISR 里的数据位数会累加,当达到阈值时,ISR 会自动把数据 “推” 到 RX FIFO(给 CPU/DMA 读);
- 推完后 ISR 会清空为 0,同时暂停接收数据(直到 FIFO 有空位);
- 如果 FIFO 满了,状态机会 “等”(暂停执行),直到 FIFO 有空位。
IN 永远使用源数据的最低 Bit count 个数据位。例如,如果 PINCTRL_IN_BASE 设置为 5(状态机输入映射从 GPIO5 开始),那么指令 IN 3, PINS 会读取管脚 5、6 和 7(不是最高位),并将这些值移入 ISR;首先,ISR 会左移或右移,为新的输入数据腾出空间,然后将输入数据复制到腾出的空间中。需要注意的是,输入数据的数据位顺序与移位方向无关。
汇编语法为:in <source>, <bit_count>
其中:
<source>是上述源之一;<bit_count>是一个值,指定了要移位的数据位数(有效值为 1 ~ 32)。
4.OUT 数据写入指令
OUT 数据写入指令用于将数据位从 OSR 移至数据目的地,例如引脚输入或 X 或 Y 暂存寄存器。

将 Bit count 个数据位移出输入移位寄存器(OSR),并写入 Destination。此外,还会增加输出移位计数器 Bit count,直到最大值 32。
参数含义如下:
-
Destination:数据写入的目的地址,Destination是 3 位二进制值(000~111),决定了数据的最终去向。 -
Bit count:Bit count 是 5 位二进制值,规则和 IN 指令完全一致:- 取值范围:
1~32位(比如移出 1 位、8 位、32 位)。 - 特殊编码:32 位对应的二进制是
00000(因为 5 位最多表示 31,所以用 0 代表 32)。
Destination可选值如下所示:![ScreenShot_2026-06-08_120645_555.png]()
- 取值范围:
将一个 32 位值写入 Destination:写入目的地的 32 位值,默认取 OSR 的低 Bit count 位,右移位时取高 Bit count 位,其余位为 0
如果启用自动加载(autopull),autopull 理解成 OSR 的 “自动补货” 功能,和 IN 指令的 autopush 是一对互补的机制:
- 设置阈值:先给 OSR 设一个 “补货阈值”(
SHIFTCTRL_PULL_THRESH,比如 8 位)。 - 自动补货:每次执行 OUT 指令,输出移位计数器会累加,当达到阈值时,OSR 会自动从 TX FIFO(CPU/DMA 给 PIO 发数据的缓冲区)加载新的 32 位数据,同时输出移位计数器清零。
- 等待机制:如果 TX FIFO 为空(没数据可补),状态机会暂停执行(直到 TX FIFO 有数据),但 OUT 指令的执行时间仍然是 1 个时钟周期。
汇编语法为:out <destination>, <bit_count>
其中:
<destination>是上述数据目的地之一<bit_count>是一个值,指定要移位的数据位数(有效值为 1 ~ 32)
5.PUSH 数据推出指令
PUSH 数据推出指令用于将 ISR 的 32 位数据推入 RX FIFO,同时清空 ISR,执行时间固定为 1 个时钟周期。

将 ISR 的内容作为一个 32 位字推入到 RX FIFO。同时将 ISR 清除为全零。
参数含义如下:
IfFull:IfFull 是 1 位二进制值(0 或 1),决定 “是否要等 ISR 里的数据位数达到阈值(SHIFTCTRL_PUSH_THRESH)才推数据”;Block:Block 是 1 位二进制值(0 或 1),决定 “RX FIFO 满了时,是暂停等还是直接扔数据”。
IfFull 的含义和参数如下:

Block 的含义和参数如下:

汇编语法为:
-
push (iffull) -
push (iffull) block -
push (iffull) nonblock其中:
-
iffull相当于上述IfFull == 1,也就是说,不指定的情况下,默认值为IfFull == 0; -
block相当于上述Block == 1,如果不指定block或noblock,则此值为默认值; -
noblock相当于上述Block == 0。![ScreenShot_2026-06-08_120723_576.png]()
6.PULL 数据加载指令
PULL 数据加载指令用于从 TX FIFO 取 1 个 32 位数据,加载到 OSR 中,同时清空 OSR,执行时间固定为 1 个时钟周期。

从 TX FIFO 加载一个 32 位字到 OSR 中。
参数含义如下:
IfEmpty:IfEmpty 用于控制 PULL 指令的执行时机,仅当输出移位计数器达到配置阈值(SHIFTCTRL_PULL_THRESH,与自动加载autopull的阈值一致)时,才执行数据加载操作;Block:Block 用于定义 TX FIFO 为空时的状态机行为,决定是否暂停执行以等待数据。
IfEmpty 的含义和参数如下:

Block 的含义和参数如下:

注意,当启用自动加载时,在 OSR 满的情况下(OSR 中仍存储有未被 OUT 指令移出的完整 32 位数据)任何 PULL 指令都是误操作,会直接将 TX FIFO 的新数据覆盖到 OSR 中,导致 OSR 中原有的未输出数据被丢失,这种操作属于硬件层面的误操作,会破坏数据输出的连续性和完整性。
PULL 指令的 “屏障” 特性,本质是利用其执行时机的可控性(通过 ifempty 参数)来阻止误操作:
- 当配置
pull ifempty时,PULL 指令仅会在输出移位计数器达到阈值(OSR 中的数据已移出大部分,接近空)时执行; - 这相当于在 OSR “满” 和 “空” 之间建立了一道 “屏障”,确保只有 OSR 数据已充分输出后,才会触发手动 PULL 操作,避免了 OSR 满时的误加载。
汇编语法为:
-
pull (ifempty) -
pull (ifempty) block -
pull (ifempty) noblock其中:
-
ifempty相当于上述IfEmpty == 1,即如果没有指定,则默认值为IfEmpty == 0 -
block相当于上述Block == 1。如果不指定block或noblock,则此值为默认值 -
noblock相当于上述Block == 0

7.MOV 数据移动指令
MOV 数据移动指令用于将数据从源地址移动到目的地址。可以使用寄存器和引脚作为数据移动的源地址、目标地址以及几个具有特殊功能的位置。

从 Source 复制数据到 Destination。
参数含义如下:
Destination:Destination为 3 位配置位,指定数据最终写入的硬件单元,部分目标具有特殊功能;Operation:Operation为 2 位配置位,用于对源数据进行预处理后再复制;Source:Source为 3 位配置位,指定数据的来源,其中STATUS为特殊状态源。
Destination 的含义和参数如下:

Operation 的含义和参数如下:

Source 的含义和参数如下:

汇编语法为:mov <destination>, (op) <source>
其中:
<destination>是上述数据移动目的地之一<op>如果存在的话,为下列值之一:!或~表示 NOT::表示反转数据位顺序
<source>是上述源之一
8.IRQ 中断写入或清除指令
IRQ 中断写入或清除指令用于引发一个中断,或对触发的中断进行清除。

参数含义如下:
Clear:Clear为 1 位配置位,决定对 IRQ 标志位执行 “清除” 还是 “设置” 操作,具有最高优先级(若Clear=1,则忽略Wait参数);Wait:Wait为 1 位配置位,仅在Clear=0(设置 IRQ)时生效,决定是否等待标志位被清除;Index:Index为 5 位配置位,其中最低 3 位(LSB)指定 IRQ 索引(0~7),最高位(MSB)控制是否启用相对寻址(模 4 运算):- 基础索引:最低 3 位直接对应 IRQ 索引 0~7,指定操作的 IRQ 标志位;
- 相对寻址(MSB=1):将状态机 ID(0~3)与 IRQ 索引的最低两位相加后取模 4,替换原索引的最低两位,第三个 LSB 位保持不变。

Clear 参数含义如下:

Wait 参数含义如下:

汇编语法如下:
irq <op> <irq_num> (_rel)
其中:
-
<op>:可选操作标识,决定指令行为(设置 / 清除 / 等待); -
<irq_num>:IRQ 编号(0~7),对应 Index 的最低 3 位; -
_rel:可选,启用相对寻址(对应 Index 的 MSB=1),实际 IRQ 编号按 “(irq_num 最低两位 + 状态机 ID) % 4” 计算(第三个 LSB 位不变)。![ScreenShot_2026-06-08_120929_929.png]()
常见用法如下:

可以在 INTR 寄存器中查看原始中断输出状态:

可以在 INTS 寄存器查看掩码中断输出状态:


9.SET 设置映射 GPIO 指令
SET 设置映射 GPIO 指令用于将数据写入到 GPIO 引脚(即控制高低电平),也可以将数据写入到 X\Y 寄存器中。

将立即数 Data 写入到 Destination。
参数含义如下:
- Destination:
Destination为 3 位配置位,指定 5 位立即数的写入对象; - Data:
Data为 5 位配置位,是直接写入目标的固定值,取值范围为 0~31(5 位二进制的最大值):- 若目标为
PINS/PINDIRS:Data 的每一位对应 SET 管脚映射中的一个 GPIO,位值 1/0 对应 GPIO 的高 / 低电平(PINS)或输出 / 输入方向(PINDIRS); - 若目标为
X/Y:Data 直接作为寄存器的低 5 位,高 27 位清 0,因此 X/Y 通过 SET 可初始化的最大值为 31(适合短周期循环计数)。
- 若目标为
该指令用于设置控制信号,如时钟或芯片选择,或初始化循环计数器。由于 Data 只有 5 个数据位,因此可擦写寄存器可以 SET 的值为 0 ~ 31,最大可循环 32 次。
SET 和 OUT 的管脚映射是独立配置的。它们可以映射到不同的位置,例如,一个管脚作为时钟信号使用,另一个作为数据使用。它们的管脚范围也可以重叠: UART 传输程序可以使用 SET 来设置开始和终止数据位,用 OUT 指令向同一个管脚上移出 FIFO 数据。
汇编语法为:set <destination>, <value>
其中:
<destination>为上述数据操作目的地;<value>是要设置的值,有效值为 0 ~ 31。

PIO 指令集共包含 9 条指令,每条指令均为 16 位长度,按功能分为 3 个固定字段(对应指令编码表):




浙公网安备 33010602011771号