2. Sitara硬件实时特性剖析

在 Sitara 平台上做实时性优化,第一步不是改内核参数,而是先看清硬件本身给了哪些“确定性资源”。AM335x 与 AM57xx 虽然同属 Sitara 家族,但实时能力的来源并不相同:AM335x 的实时性主要依赖 PRU-ICSS 与较简单的 Cortex-A8 + 中断/定时器组合;AM57xx 则拥有双核 Cortex-A15、C66x DSP、两个 PRU-ICSS 子系统以及更复杂的互连与内存层级。理解这些差异,才能判断一个抖动到底来自 CPU 调度、中断延迟、DMA 争用,还是内存访问路径。

中断控制器:实时响应的第一道门

AM335x 使用 INTC(Interrupt Controller)管理 Cortex-A8 的 IRQ/FIQ,外设中断先进入 INTC,再按优先级送到 CPU。它的关键参数是优先级分组与嵌套能力:高优先级中断可以抢占低优先级中断服务程序,但嵌套层数受硬件与软件栈限制。AM57xx 则采用 GIC(Generic Interrupt Controller)架构,支持 SPI、PPI、SGI 三类中断,并可通过 CPU 接口分发到 A15 或 DSP。GIC 的优先级字段更宽,配合 Linux 的 IRQ affinity 可以把关键中断绑定到固定 CPU,减少跨核迁移带来的缓存失效与调度抖动。

实际工程中,判断中断路径是否成为瓶颈,可以观察 /proc/interrupts 中目标中断的计数增长与 CPU 分布。如果关键中断分散在多个 CPU 上,说明 affinity 未固定;如果单次中断处理时间波动大,则要检查 ISR 中是否做了耗时操作,或是否被更高优先级中断频繁打断。对于 AM335x,还要注意 INTC 的 INTCPS 寄存器组中优先级阈值的设置,阈值过高会屏蔽低优先级中断,过低则可能引入不必要的嵌套。

定时器:时间基准的确定性来源

实时系统需要一个稳定、低抖动的时间基准。AM335x 提供多个 DMTimer,其中 DMTimer2 常被用作 Linux 的 clocksource,DMTimer3 可用于 PWM 或周期触发。DMTimer 的计数时钟来自 24MHz 晶振或 PER PLL,分频后决定分辨率。若用 24MHz 直接计数,单 tick 约 41.67ns,足以支撑微秒级定时;但若经过大分频,分辨率下降,定时抖动会明显增大。

AM57xx 除了 DMTimer,还集成了 GP Timer 与 Watchdog Timer,并可通过 PWMSS 产生高精度脉宽调制。对于需要严格周期性的任务,建议使用 DMTimer 的自动重载模式,并在 PRU 或 DSP 侧直接读取计数器,避免经过 Linux 时钟子系统带来的软件延迟。一个常见的教学示例是:将 DMTimer 配置为 1kHz 周期中断,在 ISR 中翻转 GPIO,用示波器观察 GPIO 方波的周期抖动。若抖动在 ±2μs 以内,说明定时器路径基本可用;若达到几十微秒,则要检查中断是否被屏蔽、是否与其他高优先级中断冲突。

PRU-ICSS:绕过 Linux 的硬实时通道

PRU-ICSS 是 Sitara 最具特色的实时资源。AM335x 有 2 个 PRU 核,AM57xx 有 2 个 PRU-ICSS 子系统、共 4 个 PRU 核。每个 PRU 运行在 200MHz(AM335x)或更高频率,拥有独立的 8KB 指令 RAM、8KB 数据 RAM 和 32 位通用寄存器,可直接访问 GPIO、UART、eCAP 等外设,不经过 Linux 调度。这意味着 PRU 可以实现纳秒级到微秒级的确定性响应,适合编码器采集、步进电机脉冲生成、EtherCAT 从站等场景。

使用 PRU 的关键是划分职责:Linux 负责配置、管理和非实时任务,PRU 负责硬实时循环。两者通过共享内存和中断通信。例如,PRU 每 1μs 采样一次 ADC 并写入共享内存,Linux 每 1ms 读取一次并做处理。此时实时性由 PRU 循环保证,Linux 的抖动不再影响采样周期。需要注意的是,PRU 访问外部内存时仍受互连带宽限制,若与 DMA 或 CPU 争用同一路径,延迟会上升。

DMA 与内存架构:隐藏的抖动来源

DMA 能减轻 CPU 负担,但也会引入新的不确定性。AM335x 的 EDMA 和 AM57xx 的 SDMA/EDMA 在搬运数据时会占用互连总线与内存控制器带宽。如果 DMA 突发长度大、目标内存区域与 CPU 热点数据在同一 bank,CPU 访问延迟会突然增加,表现为实时任务偶尔超时。因此,实时数据缓冲区应尽量放在片上 SRAM(如 OCMC RAM)或 PRU 的本地数据 RAM,避免与 Linux 的通用内存争用。

内存架构方面,AM335x 的 L1/L2 缓存与 DDR 之间通过 EMIF 连接,DDR 刷新和仲裁会带来几十到几百纳秒的波动。AM57xx 增加了多级互连和 MMU,缓存一致性由硬件维护,但跨核共享数据仍可能因缓存行迁移产生延迟。对于实时任务,建议将关键代码和数据锁定在 L2 SRAM 或 OCMC RAM,并减少跨核共享写操作。若必须共享,使用无锁环形缓冲区并配合内存屏障,避免伪共享。

Sitara 实时资源与数据路径示意(AM335x / AM57xx) Cortex-A8 / A15 Linux 调度 · 非实时任务 IRQ / FIQ · GIC / INTC 中断控制器 INTC(AM335x) GIC(AM57xx) DMTimer / GP Timer 24MHz 基准 自动重载 · PWM PRU-ICSS 200MHz 独立核 纳秒级响应 EDMA / SDMA 突发搬运 · 总线争用 内存层级 L1/L2 · OCMC · DDR 共享内存 PRU ↔ Linux 通信 实时结果 低抖动 · 确定性 实时性影响要点: 1. 中断优先级与 affinity 决定响应延迟;INTC/GIC 阈值设置不当会屏蔽关键中断。 2. DMTimer 分频越小分辨率越高;PRU 可绕过 Linux 调度实现纳秒级确定性。 3. DMA 与 CPU 争用总线会引入抖动;关键数据放 OCMC/SRAM 可降低延迟波动。 4. 跨核共享数据需注意缓存一致性与伪共享;无锁环形缓冲区 + 内存屏障是常用手段。

把硬件特性落到配置与验证

在 AM335x 上,一个可复现的验证流程是:先用 cat /proc/interrupts 确认 DMTimer 中断号,再通过 echo <cpu> > /proc/irq/<irq>/smp_affinity 绑定到 CPU0;随后用 cyclictest -p 80 -t 1 -n -i 1000 -l 10000 测量 1ms 周期下的最大延迟。若最大延迟超过 100μs,可进一步检查 PRU 是否已启用、DMA 是否在后台搬运大块数据。AM57xx 上则可用 taskset 将实时线程绑定到 A15 的某个核,并关闭该核的 CPU idle 深度状态,减少唤醒延迟。

需要强调的是,硬件实时特性只是基础,最终抖动还取决于内核配置、驱动行为和任务优先级。但若连中断控制器、定时器、PRU、DMA 和内存路径都没有理清,后续的软件调优很容易变成盲目试错。先把这张硬件地图画清楚,再谈优化,才是 Sitara 实时工程的正确起点。