在 《Cortex-M系统中断延迟及其测量方法简介》 一文中,我们曾介绍过 System Design 中 Cortex-M 中断延迟的基本概念及一种使用 GPIO 模块测量中断延迟的通用方法。今天,我们就将这个理论方法付诸实践,在恩智浦 i.MXRT1xxx 系列芯片上进行一次实际测量。
一、官方指标与理论背景
恩智浦的 i.MXRT1xxx 系列微控制器均基于 Arm Cortex-M7 内核,主频覆盖 500MHz 到 1GHz 不等。以该系列的首款型号 i.MXRT1050 为例,在其官方介绍页面上,赫然标注着“低至 20ns 的中断延迟”这一关键指标。

这个 20ns 的数值是如何得出的呢?根据 Cortex-M7 内核的 计算机基础 设计,其标准中断延迟为 12 至 14 个内核时钟周期。i.MXRT1050 的主频为 600MHz,因此理论计算得到的最小延迟为:(1秒 / 600,000,000 Hz) * 12 ≈ 20ns。由此可见,官方宣传的 20ns 完全符合 ARM 给出的标准值。
那么,在实际的硬件和软件环境下,我们能否测出这个数值?不同型号之间的表现又是否一致呢?接下来,我们通过代码和示波器来寻找答案。
二、测试环境搭建与代码实现
我们选取了 i.MXRT1011、i.MXRT1021、i.MXRT1052、i.MXRT1062 和 i.MXRT1176 这五个有代表性的型号进行实测。测试代码基于各型号的官方 SDK 包构建。
以 i.MXRT1052 为例,我们选用 \SDK_2.10.0_EVKB-IMXRT1050\boards\evkbimxrt1050\driver_examples\gpio\input_interrupt 例程作为基础模板。请注意:编译时应选择 debug 配置,确保代码链接在 TCM(紧耦合存储器)中运行,以满足零等待内存访问的测试前提,避免存储器的访问延迟干扰测量结果。
核心思路是使用一个 GPIO 引脚作为外部中断触发源,并在其中断服务程序(ISR)的第一条指令处,立即翻转另一个 GPIO 引脚的电平。通过示波器测量触发信号边沿与输出信号边沿之间的时间差,即可得到中断延迟时间。
以下是按照此思想修改后的主要 C/C++ 代码:
uint32_t s_pin_low = 0x000000;
uint32_t s_pin_high = 0x800000;
////////////////////////////////////////////////////////////////////////////////
// 使用 EVKB 板上的用户按键 SW8 (GPIO5_IO00) 触发中断
void GPIO5_Combined_0_15_IRQHandler(void)
{
GPIO2->DR = s_pin_low;
GPIO2->DR = s_pin_high;
GPIO_PortClearInterruptFlags(GPIO5, 1U << 0);
__DSB();
}
void init_gpio5_0(void)
{
gpio_pin_config_t din_config = {kGPIO_DigitalInput, 0, kGPIO_IntFallingEdge};
IOMUXC_SetPinMux(IOMUXC_SNVS_WAKEUP_GPIO5_IO00, 0U);
GPIO_PinInit(GPIO5, 0, &din_config);
NVIC_EnableIRQ(GPIO5_Combined_0_15_IRQn);
GPIO_PortEnableInterrupts(GPIO5, 1U << 0);
}
////////////////////////////////////////////////////////////////////////////////
// 使用 Arduino 接口 J24-2 (GPIO1_IO02) 触发中断,测试两种中断类型
void GPIO1_Combined_0_15_IRQHandler(void)
{
GPIO2->DR = s_pin_low;
GPIO2->DR = s_pin_high;
GPIO_PortClearInterruptFlags(GPIO1, 1U << 2);
__DSB();
}
void GPIO1_INT2_IRQHandler(void)
{
GPIO2->DR = s_pin_low;
GPIO2->DR = s_pin_high;
GPIO_PortClearInterruptFlags(GPIO1, 1U << 2);
__DSB();
}
void init_gpio1_2(void)
{
gpio_pin_config_t din_config = {kGPIO_DigitalInput, 0, kGPIO_IntFallingEdge};
IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_02_GPIO1_IO02, 0U);
GPIO_PinInit(GPIO1, 2, &din_config);
NVIC_EnableIRQ(GPIO1_Combined_0_15_IRQn);
//NVIC_EnableIRQ(GPIO1_INT2_IRQn); // 用于测试独立中断
GPIO_PortEnableInterrupts(GPIO1, 1U << 2);
}
////////////////////////////////////////////////////////////////////////////////
// 初始化用于输出测量信号的 GPIO2_IO23
void init_gpio2_23(void)
{
gpio_pin_config_t dout_config = {kGPIO_DigitalOutput, 0, kGPIO_NoIntmode};
IOMUXC_SetPinMux(IOMUXC_GPIO_B1_07_GPIO2_IO23, 0U);
IOMUXC_SetPinConfig(IOMUXC_GPIO_B1_07_GPIO2_IO23, 0x70F9U);
GPIO_PinInit(GPIO2, 23, &dout_config);
GPIO2->DR |= 0x800000; // 初始化为高电平
}
int main(void)
{
BOARD_ConfigMPU();
BOARD_InitBootClocks();
CLOCK_EnableClock(kCLOCK_Iomuxc);
CLOCK_EnableClock(kCLOCK_IomuxcSnvs);
init_gpio5_0();
init_gpio1_2();
init_gpio2_23();
while (1);
}
测试说明:
- 为了结果的全面性,我们同时测试了多个不同的 GPIO 中断源。因为部分 i.MXRT 型号包含普通 GPIO 和高速 GPIO(HSGPIO),且有些 GPIO 事件既可触发“组合型”中断,也可触发“独立型”中断。
- 用于输出测量信号的 GPIO 类型(普通或高速)对本次测试结果无本质影响,其自身翻转时间极短,可忽略不计。
三、五款芯片实测数据与分析
通过对五款 i.MXRT 型号的详细测试,我们得到了以下波形图与数据表格,并可以总结出几点关键结论:
核心结论:
- 中断类型影响小:对于大多数型号,使用普通 GPIO 或 HSGPIO,以及“组合型”或“独立型”中断,测得的中断延迟时间几乎相同(i.MXRT1170 除外,其不同域的中断存在差异)。
- 实测值与理论值的差异:i.MXRT1020 和 i.MXRT1050 的实测延迟接近 ARM 标准理论值。而 i.MXRT1010、i.MXRT1060 和 i.MXRT1170 的实测值则明显大于理论值。这提示我们,最终的中断延迟不仅取决于内核,还可能受到芯片内部 GPIO 模块设计、互联总线延迟等因素的影响。
- 延迟存在波动:测量发现,GPIO 中断延迟并非一个固定值,存在大约 3 个内核时钟周期的波动。这可能是由于外部 PAD 的信号跳变与内部 NVIC 中断请求信号的同步时机存在微小随机性导致的。
3.1 i.MXRT1011 实测结果

