当前位置: 首页 > news >正文

单片机开发---RP2040数据手册之PIO功能

手册第三章

3.1 概述(Overview)

RP2040 包含两个 PIO 子系统:PIO0 和 PIO1。每个 PIO 提供了 灵活的可编程状态机(state machines),可以用来实现几乎任何串行或并行通信协议,而不占用 CPU 资源。
每个 PIO 包含:

  • 4 个独立的状态机(state machines)
  • 32 条指令内存(instruction memory)
  • FIFO 缓冲区(TX 和 RX)
  • GPIO 映射逻辑
  • IRQ 和 DMA 接口

这些状态机可以协同工作,实现如 WS2812、DVI、I2C、SPI、UART、Manchester 编码等协议,甚至是自定义协议。

3.2 程序员模型(Programmer’s Model)

3.2.1 PIO 程序(PIO Programs)

PIO 程序是用一种小型汇编语言编写的,最多支持 32 条指令。每条指令执行一个时钟周期,支持以下操作:

指令 功能
jmp 条件跳转
wait 等待 GPIO 电平或边沿
in 从 GPIO/FIFO/引脚读取数据
out 向 GPIO/FIFO/引脚输出数据
push 将数据推入 RX FIFO
pull 从 TX FIFO 拉取数据
mov 在寄存器之间移动数据
irq 触发中断
set 设置 GPIO 状态

3.2.2 控制流程(Control Flow)

状态机可以:

  • 独立运行
  • 同步运行(使用 IRQ 或 FIFO)
  • 通过 jmp 实现循环、分支
  • 使用 wait 实现精确时序控制

3.2.3 寄存器(Registers)

每个状态机都拥有少量内部寄存器。这些寄存器用于保存输入或输出数据,以及临时值(例如循环计数器变量)
每个状态机有以下寄存器:

寄存器名 功能
x, y 通用 scratch 寄存器
isr 输入移位寄存器
osr 输出移位寄存器
pc 程序计数器
shiftctr 移位计数器
execctrl 执行控制寄存器(如 autopull、autopush)
pinctrl 引脚控制寄存器(如引脚映射、方向)
3.2.3.1 输出移位寄存器(OSR)

在这里插入图片描述

图 40. 输出移位寄存器(OSR)
输出移位寄存器(OSR)用于在 TX FIFO 与引脚(或其他目标,如暂存寄存器)之间缓存并移位输出数据。

  • PULL 指令:从 TX FIFO 中取出 1 个 32 位字,并加载到 OSR。
  • OUT 指令:将 OSR 中的数据逐位输出(每次 1~32 位),输出方向可配置为左移或右移。
  • 数据回收:未使用的输出数据会被双向移位器回收。
  • 自动重载:当 OSR 为空时,若启用了 autopull,状态机会自动从 TX FIFO 重新加载一个新的 32 位字。
  • OSR 在数据移出过程中,空出的位会被自动填充为 0。

解释一下autopull功能
未启用 autopull 的版本(pull_example1)

program pull_example1
loop:out pins, 8        ; 输出 8 位到引脚pull               ; 手动从 TX FIFO 拉取 32 位数据到 OSRout pins, 8 [1]    ; 再次输出 8 位,延迟 1 个周期out pins, 8 [1]    ; 输出第 38 位,延迟 1 个周期out pins, 8        ; 输出第 48 位jmp loop

autopull 简化版(pull_example2)
启用 autopull后,硬件会在 OSR 空时自动从 FIFO 重新加载数据。状态机若尝试从空 OSR 输出,会自动暂停。
优点:

  • 无需手动使用 pull 指令;
  • 吞吐量更高:若 FIFO 保持充足,可每个时钟周期输出 32 位。

简化后的程序如下,功能与上例完全一致:

program pull_example2
loop:out pins, 8        ;2 个时钟周期输出 1 字节jmp loop

使用程序循环包装进一步优化(pull_example3)
启用程序包装后,可进一步简化代码,并实现每个系统时钟周期输出 1 字节:

