1. PRU实时控制开发全景

在工业伺服、电机驱动、数字电源、EtherCAT从站等场景中,主控CPU往往要同时承担协议栈、人机界面、文件系统等非确定性任务,很难保证微秒级的抖动要求。TI Sitara系列处理器给出的答案是:在片内集成一个独立于ARM Cortex-A核的实时协处理器子系统——PRU-ICSS(Programmable Real-time Unit and Industrial Communication Subsystem)。理解PRU在整个芯片中的位置、它能承担什么任务、以及围绕它形成的开发流程,是后续所有章节的起点。

一、Sitara处理器的分层架构与PRU的定位

以AM335x、AM437x、AM57x、AM64x等典型器件为例,Sitara内部大致可分为四层:最外层是各类外设与工业接口,中间是互连总线与存储器子系统,再往内是ARM应用核(Cortex-A8/A9/A15/A53)与实时核(Cortex-M4F、R5F),最贴近引脚的一层则是PRU-ICSS。PRU-ICSS并不是挂在ARM外设总线上的普通外设,它拥有自己的指令存储器、数据存储器、中断控制器、GPIO与工业以太网MII接口,可以绕过Linux调度直接访问引脚。

每个ICSS包含两个PRU核(PRU0/PRU1),各自拥有8KB程序RAM、8KB数据RAM,共享64KB的共享RAM(部分器件为12KB×2)。PRU核运行在200MHz(AM64x可达333MHz),采用精简的RISC指令集,单周期执行大部分指令,没有流水线冒险带来的不确定性。它通过30位宽(部分器件为20位)的GPIO直接驱动引脚,通过eCAP、ePWM、UART、MII等外设与外部世界交互,通过INTC(中断控制器)与ARM核交换事件。

关键点在于:PRU不是“更快的GPIO”,而是一个可以独立编程的实时引擎。它不跑Linux,没有MMU,没有缓存,因此指令执行时间可精确预测。这正是它能承担微秒级实时控制任务的根本原因。

Sitara 处理器分层架构与 PRU-ICSS 定位 应用与协议层(ARM Cortex-A 核) Linux / RTOS · EtherCAT主站 · HMI · 文件系统 · 网络协议栈 L3/L4 互连总线 · 中断交叉开关 · EDMA 实时协处理器 Cortex-M4F / R5F · 确定性中断响应 PRU-ICSS 子系统 PRU0 + PRU1 · 独立RAM · INTC · MII PRU-ICSS 内部结构 PRU0 核 8KB IRAM + 8KB DRAM PRU1 核 8KB IRAM + 8KB DRAM 共享 RAM(64KB)· INTC · 工业以太网 MII · eCAP/ePWM 30位 GPIO 直连引脚 · 200MHz 单周期 RISC 外部实时对象 伺服驱动器 数字电源 EtherCAT从站 编码器/传感器 微秒级时序要求 · 抖动 < 100ns 控制 反馈

二、PRU承担的实时控制任务类型

PRU的典型任务可以归为四类,理解这四类有助于判断某个需求是否应该交给PRU。

第一类是引脚级时序生成与捕获。例如生成多路互补PWM并插入死区,或捕获编码器A/B/Z信号并计数。这类任务要求纳秒级边沿控制,ARM核即使使用硬件PWM也难以灵活调整相位关系,而PRU可以用循环精确控制每个GPIO翻转时刻。

第二类是工业通信协议的硬实时处理。EtherCAT从站的ESC(EtherCAT Slave Controller)需要在一个周期内完成帧的接收、处理与转发,PRU可以配合MII接口实现“直通”转发,把转发延迟压到几百纳秒。PROFINET IRT、POWERLINK等协议同理。

第三类是高速数据采集与预处理。例如以1MSPS读取ADC并通过SPI打包,或在PRU内完成FIR滤波、过采样、阈值比较,只把结果通过中断上报ARM,避免ARM被高频中断淹没。

第四类是自定义外设与胶合逻辑。当片上外设不够用时,PRU可以模拟UART、SPI、I2C、正交编码器接口,甚至实现简单的状态机来替代CPLD/FPGA。

判断准则:如果任务的时序要求严于10微秒、抖动要求小于1微秒,或者需要与引脚直接交互且逻辑可编程,就应优先考虑PRU;如果任务涉及复杂算法、网络协议栈或文件操作,则留在ARM侧。

三、开发流程与工具链总览

PRU开发与普通ARM Linux开发有本质区别:PRU固件是裸机程序,需要单独编译、加载、启动,并与ARM侧通过共享内存和中断通信。完整的开发流程如下。

第一步:环境搭建。在Ubuntu主机上安装TI的Processor SDK(如AM64x的SDK 09.x),其中包含PRU代码生成工具(ti-pru-cgt)、PRU固件加载器(remoteproc)、以及pru-software-support-package示例库。交叉编译工具链为arm-linux-gnueabihf或aarch64-linux-gnu。

第二步:编写PRU固件。使用C语言或PRU汇编,通过#include <pru_cfg.h>等头文件访问PRU寄存器。固件中需要初始化INTC、配置GPIO方向、设置共享内存指针,然后进入主循环。例如一个简单的PWM生成片段:

// 示例:PRU0 生成 10kHz PWM,占空比由共享内存控制
volatile uint32_t *shared = (uint32_t *)0x00010000;
while (1) {
    uint32_t duty = shared[0];      // ARM 写入的占空比
    __R30 |= (1 << 0);              // GPIO0 拉高
    __delay_cycles(duty);
    __R30 &= ~(1 << 0);             // GPIO0 拉低
    __delay_cycles(20000 - duty);   // 200MHz 下 20000 周期 = 100us
}

第三步:编译与打包。用clpru编译生成.out文件,再用pru-elf2bin或SDK中的工具转换为.bin,放入Linux文件系统/lib/firmware/目录。

第四步:加载与启动。在ARM Linux侧通过remoteproc框架加载:

echo am64x-pru0-fw > /sys/class/remoteproc/remoteproc0/firmware
echo start > /sys/class/remoteproc/remoteproc0/state

加载成功后,PRU核开始执行固件,ARM可以通过/dev/mem或UIO映射共享内存,通过pruss_intc触发中断。

第五步:调试与验证。常用手段包括:用示波器观察GPIO波形验证时序;通过共享内存打印调试变量;使用CCS(Code Composer Studio)配合JTAG进行单步调试;用devmem2读写PRU寄存器检查状态。

四、学习路径与本章定位