4. RX中断系统与通信实时性设计

在工业通信设备中,实时性往往不是由CPU主频单独决定的,而是由“中断能否及时被响应、能否按优先级抢占、数据能否少占CPU搬走”共同决定。RX系列MCU的中断系统围绕中断向量表、优先级寄存器、嵌套控制和DMAC/DTC传输构成一条完整的响应链。理解这条链,才能把UART、CAN、Ethernet等通信外设的响应时间压到可预测的范围。

中断向量表与中断源定位

RX的中断向量表固定在Flash起始区域,每个中断源占用4字节,存放服务程序入口地址。向量号由硬件外设固定分配,例如SCI0的RXI(接收完成)与TX I(发送完成)是两个独立向量,CMT、CAN、DMAC也有各自向量。开发时通常不直接手写向量表,而是由启动文件与编译器扩展(如#pragma interrupt或__attribute__((interrupt)))把C函数绑定到指定向量。关键点是:向量号必须与硬件手册一致,否则中断会跳到错误地址,表现为“进了中断但行为异常”或直接HardFault。

以SCI0接收为例,RXI0向量号在RX72N上为62,TXI0为63。若使用Smart Configurator生成代码,它会自动生成r_sci_rx_irq.c中的中断入口,并在vecttbl.c中登记。手工核对时,应确认ICU.IR[62].IR对应的函数名与链接映射一致。

优先级设置与中断嵌套

RX用IPR寄存器为每个中断源设置0~15级优先级,数值越大优先级越高。嵌套能否发生,取决于当前正在执行的中断优先级与待响应中断优先级的关系:只有待响应中断优先级严格高于当前中断,且当前中断已执行ENABLE_INTERRUPT(清除PSW.I),才会发生嵌套。默认情况下,进入中断后PSW.I被置1,屏蔽同级和低级中断;若通信协议要求“接收中断可被更高优先级的故障中断打断”,需在接收ISR开头显式开中断。

工业通信中常见的优先级分配原则是:故障保护 > 高速同步通信 > 普通数据接收 > 发送完成 > 低速后台任务。例如可将CAN错误中断设为15,Ethernet接收设为12,SCI接收设为8,SCI发送设为4。这样当CAN总线出现错误时,能立即抢占正在处理的串口接收,避免错误累积。

注意:嵌套会增大栈深度。每个嵌套层级都要保存PC、PSW和寄存器,若栈空间不足会破坏相邻变量。建议在启动文件中为IRQ栈预留至少1KB,并在嵌套层数较多时用栈填充模式(0xDEADBEEF)检查峰值。

DMAC与DTC:让数据搬运不占CPU

通信实时性的另一个瓶颈是“搬数据”。如果每个字节都靠CPU在ISR里读写寄存器,高波特率下CPU会被大量占用。RX提供两种搬运引擎:DMAC适合大块、固定通道、可链式传输的场景;DTC适合由中断触发、按向量表跳转的轻量搬运,不需要单独通道配置,但每次传输都要读向量表,开销略高。

以SCI接收为例,若波特率115200、每帧10位,则字节间隔约86.8µs。若用CPU在RXI中搬运,每次进出中断约1~2µs,占用率约2%,尚可接受;但若同时有4路串口,占用率接近8%,再加上协议解析就会吃紧。此时可配置DTC:RXI触发DTC,把RDR自动搬到接收缓冲区,每搬完一帧产生一次DTC完成中断,CPU只在缓冲区半满或全满时处理。这样CPU占用可降到原来的1/10以下。

DMAC则更适合SPI与外部ADC的连续采样:设置源地址为SPI数据寄存器,目的地址为内存数组,传输次数设为256,每次SPI接收完成触发一次DMAC,搬完256次后产生DMAC完成中断。注意DMAC与DTC不能同时占用同一中断源,配置时需在ICU中把该中断分配给DTC或DMAC,而不是CPU。

通信中断服务程序编写要点

一个可用的通信ISR应遵循“短、快、不阻塞”原则。以SCI接收ISR为例,典型结构是:读RDR清除RXI标志,把数据放入环形缓冲区,更新写指针,若缓冲区半满则置标志,最后返回。不要在ISR里做协议解析、浮点运算或printf。若必须处理复杂逻辑,用标志位通知主循环。

void sci0_rxi_isr(void)
{
    uint8_t data = SCI0.RDR;          /* 读数据,同时清RXI标志 */
    uint16_t next = (rx_w + 1) & RX_MASK;
    if (next != rx_r) {               /* 缓冲区未满 */
        rx_buf[rx_w] = data;
        rx_w = next;
        if (((rx_w - rx_r) & RX_MASK) >= RX_HALF)
            rx_half_flag = 1;         /* 通知主循环 */
    } else {
        rx_overrun++;                 /* 溢出计数,供诊断 */
    }
}

发送ISR则相反:从环形缓冲区取一个字节写入TDR,若缓冲区空则关闭TXI中断,避免空转。这种“按需开中断”的方式能显著减少无效中断次数。

响应时间测量与判断

响应时间指从中断请求置位到ISR第一条指令执行的时间,包括硬件采样、向量取址、寄存器保存和流水线刷新。RX在100MHz下,典型中断响应约6~12个周期,即60~120ns,但若正在执行长指令或处于低功耗模式,会明显延长。测量方法是用GPIO翻转:在ISR入口置高,出口置低,用示波器测高电平宽度,即为ISR执行时间;若要测响应延迟,可在中断触发源(如定时器比较输出)同时翻转另一路GPIO,测两路上升沿差值。

判断标准应结合通信协议:对于CAN,要求接收中断响应小于一帧时间的一半;对于Modbus RTU,3.5字符间隔约300µs(9600bps),ISR必须在其中完成标志清除和缓冲区写入。若实测响应时间超过预算,优先检查是否被高优先级中断长时间占用、是否在ISR中调用了库函数、以及DTC/DMAC是否与CPU争抢总线。

RX中断响应链与通信数据搬运路径 通信外设 SCI / CAN / SPI / Ethernet 中断请求 RXI / TXI / 错误标志 ICU 中断控制单元 向量表基址 + 向量号 IPR 优先级比较 PSW.I 嵌套控制 IR 请求标志 DTC/DMAC 触发选择 CPU 中断处理 保存 PC / PSW / 寄存器 跳转 ISR 入口 执行通信ISR 恢复现场 / RTFI 响应时间 ≈ 6~12 周期 DTC / DMAC DTC:向量表跳转搬运 DMAC:通道链式搬运 不占CPU,按次触发 接收/发送缓冲区 环形队列 + 半满标志 溢出计数 / 错误统计 主循环协议解析 优先级分配示例 CAN错误中断 IPR=15 Ethernet接收 IPR=12 SCI接收 IPR=8 SCI发送 IPR=4 响应时间测量:GPIO置高→ISR入口,GPIO置低→ISR出口;示波器测高电平宽度=ISR执行时间,两路上升沿差值=响应延迟

把上述环节串起来看,实时性设计不是单点优化,而是“向量正确、优先级合理、嵌套可控、搬运卸载、ISR精简、测量闭环”的组合。实际项目中,建议先用GPIO和示波器测出最坏情况下的响应时间,再决定是否需要把某路通信从CPU中断改为DTC搬运,或调整IPR让关键中断获得抢占权。只有测量结果落在协议允许的窗口内,通信实时性才算真正达标。