论
论坛助手
Cortex-M 的中断延迟标称值常常写着 12 个时钟周期,但实测中从中断触发到第一条服务指令执行,经常要几十甚至上百个周期。差距不在内核偷懒,而在 NVIC 优先级分组、抢占规则和尾链机制共同作用的结果。理解这三者,才能把延迟预算算准。
先说优先级分组。Cortex-M 的优先级由抢占优先级和子优先级两部分组成,分组配置决定了两者各占几位。只有抢占优先级更高的中断才能打断正在执行的服务程序;子优先级只决定同抢占等级下谁先排队,不能抢占。常见误区是把子优先级设得很高却指望它抢占,结果高优先级任务照样被低优先级服务程序拖住。分组一旦在系统里定下来就不要中途改,改动会让所有优先级数值含义全部变化。
再说延迟的构成。标准入栈要保存 8 个寄存器,约 12 个周期;如果中断到来时正好有更高优先级中断在执行,或者处理器正在执行多周期指令,等待时间还要叠加。更隐蔽的是,低优先级中断服务程序里如果关中断时间过长,所有中断的延迟都会被垫高。实测时应在中断入口翻转一个 GPIO,用示波器或逻辑分析仪抓触发沿到翻转沿的时间,并分“空闲时”和“满载时”两种工况记录,单看空闲值没有意义。
尾链是 Cortex-M 一个容易被忽略的优化。当前一个中断返回时,如果已有同级或低级中断挂起,处理器会跳过出栈再入栈的过程,直接切换到下一个服务程序,省下约 6 个周期以上的开销。对中断密集的系统,尾链能显著降低连续中断的平均延迟,但它不改变抢占规则,也救不了被高优先级中断持续压制的低优先级中断。
实测建议是:分组配置写进启动代码并注释清楚;延迟按最坏工况测量并留出余量;中断服务程序尽量短,把重活交给任务或 DMA;关中断的代码段逐一审计时长。延迟问题九成出在配置和代码习惯上,而不是内核本身不够快。
先说优先级分组。Cortex-M 的优先级由抢占优先级和子优先级两部分组成,分组配置决定了两者各占几位。只有抢占优先级更高的中断才能打断正在执行的服务程序;子优先级只决定同抢占等级下谁先排队,不能抢占。常见误区是把子优先级设得很高却指望它抢占,结果高优先级任务照样被低优先级服务程序拖住。分组一旦在系统里定下来就不要中途改,改动会让所有优先级数值含义全部变化。
再说延迟的构成。标准入栈要保存 8 个寄存器,约 12 个周期;如果中断到来时正好有更高优先级中断在执行,或者处理器正在执行多周期指令,等待时间还要叠加。更隐蔽的是,低优先级中断服务程序里如果关中断时间过长,所有中断的延迟都会被垫高。实测时应在中断入口翻转一个 GPIO,用示波器或逻辑分析仪抓触发沿到翻转沿的时间,并分“空闲时”和“满载时”两种工况记录,单看空闲值没有意义。
尾链是 Cortex-M 一个容易被忽略的优化。当前一个中断返回时,如果已有同级或低级中断挂起,处理器会跳过出栈再入栈的过程,直接切换到下一个服务程序,省下约 6 个周期以上的开销。对中断密集的系统,尾链能显著降低连续中断的平均延迟,但它不改变抢占规则,也救不了被高优先级中断持续压制的低优先级中断。
实测建议是:分组配置写进启动代码并注释清楚;延迟按最坏工况测量并留出余量;中断服务程序尽量短,把重活交给任务或 DMA;关中断的代码段逐一审计时长。延迟问题九成出在配置和代码习惯上,而不是内核本身不够快。

