4. DMA 中断机制:三大中断类型详解

DMA 中断,说白了就是硬件给你发的一个“信号”。它告诉你:活干完了、出错了、或者干到一半了。

我个人习惯把 DMA 中断分成三类:完成中断、错误中断、半传输中断。每种中断的触发时机不同,处理方式也不同。搞不清楚它们,调试时就容易抓瞎。

4.1 完成中断 —— 最常用的那个

这是最常见的中断类型。当 DMA 把设定的数据量全部传输完毕后,硬件就会触发这个中断。

核心作用:通知 CPU,数据已经就位,可以拿了。

我很多年前调试一个高速数据采集卡时,就遇到过一个典型的完成中断问题。板卡每采集完一帧数据,DMA 就触发完成中断,CPU 在中断里把数据搬到应用程序缓冲区。代码逻辑看着没问题,但一跑起来就丢数据。

后来发现,中断处理函数里做了太多事——又是拷贝数据,又是更新队列指针,还顺带打印调试信息。中断处理时间过长,导致下一个 DMA 传输完成时,上一个中断还没处理完。嗯,这就是典型的“中断丢失”。

我的经验:完成中断处理函数里,尽量只做“通知”工作。比如设置一个标志位,或者唤醒一个内核线程。真正费时的数据搬运,交给下半部(bottom half)去做。

4.2 错误中断 —— 不能忽视的信号

错误中断,说白了就是 DMA 干活时出岔子了。常见的错误类型有:

  • 总线错误:DMA 访问了无效的地址
  • 对齐错误:地址或长度没有按硬件要求对齐
  • 传输超时:总线一直拿不到控制权
  • 描述符错误:链式传输时,描述符链表出了问题

我曾经在一个项目中犯过这样的错:用 DMA 搬运数据时,源地址指向了一个已经释放的缓冲区。结果 DMA 一启动,立刻触发总线错误中断。系统直接 panic,所有同事都盯着我。

那次之后我养成一个习惯:注册一个错误中断的处理函数,哪怕暂时什么都不做,也要先把它打印出来。否则出了问题,你连从哪里查都不知道。

避坑指南:错误中断处理函数里,一定要清除错误标志位。否则中断会一直触发,导致系统死在中断里。我曾经被这个问题折磨了两天才找到原因。

4.3 半传输中断 —— 双缓冲区的关键

半传输中断,名字很直白——DMA 传输了一半数据时触发。这玩意主要用在音频、视频这类需要“流式”处理的场景。

你想想看,如果一个音频播放程序,要等 DMA 把整个音频文件都搬完才开始播放,那延迟得多大?用户听到的会是“咔咔”的爆音。

有了半传输中断,就可以这么玩:

  1. 把缓冲区分成两个半区:A 区和 B 区
  2. DMA 填满 A 区后,触发半传输中断
  3. CPU 在中断里处理 A 区的数据,同时 DMA 继续填 B 区
  4. DMA 填满 B 区后,触发完成中断
  5. CPU 处理 B 区数据,DMA 又回头填 A 区

这样,CPU 和 DMA 就像两个流水线工人,交替工作,永远不会互相等待。

4.4 三种中断类型的对比

为了让你更直观地理解,我整理了一个对比表:

中断类型 触发时机 典型应用场景 注意事项
完成中断 全部数据传输完毕 文件传输、内存拷贝 处理函数要轻量,避免中断嵌套
错误中断 总线错误、对齐错误等 异常处理、系统保护 必须清除错误标志,否则死循环
半传输中断 数据传输至一半时 音频流、视频流、数据采集 缓冲区大小要匹配处理速度

4.5 中断优先级与嵌套问题

讲到这里,必须提一下中断优先级。为什么?因为有时候中断之间会“打架”。

假设你同时使能了半传输中断和完成中断。DMA 先触发半传输中断,你正在处理,结果传输完成了,又触发了完成中断。如果完成中断的优先级更高,它就会打断半传输中断的处理函数。

这会造成什么后果?嗯,我在项目中遇到过:半传输中断里正更新缓冲区指针呢,被完成中断抢占了,结果指针状态不一致,数据就乱了。

我的建议:如果使用半传输中断做双缓冲,建议把半传输中断的优先级设得比完成中断高。或者,干脆在完成中断里也检查一下半传输标志位,避免漏掉状态更新。

4.6 中断延迟的根源

聊完了中断类型,我们再来看中断延迟。你可能会问:“为什么我的 DMA 中断,从触发到 CPU 开始处理,要等好几微秒?”

原因有很多,但最常见的是这几个:

  • 中断屏蔽:CPU 在处理更高优先级中断时,关掉了全局中断
  • 中断嵌套:高优先级中断占用了 CPU,低优先级中断只能排队
  • 中断控制器延迟:GIC 或者类似的硬件,分发中断需要时间
  • 上下文保存:CPU 进入中断模式前,要保存寄存器等上下文信息

我曾经在一个项目里,看到 DMA 中断延迟长达 20 微秒。排查下来,原来是因为系统里有个定时器中断,每 10 微秒触发一次,优先级还特别高。DMA 中断每次都要等定时器中断处理完才能执行。

解决方案很简单:把 DMA 中断的优先级调到比定时器高。延迟一下子就降到了 3 微秒以内。

4.7 本章知识体系

说了这么多,我们来画一张关系图,把这三类中断的来龙去脉理清楚。

DMA中断类型与处理流程 DMA 中断类型与处理流程 DMA 中断源 完成中断 错误中断 半传输中断 通知 CPU 取数据 触发下半部处理 清除错误标志位 异常记录 & 重启 切换缓冲区半区 流水线操作不等待 中断优先级影响处理顺序 高优先级中断可能抢占低优先级中断,导致延迟

这张图把三类中断的触发、处理和相互关系都画清楚了。你可以看到,完成中断和半传输中断是“好兄弟”,一起实现了双缓冲流水线。而错误中断是“坏消息”,但我们必须认真对待它。