program pull_example3
.wrap_targetout pins, 8 [1]    ; 每周期输出 1 字节
.wrap

✅ 总结

版本 是否手动 pull 是否使用 autopull 是否使用程序包装 输出速率
示例 1 ✅ 是 ❌ 否 ❌ 否 每 2 周期 1 字节
示例 2 ❌ 否 ✅ 是 ❌ 否 每 2 周期 1 字节
示例 3 ❌ 否 ✅ 是 ✅ 是 每周期 1 字节
3.2.3.2 输入移位寄存器(ISR)

功能与OSR相反,从IO读取数据,写入数据缓冲区
在这里插入图片描述

图 41 输入移位寄存器(ISR)与数据 RXFIFO
移位寄存器:

  • 每次通过引脚接收 1~32 位数据
  • 当前内容向左或向右移位,为新数据腾出空间
  • IN 指令每次将 1~32 位数据移入寄存器
  • 寄存器装满后,其内容被写入 RX FIFO
  • PUSH 指令将 ISR 内容写入 RX FIFO,随后 ISR 被清零
  • 如果启用了自动推送(autopush),当移入数据达到设定的移位阈值后,状态机会在 IN 指令执行时自动推送 ISR 内容至 RX FIFO。

移位方向可通过处理器的配置寄存器进行设置。
对于 UART 等外设,由于线路顺序是 LSB 在前,因此必须从左端移入才能保证位序正确;然而,处理器可能期望最终字节右对齐。
为解决此问题,提供了特殊的 null 输入源,允许程序员在数据之后向 ISR 中移入若干位 0。

3.2.3.3. 移位计数器

状态机通过硬件计数器记录通过 OUT 指令从输出移位寄存器(OSR)移出以及通过 IN 指令移入输入移位寄存器(ISR)的总位数。这些信息始终由一对硬件计数器跟踪——输出移位计数器和输入移位计数器——每个计数器的值范围为 0 到 32(包含 32)。每次移位操作时,相关计数器会增加移位数,最大值为 32(等于移位寄存器的宽度)。状态机可以配置为在计数器达到可配置阈值时执行特定操作:

  • 当移出一定数量的位后,OSR 可以自动重新填充。详见第 3.5.4 节。
  • 当移入一定数量的位后,ISR 可以自动清空。详见第 3.5.4 节。
  • PUSH 或 PULL 指令可以根据输入或输出移位计数器进行条件判断。

在 PIO 复位或 CTRL_SM_RESTART 信号断言时,输入移位计数器被清零(尚未移入任何位),输出移位计数器初始化为 32(没有剩余位需要移出;完全耗尽)。其他一些指令会影响移位计数器:

  • 成功的 PULL 操作将输出移位计数器清零。
  • 成功的 PUSH 操作将输入移位计数器清零。
  • MOV OSR,…(即任何写入 OSR 的 MOV 指令)将输出移位计数器清零。
  • MOV ISR,…(即任何写入 ISR 的 MOV 指令)将输入移位计数器清零。
  • OUT ISR,count 设置输入移位计数器为 count。
3.2.3.4. 暂存寄存器

每个状态机有两个32位的内部暂存寄存器,称为 X 和 Y。
它们用作:

  • IN/OUT/SET/MOV 指令的源/目标
  • 分支条件的源

例如,假设我们想要为“1”数据位产生一个长脉冲,为“0”数据位产生一个短脉冲:

.program ws2812_led
public entry_point:pull                ; 拉取操作set x, 23           ; 设置 x 为 23,循环 24 位
bitloop:set pins, 1         ; 将引脚驱动为高电平out y, 1 [5]        ; 移出 1 位,并将其写入 yjmp !y skip         ; 如果位为 0,则跳过额外的延迟nop [5]             ; 无操作,延迟 5 个周期
skip:set pins, 0 [5]     ; 将引脚驱动为低电平,延迟 5 个周期jmp x-- bitloop     ; 如果 x 不为零,则跳回 bitloop,并递减 xjmp entry_point     ; 跳转到入口点

