3. Sitara EtherCAT从站软件架构

在 Sitara AM335x/AM437x/AM57x 这类带 PRU-ICSS 的处理器上,EtherCAT 从站并不是“跑一个协议栈”那么简单,而是由三层协同构成:PRU-ICSS 内的 EtherCAT 从站控制器固件(ESC Firmware)、运行在 ARM 上的操作系统与驱动层、以及最上层的应用接口与过程数据接口(PDI)中断处理。理解这三层的分工与数据通路,是后续做从站移植、调试和性能优化的基础。

一、三层架构的分工

最底层是 PRU-ICSS EtherCAT 从站固件,TI 官方称为 PRU-ICSS EtherCAT Slave Firmware,它实现了 EtherCAT 从站控制器(ESC)的核心功能:EtherCAT 帧的收发、FMMU(Fieldbus Memory Management Unit)与 SM(SyncManager)通道管理、分布式时钟(DC)时间戳、EEPROM 读取与 SII 信息、以及过程数据接口(PDI)的读写。固件运行在两个 PRU 核上,一个负责 EtherCAT 数据链路(MII 收发与帧处理),另一个负责与 ARM 侧交互(PDI 接口、中断、寄存器访问)。

中间层是 ARM 侧的驱动与协议栈。在 SYS/BIOS 方案中,TI 提供 PRU-ICSS EtherCAT Slave Driver,配合 NDK 或裸机环境使用;在 Linux 方案中,则通过 UIO 或 remoteproc/rpmsg 暴露 PRU 寄存器与中断,再由 EtherCAT Master 协议栈(如 SOEM、IgH EtherCAT Master 的从站侧对应实现)或 TI 的 EtherCAT Slave Stack Code(SSC) 完成邮箱通信、CoE(CANopen over EtherCAT)对象字典、状态机(INIT→PREOP→SAFEOP→OP)管理。驱动层的核心职责是把 PRU 固件暴露的寄存器映射成可读写的内存区域,并把 PDI 中断转换为操作系统可处理的中断事件。

最上层是应用层接口。它通过 SSC 生成的 API(如 ECAT_Application、APPL_InputMapping、APPL_OutputMapping)把过程数据映射到用户变量,同时处理 CoE 对象字典的读写回调。应用层不直接触碰 PRU 寄存器,而是通过协议栈提供的接口完成数据交换。

PRU-ICSS EtherCAT 从站固件(ESC) PRU0:数据链路 MII 收发 / 帧解析 FMMU / SM 通道 PRU1:PDI 接口 寄存器映射 / 中断 DC 时间戳 EEPROM / SII 从站信息接口 共享 RAM 过程数据缓冲区 PDI 中断 / 寄存器访问 ARM 侧驱动与协议栈 SYS/BIOS 方案 PRU-ICSS EtherCAT Driver Hwi / Swi 中断管理 Linux 方案 UIO / remoteproc / rpmsg 字符设备 / sysfs 接口 EtherCAT Slave Stack Code(SSC) 状态机 / 邮箱 / CoE 对象字典 PDI 读写回调 API 调用 / 数据映射 应用层接口与 PDI 中断处理 APPL_InputMapping 过程数据 → 用户变量 APPL_OutputMapping 用户变量 → 过程数据 PDI 中断服务程序 同步触发 / 数据搬运

二、PDI 中断:从站实时性的关键

PDI(Process Data Interface)中断是 PRU 固件通知 ARM 侧“过程数据已更新”或“需要发送新数据”的机制。在 AM335x 上,PRU 通过 PRU_ICSS 中断控制器向 ARM 的 INTC 发出中断请求,典型映射为 PRU_ICSS_EVTOUT0~7。以 SYS/BIOS 为例,配置流程如下:

// 1. 在 PRU 固件中使能 PDI 中断
//    PRU1 写 PRU_ICSS_INTC 的 SRSR 寄存器
//    设置 PDI_ISR 位,触发 EVTOUT0

