[AT32F437] 如何判断DMA中断是否被高优先级中断阻塞?

[复制链接]
123|5
铁血丹心LLLL 发表于 2025-10-31 01:21 | 显示全部楼层 |阅读模式
要判断 DMA 中断是否被高优先级中断阻塞,可以通过硬件监测、中断日志分析和代码 instrumentation 等方法,从 “中断响应延迟” 和 “中断抢占关系” 两个维度进行验证。以下是具体实现方案:
一、硬件级监测(最直接的方法)
利用 GPIO 引脚在中断入口 / 出口翻转电平,通过示波器或逻辑分析仪捕捉中断执行时序,直观判断是否被阻塞。
实现步骤:
配置一个空闲 GPIO 引脚(如 PA0),作为中断活动的 “标记线”。
在 DMA 中断服务程序(ISR)中翻转电平:
c
运行
// DMA接收中断处理函数
void DMA1_Channel3_IRQHandler(void)
{
  // 进入中断时置高电平
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);

  // 实际中断处理(调用HAL库回调)
  HAL_DMA_IRQHandler(&hdma_usart2_rx);

  // 退出中断时置低电平
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);
}
对系统中所有高优先级中断做同样处理(如定时器中断、SPI 中断),使用不同 GPIO 引脚(如 PA1、PA2)。
分析方法:
用示波器同时监测 DMA 中断标记线(PA0)和高优先级中断标记线(如 PA1):
若 PA0 的高电平出现前,PA1 有持续的高电平(超过正常中断处理时间),说明 DMA 中断被该高优先级中断阻塞。
若 DMA 中断的 “进入 - 退出” 时间间隔突然变长,且期间有其他中断标记线的电平变化,表明发生了中断抢占。

 楼主| 铁血丹心LLLL 发表于 2025-10-31 01:22 | 显示全部楼层
中断响应延迟统计(软件日志法)
通过定时器记录 DMA 中断触发到实际执行的时间差,判断是否存在异常延迟(被阻塞)。
实现步骤:
初始化一个高精度定时器(如 TIM2,配置为 1MHz 计数,精度 1μs):
c
运行
void MX_TIM2_Init(void)
{
  TIM_HandleTypeDef htim2;
  htim2.Instance = TIM2;
  htim2.Init.Prescaler = SystemCoreClock / 1000000 - 1; // 1μs计数
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 0xFFFFFFFF; // 最大计数
  HAL_TIM_Base_Init(&htim2);
  HAL_TIM_Base_Start(&htim2);
}
在 DMA 中断触发源处记录 “理论触发时间”:对于串口 DMA 接收,可在 UART 的ORE(溢出)标志或 DMA 的TC(传输完成)标志置位时记录时间(需结合硬件特性)。更简单的方法是在中断服务程序中记录 “实际进入时间”,并与上一次中断的理论结束时间对比:
c
运行
volatile uint32_t dma_irq_entry_time = 0;
volatile uint32_t dma_irq_prev_exit_time = 0;
volatile uint32_t dma_irq_delay = 0; // 中断延迟时间(μs)

void DMA1_Channel3_IRQHandler(void)
{
  // 记录进入中断的实际时间
  dma_irq_entry_time = TIM2->CNT;
  
  // 计算延迟:本次进入时间 - 上次退出时间(理论上应接近0)
  if (dma_irq_prev_exit_time > 0) {
    dma_irq_delay = dma_irq_entry_time - dma_irq_prev_exit_time;
    // 若延迟超过阈值(如100μs),记录异常
    if (dma_irq_delay > 100) {
      dma_blocked_count++; // 统计被阻塞次数
    }
  }
  
  // 执行中断处理
  HAL_DMA_IRQHandler(&hdma_usart2_rx);
  
  // 记录退出时间
  dma_irq_prev_exit_time = TIM2->CNT;
}
主循环中打印或存储延迟数据,分析是否存在周期性的大延迟(被高优先级中断阻塞的特征)
 楼主| 铁血丹心LLLL 发表于 2025-10-31 01:22 | 显示全部楼层
中断优先级与抢占关系验证
通过动态调整中断优先级,观察 DMA 中断丢失是否缓解,反推是否被高优先级中断阻塞。
验证步骤:
记录当前所有中断的优先级配置(在stm32xxxx_it.c或 NVIC 初始化函数中):
c
运行
// 示例:查看优先级
printf("DMA IRQ priority: %d\n", NVIC_GetPriority(DMA1_Channel3_IRQn));
printf("TIM2 IRQ priority: %d\n", NVIC_GetPriority(TIM2_IRQn));
printf("SPI1 IRQ priority: %d\n", NVIC_GetPriority(SPI1_IRQn));
(注:STM32 中优先级数值越小,优先级越高)
临时提高 DMA 中断优先级(高于所有其他中断):
c
运行
// 仅用于测试
HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 0, 0); // 最高优先级
对比调整前后的数据丢失情况:
若调整后数据丢失明显减少或消失,说明原 DMA 中断优先级过低,被其他高优先级中断阻塞。
若问题依旧,可能是其他原因(如缓冲区管理、硬件溢出)。
 楼主| 铁血丹心LLLL 发表于 2025-10-31 01:22 | 显示全部楼层
特殊场景:嵌套中断阻塞检测
若高优先级中断内部又触发了其他中断(嵌套中断),可能导致 DMA 中断长期被阻塞。可通过以下方法检测:
在高优先级中断中添加 “禁止嵌套” 代码(临时测试):
c
运行
void TIM2_IRQHandler(void)
{
  __disable_irq(); // 禁止所有中断嵌套
  
  // 原定时器中断处理代码
  HAL_TIM_IRQHandler(&htim2);
  
  __enable_irq(); // 恢复中断
}
若 DMA 数据丢失减少,说明嵌套中断是阻塞原因之一。
统计各中断的执行时长:在每个中断的入口 / 出口记录时间,计算单次中断的执行时间:
c
运行
// 在高优先级中断中
volatile uint32_t tim2_irq_duration = 0;
void TIM2_IRQHandler(void)
{
  uint32_t start = TIM2->CNT;
  HAL_TIM_IRQHandler(&htim2);
  tim2_irq_duration = TIM2->CNT - start; // 记录执行时间(μs)
}
若某高优先级中断的tim2_irq_duration超过串口一个字节的传输时间(如 115200bps 下约 10μs),则必然会阻塞 DMA 接收。
 楼主| 铁血丹心LLLL 发表于 2025-10-31 01:22 | 显示全部楼层
总结判断流程:
先用硬件 GPIO 标记法捕捉中断时序,确认是否有高优先级中断在 DMA 中断触发时活跃。
再用延迟统计法量化 DMA 中断的响应延迟,判断是否超过合理范围。
最后通过调整优先级验证阻塞关系,定位具体的抢占中断。
通过这三个步骤,可精准判断 DMA 中断是否被高优先级中断阻塞,并定位到具体的干扰中断源。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

80

主题

547

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部