在这里,X 用作循环计数器,Y 用作从 OSR 分支到单个位的临时变量。该程序可以用于驱动 WS2812 LED 接口,尽管更紧凑的实现是可能的(例如,仅用 3 条指令)。
MOV 指令允许使用暂存寄存器来保存/恢复移位寄存器,例如,如果您想重复移出相同的序列。

3.2.3.5. FIFO

每个状态机都有一对4字深度的FIFO,一个用于从系统到状态机(TX)的数据传输,另一个用于从状态机到系统(RX)。TX FIFO由系统总线主设备(如处理器或DMA控制器)写入,而RX FIFO由状态机写入。FIFO解耦了PIO状态机和系统总线的时序,使状态机能够在没有处理器干预的情况下运行更长时间。
FIFO还生成数据请求(DREQ)信号,允许系统DMA控制器根据RX FIFO中的数据存在或TX FIFO中新数据的空间来调整其读写操作。这使得处理器可以设置一个长事务,可能涉及许多千字节的数据,而无需进一步的处理器干预。
通常,状态机只在一个方向上传输数据。在这种情况下,SHIFTCTRL_FJOIN选项可以将两个FIFO合并为一个单向8字深度的FIFO。这对于DPI等高带宽接口非常有用。

3.2.4. 暂停

状态机可能会因为多种原因暂时暂停执行:

  • WAIT 指令的条件尚未满足
  • 当 TX FIFO 为空时的阻塞 PULL,或当 RX FIFO 已满时的阻塞 PUSH
  • 设置了 IRQ 标志并等待其清除的 IRQ WAIT 指令
  • 启用了自动拉取(autopull)时的 OUT 指令,并且 OSR 已经达到其移位阈值
  • 启用了自动推送(autopush)时的 IN 指令,ISR 达到其移位阈值,并且 RX FIFO 已满

在这种情况下,程序计数器不会前进,状态机将在下一个周期继续执行该指令。如果指令指定在下一个指令开始之前有一些延迟周期,则这些延迟周期在暂停清除后才会计时。

3.2.5. 引脚映射

PIO 控制多达 32 个 GPIO 的输出电平和方向,并可以观察它们的输入电平。在每个系统时钟周期,每个状态机可以执行以下操作之一或两者:

  • 通过 OUT 或 SET 指令更改某些 GPIO 的电平或方向,或通过 IN 指令读取某些 GPIO
  • 通过边设操作更改某些 GPIO 的电平或方向

这些操作中的每一个都作用于四个连续的 GPIO 范围之一,每个范围的基地址和计数通过每个状态机的 PINCTRL 寄存器配置。对于 OUT、SET、IN 和边设操作,每个操作都有一个范围。每个范围可以覆盖给定 PIO 块(在 RP2040 上这是 30 个用户 GPIO)的任何 GPIO,并且这些范围可以重叠。
对于每个单独的 GPIO 输出(电平和方向),PIO 会考虑该周期内可能发生的所有 8 次写操作,并应用来自编号最高的状态机的写操作。如果同一个状态机同时对同一个 GPIO 执行 SET/OUT 和边设操作,则使用边设操作。如果没有状态机写入该 GPIO 输出,则其值不会从前一个周期改变。
通常,每个状态机的输出映射到一组不同的 GPIO,实现某些外设接口。

3.2.6. IRQ 标志

IRQ 标志是状态位,可以由状态机或系统设置或清除。总共有 8 个:所有 8 个对所有状态机都是可见的,并且较低的 4 个也可以通过 IRQ0_INTE 和 IRQ1_INTE 控制寄存器掩码到 PIO 的一个中断请求线。
它们有两个主要用途:

  • 从状态机程序中断言系统级中断,并可选地等待中断被确认
  • 在两个状态机之间同步执行

状态机通过 IRQ 和 WAIT 指令与这些标志进行交互。