// 2. ARM 侧注册中断服务程序
Hwi_Params hwiParams;
Hwi_Params_init(&hwiParams);
hwiParams.arg = (UArg)&pdiEvent;
hwiParams.enableInt = TRUE;
Hwi_create(PRU_ICSS_EVTOUT0, pdiIsr, &hwiParams, NULL);

// 3. ISR 中读取过程数据
Void pdiIsr(UArg arg) {
    // 从共享 RAM 读取输入数据
    memcpy(inputBuffer, (void*)PRU_SHARED_RAM_IN, INPUT_SIZE);
    // 处理输出数据
    memcpy((void*)PRU_SHARED_RAM_OUT, outputBuffer, OUTPUT_SIZE);
    // 清除中断标志
    PRU_ICSS_INTC.SRSR = 0x01;
}

在 Linux 方案中,PDI 中断通常通过 UIO 设备暴露给用户空间,或由内核驱动注册 request_irq()。用户空间程序通过 read() 阻塞等待中断事件,再通过 mmap() 访问共享 RAM 完成数据交换。这种方式的实时性取决于内核调度延迟,通常需要配合 PREEMPT_RT 补丁或使用 SCHED_FIFO 实时线程。

三、应用层接口的实际使用

以 TI SSC 生成的代码为例,应用层需要实现三个关键回调:

  • APPL_InputMapping():将 ESC 收到的过程数据(如电机位置、传感器状态)复制到用户变量。
  • APPL_OutputMapping():将用户变量(如控制指令、目标位置)写入 ESC 的输出缓冲区。
  • APPL_Application():在状态机进入 OP 后周期调用,执行实际控制逻辑。

一个典型的映射示例如下:

// 输入映射:ESC 输入 → 用户变量
void APPL_InputMapping(UINT16* pData) {
    // 假设输入过程数据为 4 字节位置 + 2 字节状态
    gMotorPosition = *(INT32*)pData;
    gSensorStatus  = *(UINT16*)(pData + 2);
}

// 输出映射:用户变量 → ESC 输出
void APPL_OutputMapping(UINT16* pData) {
    *(INT32*)pData = gTargetPosition;
    *(UINT16*)(pData + 2) = gControlWord;
}

这里需要注意字节序与对齐:EtherCAT 过程数据按小端序传输,而 PRU 共享 RAM 的访问宽度为 32 位,映射时需确保指针类型与数据宽度匹配,否则会出现数据错位。

四、调试与验证要点

实际调试时,建议按以下顺序排查:

  1. 确认 PRU 固件加载成功:检查 /sys/class/remoteproc/remoteproc0/state 是否为 running,或 SYS/BIOS 下 PRU 是否已启动。
  2. 验证 PDI 中断是否触发:在 ISR 中翻转 GPIO 或用计数器统计中断次数,用示波器观察周期是否与 EtherCAT 周期一致(如 1ms)。
  3. 检查过程数据一致性:通过 ecat_master 工具读取从站输入数据,与用户变量对比,确认映射无误。
  4. 观察状态机迁移:从 INIT→PREOP→SAFEOP→OP,每一步都应有对应的邮箱通信和 PDI 中断,若卡在 SAFEOP 通常是 DC 同步或看门狗配置问题。
提示:PDI 中断的响应时间直接影响从站的最小周期。在 AM335x 上,PRU 到 ARM 的中断延迟约为 1~2μs,但 Linux 用户空间处理可能达到数十微秒。若需要更短周期,建议将关键数据搬运放在内核驱动或 PRU 内部完成,ARM 侧仅做非实时处理。

总结来说,Sitara EtherCAT 从站软件架构的核心是“PRU 固件做实时链路、ARM 驱动做桥接、应用层做业务”的三层分工。PDI 中断是连接 PRU 与 ARM 的纽带,其配置与响应特性决定了从站的实时性能。理解这三层的接口与数据流,才能在后续的移植、优化和故障排查中快速定位问题。