| 系统时钟配置 |
PAD |
GPIO |
IRQ |
t1 |
t2 |
td |
中断延迟时钟数 |
| Core: 500MHz |
| IPG: 125MHz |
GPIO_01 |
GPIO1[1] |
GPIO1_Combined_0_15_IRQn |
74 - 78ns |
33ns |
41 - 45ns |
20 - 23 cycles |
|
GPIO_01 |
GPIO2[1] |
GPIO2_Combined_0_15_IRQn |
|
|
|
|
|
GPIO_SD_05 |
GPIO2[5] |
GPIO2_Combined_0_15_IRQn |
|
|
|
|
3.2 i.MXRT102x 实测结果

| 系统时钟配置 |
PAD |
GPIO |
IRQ |
t1 |
t2 |
td |
中断延迟时钟数 |
| Core: 500MHz |
| IPG: 125MHz |
GPIO_AD_B0_06 |
GPIO1[6] |
GPIO1_Combined_0_15_IRQn |
92 - 96ns |
64ns |
28 - 32ns |
14 - 16 cycles |
|
GPIO_AD_B0_06 |
GPIO1[6] |
GPIO1_INT6_IRQn |
|
|
|
|
|
SNVS_WAKEUP |
GPIO5[0] |
GPIO5_Combined_0_15_IRQn |
|
|
|
|
3.3 i.MXRT105x 实测结果

| 系统时钟配置 |
PAD |
GPIO |
IRQ |
t1 |
t2 |
td |
中断延迟时钟数 |
| Core: 600MHz |
| IPG: 150MHz |
GPIO_AD_B0_02 |
GPIO1[2] |
GPIO1_Combined_0_15_IRQn |
78 - 82ns |
54ns |
24 - 28ns |
14 - 17 cycles |
|
GPIO_AD_B0_02 |
GPIO1[2] |
GPIO1_INT2_IRQn |
|
|
|
|
|
SNVS_WAKEUP |
GPIO5[0] |
GPIO5_Combined_0_15_IRQn |
|
|
|
|
3.4 i.MXRT106x 实测结果

| 系统时钟配置 |
PAD |
GPIO |
IRQ |
t1 |
t2 |
td |
中断延迟时钟数 |
| Core: 600MHz |
| IPG: 150MHz |
GPIO_AD_B0_02 |
GPIO1[2] |
GPIO1_Combined_0_15_IRQn |
62 - 66ns |
27ns |
35 - 39ns |
21 - 24 cycles |
|
GPIO_AD_B0_02 |
GPIO1[2] |
GPIO1_INT2_IRQn |
|
|
|
|
|
GPIO_AD_B0_02 |
GPIO6[2] |
GPIO6_7_8_9_IRQn |
|
|
|
|
|
SNVS_WAKEUP |
GPIO5[0] |
GPIO5_Combined_0_15_IRQn |
|
|
|
|
3.5 i.MXRT117x 实测结果

| 系统时钟配置 |
PAD |
GPIO |
IRQ |
t1 |
t2 |
td |
中断延迟时钟数 |
| Core: 996MHz |
| BUS: 240MHz |
GPIO_AD_01 |
GPIO2[31] |
GPIO2_Combined_16_31_IRQn |
52 - 54ns |
29ns |
23 - 25ns |
23 - 25 cycles |
|
GPIO_AD_01 |
CM7_GPIO2[31] |
CM7_GPIO2_3_IRQn |
|
|
|
|
|
WAKEUP_DIG |
GPIO13[0] |
GPIO13_Combined_0_31_IRQn |
47 - 50ns |
29ns |
18 - 21ns |
18 - 21 cycles |
总结
通过本次对 i.MXRT1xxx 系列五款芯片的系统中断延迟实测,我们不仅验证了 GPIO 测量方法的可行性,还获得了不同型号芯片在真实环境下的性能数据。数据显示,虽然都基于 Cortex-M7 内核,但不同型号芯片的中断延迟表现存在差异,这提醒开发者在设计高实时性系统时,除了关注内核理论指标,还需结合具体芯片的实测数据进行综合评估。希望这些实测数据和分析能在 云栈社区 帮助到更多从事嵌入式实时系统开发的工程师。