3.2.7. 状态机之间的交互

指令存储器被实现为一个1写4读的寄存器文件,因此所有四个状态机可以在同一个周期内读取指令,而不会停顿。
应用多个状态机有三种方式:

  • 在同一个程序中指向多个状态机
  • 在不同的程序中指向多个状态机
  • 使用多个状态机运行同一接口的不同部分,例如 UART 的发送(TX)和接收(RX)端,或 DPI 显示器上的时钟/同步和像素数据

状态机之间不能直接通信数据,但可以通过使用 IRQ 标志进行同步。总共有 8 个标志(其中较低的 4 个可以被掩码用作系统 IRQ),每个状态机可以使用 IRQ 指令设置或清除任何标志,并可以使用 WAIT IRQ 指令等待某个标志变高或变低。这允许状态机之间进行周期精确的同步。

3.3 PIO 汇编器(pioasm)

pioasm 是官方提供的 PIO 汇编器,支持以下语法:

3.3.1 指令

以下指令用于控制 PIO 程序的组装。

指令 描述
.define (PUBLIC) <symbol> <value> 定义一个名为 <symbol> 的整数符号,其值为 <value>。如果 .define 出现在第一个程序之前,则为全局定义。
.program <name> <name> 名称开始一个新的程序。程序持续到另一个 .program 指令或源文件结束。
.origin <offset> 可选指令,用于指定程序必须加载的 PIO 指令内存偏移量。通常用于必须在偏移量 0 处加载的程序。
.side-set <count> (opt) <pinds> 指定要使用的边集位的数量。可选的 opt 参数指定 side_valuespinds 参数指示边集值应用于 PINDIRs 而不是 PINs。
.wrap_target 放置在指令之前,指定由于程序包装而继续执行的指令。只能在程序内使用一次。
.wrap 放置在指令之后,指定在正常控制流之后程序将包装到 wrap_target 指令。只能在程序内使用一次。
.lang_opt <lang> <name> <option> 为特定语言生成器指定与程序相关的选项。只在程序内有效。<
http://www.dtcms.com/a/419672.html

相关文章:

  • 怎么免费做网站视频教学网站不收录 域名问题
  • 青海省城乡建设厅网站首页网站缩放代码
  • 学习2025.9.28
  • C++协程
  • 模电基础:多级放大电路与集成运放的认识
  • 汕头网站推广教程.电子商务网站规划
  • 深入理解哈希表:闭散列与开散列两种实现方案解析
  • 无锡网站推广公司排名线下推广都有什么方式
  • Linux从入门到精通——基础指令篇(耐人寻味)
  • 网站建设 运维 管理包括哪些公众号开发者中心在哪
  • IDEA AI Agent
  • 有没有帮人做数学题的网站现在网站建设都用什么语言
  • 解决Ubuntu22.04 安装telnetd ubuntu入门之二十九
  • 个人网站怎么写网站哪里可以做
  • 嵌入式linux内核驱动学习2——linux启动流程
  • 机械网站案例分析wordpress导航栏插件
  • 大姚县建设工程招标网站云平台网站叫什么
  • mysql独立表空间迁移
  • 泸州网站建设价格高端网站建设公司排名
  • 实战:SQL统一访问200+数据源,构建企业级智能检索与RAG系统(下)
  • 免费公司主页网站开源seo软件
  • 创建网站需要学什么知识四川省建设监理协会网站
  • Android Studio历史版本下载
  • Vue3 + TypeScript + Ant Design Vue 实战:密码表单校验与拓展功能(强度提示 + 显示/隐藏密码)
  • 单页式网站网站建设的公司都有哪些
  • 正规的金融行业网站开发深圳高端网站设计公司
  • 2025年AI人才市场分析与CAIE认证备考指南
  • asyncio.Lock 的使用
  • 某制造业公司整体网络规划设计方案和实施过程要点(全套中兴方案)
  • 毕业设计代做网站都有哪些成都网站建设哪家比较好