尧图精选

DMA方式详解:从CPU搬砖到直接内存访问的I/O控制演进

🕒 发布时间:2026/10/1 9:17:22 📁 来源:尧图网络
说实话很多人学计算机组成原理到I/O这一章最容易卡住的地方就是DMA。嵌入式工程师天天在嘴边挂着DMA多好用可真要问一句DMA到底是怎么从CPU手里把总线拿过来的一半人会含糊。考研党更不用说程序查询、程序中断、DMA、通道这四种I/O控制方式背得滚瓜烂熟一做大题还是漏掉关键得分点。这篇文章我就围绕DMA方式这一条主线把I/O设备与主机之间信息传送控制方式的来龙去脉拆开揉碎讲清楚。内容既覆盖408考研大纲里DMA的考点也补上实际MCU开发STM32这类芯片里DMA的落地姿势。如果你正在备战计算机408或者写代码时对DMA知其然不知其所以然这篇文章应该能帮你把概念和工程串成一条线。1. 为什么高速外设让CPU手搬砖模式彻底失灵要理解DMA的价值得先看看在它之前CPU是怎么干活的。I/O控制方式的发展脉络其实是顺着一个矛盾走的外设越来越快、数据量越来越大而CPU每一笔数据都要亲自过问的话迟早会把自己活活累死。1.1 程序查询方式CPU从头到尾守着设备程序查询方式最原始也最符合直觉。CPU不断读取外设的状态寄存器判断设备是否准备好准备好了就传一个数据没准备好就继续轮询。这种办法写起来简单但CPU基本被锁死在等待上。设备处理一个字节要5毫秒CPU这5毫秒除了转圈查状态什么正事都干不了。我见过一个直观的估算假设CPU每轮询一次需要执行20条指令每条指令平均2个时钟周期。外设速率如果只有每秒1千字节CPU每秒要消耗20×2×10004万个时钟周期在1GHz主频下占用率不到1%完全能忍。但设备速率升到每秒1兆字节CPU每秒就被吃掉4000万个时钟周期占用率直接飙到40%。这还只是查询损耗没算真正搬数据的开销。所以程序查询只适合极慢速设备稍微一快就顶不住。1.2 中断方式每次都要打招呼再干活的开销程序中断方式看起来比轮询聪明多了设备准备好了主动发中断信号CPU放下手头的事去处理。问题在于中断方式的处理成本很高。一次中断要经历识别中断源、保护CPU现场压栈寄存器、跳进中断服务程序、读数据写内存、恢复现场、中断返回。这一整套动作少则几十个时钟周期多则几百个。按字节中断的话磁盘读一个扇区512字节就要触发至少512次中断。高吞吐场景下CPU绝大部分时间都在做被打断→擦屁股→接着干的循环真正用于业务计算的时间所剩无几。1.3 核心矛盾能不能有个硬件替CPU搬砖于是矛盾就很清楚了中断方式让CPU每个字节都参与搬运而高速块设备每次要搬运的是一大批连续数据。如果能把从外设取数、写到内存、数一数传了多少个、判断有没有传完这一整套动作交给专门的硬件去做CPU只需要在开头交代任务、结尾清点结果那效率就完全不同了。这就是DMADirect Memory Access直接内存访问方式的设计初衷一个专门的硬件控制器接管总线让外设和内存之间直接传数据CPU全程不碰中间数据。2. 一次DMA传送的完整生命周期谁在请求、谁在响应、谁在清场DMA这个词看起来抽象实际上它的工作流程比你想的要直白。我把整个生命周期拆成四个阶段你把这个链条记熟后面做题基本不会绕晕。2.1 阶段一CPU先给DMA控制器写任务书DMA不是自己决定要搬数据的它完全听CPU的安排。传送开始前CPU要往DMA控制器里写好几项关键参数内存首地址告诉DMA这批数据放到内存哪里传送字数告诉DMA总共要搬多少个字传送方向是从外设读到内存还是从内存写到外设设备地址告诉DMA数据从哪个外设接口来/去。这个过程叫DMA初始化可以类比成项目经理给搬家公司下工单地址写清楚、数量写清楚、方向写清楚然后项目经理就去干别的活了。2.2 阶段二和阶段三外设请求DMADMA再请求总线外部设备准备好数据后会向DMA控制器发出DMA请求信号。DMA控制器收到请求不会直接开搬而是先向CPU发出总线请求信号比如Intel体系里的HOLD/HRQ。CPU最迟在当前总线周期结束后响应这个请求让出总线控制权回一个总线应答信号HLDA。DMA控制器拿到总线才开始真正干活根据内存地址寄存器和数据计数器控制数据直接从外设接口写到内存指定位置写完一个数据自动把地址加一、计数器减一。这里有个考研常考的关键点CPU不是在任意时刻都能响应总线请求的。如果CPU正在访存DMA不能强行打断这个总线周期必须等当前周期结束才能让出总线。这就解释了为什么DMA传输偶尔会有一点点延迟——总线不能同时让两方用这是物理规则。2.3 阶段四数据块传完DMA主动交还总线并通知CPU当计数器减到0说明整个数据块传完了。DMA控制器做两件事撤销总线请求把总线还给CPU发一个中断请求信号通知CPU活干完了你来验收。注意这个中断和前面说的中断方式完全是两码事。中断方式是每传一个字节/字都要进一次中断服务程序DMA方式下整个数据块只产生一次中断而且这次中断只是用于善后比如检查数据完整性、处理下一步逻辑。这就是DMA能大幅降低CPU开销的根本原因——把每笔都报账变成了先干完再结账。3. DMA控制器内部藏着哪几张底牌从寄存器看懂硬件实现光知道流程还不够很多人做错题是因为不清楚DMA控制器内部靠什么记住任务。DMA控制器不是一堆神秘电路它就是一套专门干搬运工作的寄存器组合加上控制逻辑。3.1 四个核心部件一张表说清楚我把DMA控制器最核心的几个组成部分列成表格你对照着记会清晰很多部件/寄存器作用初始化时谁写工作过程中谁改内存地址寄存器AR/SAR存放数据块在内存的首地址每传一个数据自动递增CPU写入DMA控制器硬件自动维护字计数器WC/DC记录剩余要传送的数据个数每传一个数据减一CPU写入DMA控制器硬件自动维护设备地址寄存器DAR指明外设接口的地址CPU写入一般不变控制/状态寄存器CR/SR记录传送方向、模式、中断使能、设备状态CPU写入DMA/外设更新状态位数据缓冲寄存器暂存一次传送的数据起缓冲作用不需要DMA控制器自动使用你发现没有CPU初始化时做的事就是往这些寄存器里填初值。传送开始后地址递增、计数递减这种繁琐的活全是DMA控制器的硬件逻辑自动完成的CPU再也不用管了。这个自动递增地址、自动递减计数的机制就是DMA能独立完成数据块搬运的底气。3.2 为什么说DMA不是聪明的控制器很多人问过一个有意思的问题DMA都能自己搬数据了它算不算一个小处理器严格来说不算。DMA控制器没有指令系统不能执行程序它本质上是一套固定状态机只会按照预设好的规则完成取数据、送数据、数数、结束这一件事。你让它换个条件判断或者做复杂决策它做不到。能执行I/O指令、能控制多台设备、能在传送中做校验和转换的那是通道方式通道实际上就是一种专门处理I/O的处理器。这个区别是408考试里的高频考点后面我还会专门讲对比。3.3 实际芯片里的DMA控制器是不是这个结构这里插一句工程视角。STM32、GD32这类单片机里的DMA控制器虽然寄存器名字不叫AR、WC但逻辑结构跟教材完全对应你配置外设地址、内存地址、传输数量、传输方向对应就是填设备地址寄存器、内存地址寄存器和字计数器传输完成后触发传输完成中断对应就是DMA结束后发一次中断。也就是说你在考研卷子上画的DMA结构图和你在STM32库函数里填的结构体是一一对应的。这层对应关系能帮你把抽象的概念落回真实硬件。4. 三种访存冲突处理方式不能只背结论周期挪用的真正代价DMA要搬数据必须访问内存。CPU也要访问内存。但内存同一时刻只能给一方用。这个矛盾怎么解决就是教材里最经典的三种方式。千万别只背结论得想明白每种方式的实际代价是什么。4.1 停止CPU访存干脆利落代价也干脆第一种方式最简单粗暴DMA获得总线后CPU在数据块传送期间完全不能访存。等到整块数据传完DMA把总线交回CPU才能继续取指令、读数据。这种方式的优点是控制简单数据块可以连续快速传送适合高速外设和内存之间成批量的数据交换比如磁盘读一大块数据到内存。代价也极其明显如果数据块很长CPU可能被晾好几个存储周期。CPU的工作访存需求被完全抑制系统整体吞吐量不一定划算。在学习时别以为这是最优解——它只是特定场景下的取舍。4.2 周期挪用DMA见缝插针每次只借一个周期第二种方式叫周期挪用Cycle Stealing有的书也叫周期窃取。DMA不要求CPU整段时间让路而是在CPU不访问内存的周期里插一脚。CPU执行指令时很多周期根本不访存比如内部运算、寄存器操作这些周期里总线闲着也是闲着DMA正好借来传一个数据。传完一个数据就释放总线如果还有数据要传再申请下一轮。这个机制听着很完美但它有个隐蔽的代价DMA每传一个数据都要重新执行一遍请求总线→获得应答→传送→释放总线的过程。每次申请总线都有握手开销所以如果外设要求的传送速率非常高周期挪用的申请频率会非常密集控制开销不容忽视。另外它会轻微拖慢CPU——因为一部分本该给CPU的访存周期被DMA抽走了程序执行时间会有一点点抖动。实际MCU项目里DMA频繁搬运数据时主循环变慢本质上就是这个原因。4.3 交替分时访问把内存周期拆成两半第三种方式更进一步把内存的存储周期一分为二一个给CPU用一个给DMA用两个控制器固定交替访问内存。这种方式适用于CPU周期比内存存取周期长的情况因为一个CPU周期里可以容纳一个完整的存取周期多出来的时间正好给DMA。这种方式在硬件上实现相对复杂传送效率高但灵活性一般。它的核心思想是时间片轮转并不考虑DMA数据是否就绪固定间隔让DMA访问内存。在传统大型机上出现过你理解这个思路就行考试常以选择题形式出现要求你判断某种方式的应用场景。三种方式放到一起看本质是一个权衡DMA传送的紧急性、CPU访存的需求、硬件复杂度三者不可能同时最优。408考题特别喜欢在这里挖坑——不是问你周期挪用是什么而是给你一个具体场景让你选哪种方式、判断代价是什么。记住每种方式的代价比记住定义管用得多。5. DMA、中断、通道放在同一张表里考点立刻清晰I/O控制方式的大题最常考的就是横向比较尤其是DMA和中断的差异、DMA和通道的差异。我把它们揉在一张表里你盯着这张表记答题思路就出来了。5.1 一张表横向对比四种I/O控制方式对比维度程序查询程序中断DMA通道CPU参与程度全程参与轮询和搬运每次数据传送都要CPU服务仅在初始化时介入数据块传送期间不介入初始化后通道独立完成控制CPU极少介入数据传送单位字/字节字/字节数据块数据块/一组数据数据传送路径外设→CPU→内存外设→CPU→内存外设→内存不经CPU外设→内存不经CPU响应对象无中断主动查询CPU中断信号总线控制权请求通道指令和中断是否需要保护现场不需要每次都要数据传送中不需要结束后中断需要通道程序切换时需要一定程度的管理智能程度最低较低中等只能固定搬数据有指令系统可执行通道程序这张表最关键的一行是数据传送路径。程序查询和中断方式下数据都经过CPU内部寄存器中转DMA方式下数据直接从外设到内存CPU根本不碰数据。这就是直接内存访问这个名称的真正含义。5.2 为什么DMA结束才发中断而不是传一个发一个我接触过不少初学者纠结这个问题DMA不是也叫DMA中断吗它到底算不算中断方式答案很明确DMA的传输过程不需要中断。整个数据块搬运期间DMA控制器完全掌控总线CPU不需要被反复打断。只有数据块全部传完后DMA控制器才发出一次中断通知CPU来坐收尾工作。所以严格讲DMA方式是先DMA传送、后中断善后两者是嵌套关系而不是并列关系。考试如果问DMA和中断方式的区别一个是数据传送方法一个是CPU响应外部事件的处理机制一个以块为单位接管总线一个以事件为单位打断指令流。这两者不在同一个层级上别混着答。5.3 通道比DMA聪明在哪再往上一层是通道方式。通道本质上是专门负责I/O控制的处理器拥有自己的指令系统可以执行通道程序。通道程序能描述复杂的I/O操作序列比如从设备A读1000个字到内存地址X再从内存地址Y写到设备B中间做一次格式转换。DMA没有这个能力它只能完成固定的简单搬运。如果题目问DMA和通道的区别最核心的一点就是有无指令系统、能否执行通道程序。通道可以管理多台同类型设备DMA通常一对一服务通道的硬件成本和复杂度比DMA高不少所以小型系统用DMA大型系统才上通道。5.4 一个答题模板四个维度不丢分遇到试比较DMA方式与程序中断方式这种15分大题我的建议是从四个维度展开谁搬数据、搬多少、CPU干不干活、要不要保护现场。具体来说谁搬数据中断是CPU执行服务程序搬DMA是DMA控制器用硬件搬搬多少中断通常按字/字节DMA按数据块CPU干不干活中断整个传输过程CPU都在场DMA只在初始化和结束后在场现场保护中断每次都要保护/恢复现场DMA数据传送过程中不需要最后那次善后中断才按中断流程走。按这四个维度答条理清晰阅卷老师找得分点也容易。6. 从纸面到桌面DMA在STM32这类MCU里是怎么落地的考试考的是原理但你要是只懂原理没上手过很多结论其实是空的。反过来那些在STM32里配过DMA的工程师回到考纲知识点时往往一点就透。我在实际项目里用过不少次DMA也踩过不少坑这一段就当是从课本到板子的补充经验。6.1 从DMA请求映射看总线的分配STM32的DMA控制器有多个通道每个通道可以响应若干外设的DMA请求。配置的时候要填一堆参数外设地址、内存地址、传输方向内存到外设还是外设到内存、传输数据量、数据宽度8位/16位/32位、是否自动递增、是否循环模式、优先级。这套配置在忙碌的工程师眼里就是填结构体但在组成原理的视角下你其实是在初始化DMA控制器内部的设备地址寄存器、内存地址寄存器和字计数器。比如串口接收用DMA你把外设地址填成串口数据寄存器地址内存地址填成自己定义的缓冲区首地址数据长度填成缓冲区长然后打开DMA和外设请求。硬件就会在每次串口收到一个字节时发起一次DMA请求DMA控制器通过周期挪用的方式插在总线空闲周期里把字节搬进内存缓冲区。CPU从头到尾不碰这个字节。6.2 常见坑DMA配置对了数据却不走第一个坑外设侧的DMA请求没有使能。很多人只配置了DMA控制器忘了在外设那边打开DMA请求开关。以串口为例你要在USART的CR3寄存器里把DMAR位置1串口才会在收到数据时产生DMA请求。否则DMA控制器就像没有信号源的搬运工干等着。第二个坑传输长度算错。DMA控制器里那个字计数器的值如果配成缓冲区满长度实际数据量小的时候没有任何问题但你要是配错了长度要么传不够数要么越界写穿。尤其是配合循环模式时计数器递减到0会自动重装初值这个自动重装的行为如果不理解你会看到缓冲区里的数据乱糟糟的背景是计数器在循环重置。第三个坑缓存一致性。这在带Cache的高性能MCU上尤其明显。DMA直接把外设数据写进内存CPU读到的可能是Cache里的旧数据必须做Cache维护操作clean/invalidate。这对应到计算机组成原理里面就是Cache和DMA之间的一致性问题——DMA不经过CPUCPU并不知道Cache已经过期了。第四个坑DMA占用总线对主程序的影响。很多人以为DMA是零成本的其实它不是。大块数据用DMA搬运时因为周期挪用或者总线仲裁主程序执行会明显变慢。我调试过一次音频播放DMA在持续搬运PCM数据主循环的定时精度被扰动得很厉害。后来查资料才彻底想明白这不就是周期挪用的代价嘛。课本上那句周期挪用会轻微降低CPU访存效率在真实项目里是会咬人的。6.3 学了组成原理写代码时多问一句总线在谁手里最后分享一个我个人觉得特别有用的思考习惯写DMA相关代码时遇到灵异问题先停下来问自己一句此刻总线上到底有几路设备在抢DMA通道有好几个外设也有好几个它们同时要传数据时DMA控制器内部有优先级仲裁主CPU也在不断访存总线仲裁的结果直接决定谁的延迟高、谁的吞吐掉链子。一旦用这个思路去排查很多为什么我的DMA偶尔丢数据为什么主循环偶尔卡顿的问题都能解释清楚。这也是我为什么总跟学生说计算机组成原理不是考研专用科目它是写嵌入式代码时背后的总规则。你越早知道DMA夺走的是总线而不仅仅是帮你干活你写初始化代码时就越有底气。回头再看标题里那个DMA方式它说的从来不只是DMA控制器这一个部件而是从程序查询到程序中断再到DMA再到通道这条完整的I/O控制方式演进路线。DMA站在一个关键转折点上数据搬运动作第一次从CPU手里分离出去交给了专用硬件。理解了这个转折点你考研的大题能多拿几分调板子的效率也能高出一截。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →