
DMA这三个字母如果你正在啃408的计算机组成原理大概率已经在输入输出系统那一章被它绊过一跤。教材上给的定义很干脆——直接存储器存取数据在内存和外设之间搬来搬去不用CPU插手。但真到做题的时候很多人还是分不清它和中断方式到底差在哪为什么DMA能解放CPU周期挪用又是怎么个挪法。这篇就把DMA方式从为什么需要它到考试怎么考完整拆一遍顺带把那些教材上一笔带过、但做题时处处是坑的细节补上。1. 从程序查询到DMACPU到底被谁拖住了1.1 三种控制方式的本质区别I/O设备和主机之间传数据核心矛盾只有一个CPU太快外设太慢。一台主频3GHz的处理器一个时钟周期大约0.33纳秒而一个机械硬盘读写一个扇区动辄几毫秒两者差了将近七个数量级。这个速度鸿沟决定了CPU不能傻等着外设必须有一套机制来协调。程序查询方式是最原始的做法。CPU不断读取设备状态寄存器检查数据是否准备好。设备没准备好就继续查准备好了就传一个字节或一个字。这种方式的问题显而易见——CPU的时间几乎全耗在查岗上真正干活的时间被严重挤压。你可以把它理解成一个前台接待员每隔十秒就跑去仓库问货到了没有来回跑的路上什么正事都干不了。程序中断方式进了一步。CPU发完I/O命令后就去执行别的程序设备准备好数据后主动发中断信号通知CPUCPU暂停当前工作转去处理数据传送。这就像仓库管理员货到了给你打个电话你再去取。效率提升明显但每次传送一个字节或一个字都要打断CPU一次中断处理本身有开销——保存现场、跳转中断服务程序、恢复现场这些动作加起来可能比传送一个字节本身还费时间。对于高速外设比如磁盘、网卡大批量传数据中断方式的中断开销会大到不可接受。DMA方式则是彻底换了个思路。既然CPU只是负责搬砖这个动作本身不需要动脑子那就找一个专门的搬运工——DMA控制器DMAC来干这件事。CPU只需要告诉DMAC从哪个设备读、写到内存哪个位置、传多少数据、传完了告诉我一声。剩下的搬运工作DMAC自己完成CPU该干嘛干嘛去。1.2 DMA的核心价值把CPU从搬运工变成指挥官理解DMA的价值关键在于区分数据传送和数据处理这两件事。在程序查询和中断方式下数据传送这个动作本身是由CPU执行的——数据必须经过CPU的寄存器中转从设备到CPU再到内存或者反过来。CPU在这里扮演的是搬运工的角色虽然中断方式下它只在数据准备好时才搬但搬这个动作还是它做的。DMA方式下数据传送的路径变成了设备↔内存直连数据不再经过CPU。DMAC接管了地址总线和数据总线的控制权直接在内存和外设之间开辟一条数据通道。CPU的角色从搬运工升级成了指挥官——它只负责下达命令和接收完成通知具体的搬运工作全部交给DMAC。这个变化带来的性能提升是数量级的。以磁盘读取为例假设一个扇区512字节中断方式下需要中断512次每次传一个字节每次中断开销假设50个时钟周期总共就是25600个时钟周期纯开销。DMA方式下只需要在开始和结束时各处理一次中间的数据传送完全由硬件完成CPU开销几乎可以忽略。1.3 为什么408特别爱考DMA翻翻历年408真题DMA相关的考点出现频率相当高。原因很简单DMA是I/O控制方式演进的终点它把前面几种方式的优缺点都串起来了。一道题可以同时考中断和DMA的对比、考周期挪用和停止CPU访存的区别、考DMAC的组成和工作流程、考总线仲裁知识点密度极大特别适合出综合题。而且DMA这个概念在实际工程中无处不在。STM32的串口DMA发送、ADC多通道DMA采集、SPI DMA传输这些嵌入式开发中的常规操作底层原理就是408教材上讲的DMAC工作流程。把408的DMA搞透了看这些实际应用的配置代码会顺畅很多。2. DMAC内部到底装了些什么2.1 四个核心寄存器各管什么DMAC不是一块黑盒它内部有几个关键寄存器每个都有明确分工。理解这些寄存器的作用是搞懂DMA工作流程的基础。内存地址寄存器MAR存放数据在内存中的起始地址。如果是设备到内存的传送MAR指向数据要写入的内存首地址如果是内存到设备MAR指向数据要读出的内存首地址。每传送一个数据MAR自动加一或减一指向下一个存储单元。设备地址寄存器DAR存放I/O设备的地址也就是设备接口中数据寄存器的端口号。这个地址在传送过程中通常不变因为数据总是从同一个设备端口读出或写入。传送长度计数器WC记录还需要传送多少个数据。每传送一个数据WC减一。当WC减到零时表示传送完成DMAC向CPU发出中断请求。这个计数器决定了DMA传送的批量大小。控制与状态寄存器CSR存放控制信息和状态信息。控制位包括传送方向读/写、是否允许中断、DMA使能等状态位包括传送完成标志、错误标志等。CPU通过读写这个寄存器来启动DMA、查询状态、响应中断。考试中经常考的一个细节MAR和WC在每次传送后都要修改而DAR通常不变。如果题目问哪些寄存器在DMA传送过程中需要修改答案就是MAR和WC。2.2 DMAC与CPU、内存、设备的连接关系DMAC在系统中的位置很特殊它同时连接着三样东西CPU、内存、I/O设备。但它和CPU之间不是主从关系而是共享总线的对等关系。这就引出了一个关键问题——总线归谁用。DMAC需要控制总线才能进行数据传送而CPU也要用总线取指令、读写数据。两者不能同时使用总线必须有仲裁机制。常见的做法是DMAC向CPU发送总线请求信号HOLDCPU在当前总线周期结束后让出总线控制权发出总线响应信号HLDADMAC获得总线控制权后开始传送数据传完后释放总线CPU重新接管。这个让出-接管-释放的过程就是DMA传送对CPU最直接的影响。CPU不是完全不受影响而是在DMA传送期间无法访问内存。这个影响的大小取决于DMAC采用哪种总线占用方式。2.3 数据传送方向与工作模式DMAC支持三种数据传送方向设备到内存读操作、内存到设备写操作、内存到内存某些DMAC支持。408考试主要考前两种。设备到内存的流程设备数据准备好后向DMAC发DMA请求DMAC向CPU发总线请求获得总线控制权后从设备读取数据写入MAR指向的内存单元MAR加一WC减一判断WC是否为零不为零则继续为零则释放总线并向CPU发中断。内存到设备的流程类似只是数据方向反过来从MAR指向的内存单元读出数据写入设备其余步骤相同。这里有一个容易混淆的点DMA请求和中断请求是两回事。DMA请求是设备向DMAC发出的表示我有数据要传中断请求是DMAC向CPU发出的表示数据传完了。前者在每个数据传送前都可能发生后者只在整批数据传送完成后发生一次。3. 三种DMA传送方式CPU到底被偷走多少时间3.1 停止CPU访存最简单也最霸道停止CPU访存方式下DMAC一旦获得总线控制权就独占总线直到整批数据传送完毕才释放。在这段时间里CPU完全无法访问内存只能执行那些不需要访存的指令比如寄存器运算实际上大部分时间处于停滞状态。这种方式的优点是控制简单DMAC不需要复杂的仲裁逻辑。缺点是CPU被长时间挂起内存利用率也不高——DMAC传送数据时可能只需要占用部分内存周期但停止CPU访存方式下整个内存周期都被DMAC占着浪费了内存带宽。从数据传送效率看这种方式适合数据传送速率极高的场景比如高速磁盘阵列。但在408考试中它更多是作为一个对比基准出现用来和周期挪用、周期交替方式做比较。3.2 周期挪用偷一个周期还一个周期周期挪用也叫周期窃取是考试中最常考的方式。它的核心思想是DMAC不独占总线而是在CPU不使用总线的那些时钟周期里偷一个周期来完成一次数据传送。具体来说当设备有DMA请求时DMAC向CPU申请总线。CPU在当前总线周期结束后让出一个总线周期给DMACDMAC利用这个周期完成一次数据传送然后立即释放总线。CPU继续执行下一条指令。如果下一条指令不需要访存CPU甚至感觉不到总线被偷走过。这种方式下DMA传送对CPU的影响被降到最低。每次DMA传送只占用一个内存周期CPU的执行速度最多降低到原来的几分之一取决于DMA请求的频率。但代价是DMAC需要更复杂的控制逻辑因为每次传送都要重新申请总线。这里有一个计算题常考的点如果DMA请求频率很高CPU可能每个总线周期都要让出一次此时CPU的性能会下降到接近停止CPU访存方式的水平。所以周期挪用方式下DMA请求的频率决定了CPU性能的下降程度。3.3 周期交替CPU和DMAC轮流坐庄周期交替方式介于前两者之间。它把时间划分为固定长度的周期块每个周期块内一部分时间给CPU访存一部分时间给DMAC传送数据。比如一个周期块包含4个时钟周期其中2个给CPU2个给DMAC交替进行。这种方式的好处是CPU和DMAC都有确定的总线使用时间不会出现某一方被完全饿死的情况。缺点是灵活性差如果CPU或DMAC在分配给自己的时间段内没有访存需求这段时间就白白浪费了。三种方式的对比可以用一个表格来总结对比维度停止CPU访存周期挪用周期交替总线控制权DMAC独占按需申请固定分配CPU受影响程度最大最小中等DMAC控制复杂度最简单最复杂中等内存利用率最低最高中等适用场景高速大批量传送低速随机传送中速规律传送3.4 一个具体的计算例子假设某系统时钟频率为100MHz一个总线周期包含4个时钟周期即总线周期为40ns。CPU执行一条指令平均需要2个总线周期取指和访存各一次。现在有一个DMA请求每次传送一个32位数据传送速率为每秒500万次。在周期挪用方式下每次DMA传送占用一个总线周期40ns每秒500万次DMA请求意味着每秒占用500万×40ns0.2秒的总线时间。也就是说CPU有20%的时间无法使用总线。如果CPU原本执行一条指令需要80ns现在由于总线被占用平均每条指令的执行时间会延长。具体延长多少取决于DMA请求和CPU访存的冲突概率。这个计算在408真题中经常出现关键是要区分清楚时钟周期、总线周期、指令周期这几个概念以及DMA传送占用的是哪个级别的时间单位。4. DMA与中断的配合为什么DMA传送完成后还要中断4.1 DMA不处理异常中断负责善后一个常见的困惑是既然DMA已经解放了CPU为什么传送完成后还要发中断直接让CPU轮询状态寄存器不就行了吗答案在于效率。如果CPU轮询它就必须周期性地检查DMAC的状态寄存器这又回到了程序查询方式的老路。而中断方式下CPU在DMA传送期间可以完全不管直到DMAC主动通知它。所以DMA和中断不是替代关系而是配合关系——DMA负责数据搬运中断负责通知CPU搬运完成。更进一步DMA传送过程中可能出现异常情况比如设备故障、数据校验错误、总线错误等。这些异常需要CPU介入处理而DMAC本身没有处理异常的能力只能通过中断把CPU叫来处理。所以中断在DMA体系中承担的是异常处理和善后的角色。4.2 中断服务程序在DMA流程中的位置完整的DMA传送流程中中断服务程序出现在最后一步。以磁盘读取为例CPU初始化DMAC设置MAR指向内存缓冲区首地址DAR指向磁盘接口数据端口WC设置为要读取的字节数CSR设置传送方向为设备到内存、允许中断。CPU启动DMA然后转去执行其他程序。磁盘控制器从磁盘读取数据每准备好一个字节或一个字向DMAC发DMA请求。DMAC向CPU申请总线获得后从磁盘接口读取数据写入内存MAR加一WC减一。重复步骤3-4直到WC减到零。DMAC向CPU发中断请求。CPU响应中断执行中断服务程序检查传送是否成功处理可能的异常然后继续原来的程序。中断服务程序在这里做的事情很少——检查状态、处理异常、通知上层软件数据已就绪。真正耗时的数据搬运已经被DMAC做完了。4.3 中断优先级与DMA请求的优先级关系在同时有DMA请求和中断请求的情况下谁的优先级更高这个问题在408中经常以选择题形式出现。一般来说DMA请求的优先级高于中断请求。原因很直接DMA请求对应的是数据传送如果得不到及时响应数据可能丢失比如设备的数据寄存器被新数据覆盖而中断请求对应的是CPU的后续处理晚一点响应通常不会导致数据丢失。所以当DMAC和CPU同时竞争总线时总线仲裁器通常优先满足DMAC。但这个优先级关系不是绝对的。在某些系统中如果中断请求对应的是紧急事件比如电源故障可能会被赋予更高的优先级。408考试中如果没有特别说明默认DMA请求优先级高于中断请求。5. 408真题中的DMA考点拆解5.1 常见题型与解题思路408中DMA相关题目主要有以下几种类型概念辨析题问DMA方式和中断方式的区别或者问DMA方式下CPU是否完全不需要干预。这类题的关键是记住DMA的三个不——数据不经过CPU、CPU不参与搬运、但CPU仍需初始化和善后。计算题给定DMA传送速率、总线周期、CPU指令执行时间等参数计算CPU性能下降百分比或者计算DMA传送占用总线的比例。解题关键是理清时间单位区分时钟周期、总线周期、存取周期。流程排序题给出DMA传送的若干步骤要求排序。这类题需要熟记DMAC的工作流程特别是总线请求和DMA请求的先后顺序。寄存器功能题问MAR、WC、DAR、CSR各自的作用或者问传送过程中哪些寄存器需要修改。5.2 一道典型真题的完整分析以某年408真题为例题目大意某系统采用周期挪用方式DMACPU主频500MHzCPI为4即每条指令平均4个时钟周期DMA传送速率为每秒2MB每次DMA传送4字节。求CPU用于DMA的时间比例。解题步骤计算DMA传送次数每秒2MB ÷ 4字节 500K次/秒。每次DMA传送占用一个总线周期。假设一个总线周期等于一个时钟周期简化处理则每次占用2ns。DMA每秒占用总线时间500K × 2ns 1ms。CPU每秒总时间1秒 1000ms。CPU用于DMA的时间比例1ms / 1000ms 0.1%。如果题目进一步问CPU性能下降多少则需要考虑DMA占用总线时CPU是否完全停滞。在周期挪用方式下如果CPU恰好不需要访存则性能不受影响如果需要访存则被延迟。实际计算中通常简化为CPU性能下降比例等于DMA占用总线比例。5.3 容易踩的坑第一个坑混淆DMA请求和中断请求。DMA请求是设备发给DMAC的中断请求是DMAC发给CPU的。考试中经常把这两个概念对调来迷惑考生。第二个坑忽略DMA传送前的初始化开销。有些题目问DMA方式下CPU完全不参与数据传送对吗答案是错的因为CPU需要初始化DMAC设置寄存器传送完成后还需要处理中断。第三个坑周期挪用方式下DMA传送占用的是总线周期还是时钟周期。这取决于题目给出的条件。如果题目说每次DMA传送占用一个总线周期那就用总线周期计算如果说占用一个时钟周期就用时钟周期计算。审题时务必看清。第四个坑DMA传送过程中MAR和WC的修改时机。是在传送前修改还是传送后修改标准流程是传送一个数据后MAR加一WC减一然后判断WC是否为零。所以判断WC是否为零是在修改之后进行的。6. 从408到实际工程DMA在嵌入式中的真实样子6.1 STM32串口DMA发送的配置逻辑学408的时候可能觉得DMA是个抽象概念但如果你用过STM32的HAL库配置串口DMA发送会发现教材上的DMAC寄存器在代码里都有对应。以STM32F4的串口DMA发送为例配置流程大致如下// 1. 使能DMA时钟和串口时钟 __HAL_RCC_DMA1_CLK_ENABLE(); __HAL_RCC_USART1_CLK_ENABLE(); // 2. 配置DMA流 hdma_usart1_tx.Instance DMA1_Stream6; hdma_usart1_tx.Init.Channel DMA_CHANNEL_4; hdma_usart1_tx.Init.Direction DMA_MEMORY_TO_PERIPH; // 内存到外设 hdma_usart1_tx.Init.PeriphInc DMA_PINC_DISABLE; // 外设地址不变 hdma_usart1_tx.Init.MemInc DMA_MINC_ENABLE; // 内存地址递增 hdma_usart1_tx.Init.PeriphDataAlignment DMA_PDATAALIGN_BYTE; hdma_usart1_tx.Init.MemDataAlignment DMA_MDATAALIGN_BYTE; hdma_usart1_tx.Init.Mode DMA_NORMAL; // 普通模式传完停止 hdma_usart1_tx.Init.Priority DMA_PRIORITY_HIGH; HAL_DMA_Init(hdma_usart1_tx); // 3. 关联DMA到串口 __HAL_LINKDMA(huart1, hdmatx, hdma_usart1_tx); // 4. 启动DMA发送 HAL_UART_Transmit_DMA(huart1, buffer, length);对照408的知识点Direction对应CSR中的传送方向位PeriphInc和MemInc对应MAR和DAR是否递增Mode对应是否循环传送Priority对应总线仲裁优先级。教材上的抽象概念在这里全部落地了。6.2 DMA缓冲区的双缓冲机制实际工程中DMA传送经常配合双缓冲使用。原因很简单如果只有一个缓冲区DMA正在往缓冲区写数据时CPU不能读这个缓冲区否则会读到不完整的数据。双缓冲机制下DMA写缓冲区A时CPU读缓冲区BDMA写完后切换CPU读ADMA写B如此交替。这个机制在408教材中通常不涉及但它是DMA在实际系统中发挥威力的关键。STM32的DMA支持双缓冲模式DMA_MODE_CIRCULAR配合两个内存地址可以在不中断数据流的情况下实现连续采集。6.3 DMA传送完成中断的实际处理在STM32中DMA传送完成会触发中断对应408中讲的DMAC向CPU发中断请求。中断服务程序通常做这几件事void DMA1_Stream6_IRQHandler(void) { if (__HAL_DMA_GET_FLAG(hdma_usart1_tx, DMA_FLAG_TCIF6)) { __HAL_DMA_CLEAR_FLAG(hdma_usart1_tx, DMA_FLAG_TCIF6); // 传送完成通知上层应用 dma_tx_complete_callback(); } }这段代码和408中描述的中断服务程序做的事情完全一致检查状态标志、清除标志、执行善后处理。区别只在于408用文字描述这里用代码实现。7. 几个反复被问到的细节问题7.1 DMA方式下CPU和DMAC会同时访存吗不会。DMA传送和CPU访存都需要使用内存总线而内存总线在同一时刻只能被一个主设备控制。所以DMAC获得总线控制权时CPU无法访存CPU使用总线时DMAC必须等待。这正是周期挪用方式下偷周期的由来——DMAC只能在CPU不使用总线的间隙插入自己的传送。但有一种例外情况如果系统采用多端口存储器比如双端口RAM内存有多个访问端口CPU和DMAC可以同时访问不同的端口。这种设计在高端系统中存在但408考试中默认单端口存储器CPU和DMAC不能同时访存。7.2 DMA传送是否影响CPU的指令执行影响程度取决于DMA传送方式。停止CPU访存方式下CPU完全无法访存只能执行寄存器运算类指令实际上大部分时间停滞。周期挪用方式下CPU只在DMA传送的那个总线周期被延迟其他时间正常执行。周期交替方式下CPU在分配给自己的时间段内正常执行在DMAC的时间段内停滞。从指令执行的角度看DMA传送影响的是需要访存的指令取指、读写数据不影响纯寄存器运算指令。但现代CPU中取指本身就需要访存所以实际上几乎所有指令都会受到不同程度的影响。7.3 DMA传送的优先级一定高于中断吗不一定但通常如此。DMA请求的紧迫性来自数据可能丢失的风险——如果设备的数据寄存器被新数据覆盖旧数据就丢了。中断请求的紧迫性来自事件的时效性但大多数情况下晚几个周期处理不会造成数据丢失。所以系统设计时通常给DMA更高的总线优先级。但在某些实时系统中如果某个中断对应的是紧急事件比如故障保护可能会通过总线仲裁器给中断更高的优先级。408考试中如果没有特别说明默认DMA优先级高于中断。7.4 为什么DMA传送不需要CPU参与却还需要CPU初始化因为DMAC本身没有智能它不知道要传什么数据、传到哪里、传多少。这些信息必须由CPU通过程序设置到DMAC的寄存器中。CPU初始化DMAC的过程本质上是在告诉DMAC做什么而DMAC执行传送的过程是怎么做。CPU负责决策DMAC负责执行。这就像你给快递员一个包裹和地址快递员负责送但送什么、送到哪是你决定的。DMA传送完成后CPU还需要处理中断相当于确认快递是否送达、有没有损坏。7.5 周期挪用方式下DMA请求的频率上限是多少理论上如果DMA请求频率等于总线周期频率即每个总线周期都有DMA请求那么CPU每个总线周期都要让出总线此时CPU的性能下降到接近停止CPU访存方式。但实际上DMA请求频率受限于设备的传送速率通常远低于总线频率。以磁盘为例假设磁盘传送速率为100MB/s每次DMA传送4字节则DMA请求频率为25M次/秒。如果总线周期为10ns100MHz则总线周期频率为100M次/秒。DMA请求频率25M次/秒意味着每4个总线周期才有一次DMA请求CPU有75%的总线周期可以使用。这个比例在实际系统中是可以接受的。8. 把DMA放进整个I/O体系里看8.1 DMA在I/O控制方式演进中的位置I/O控制方式的演进路线是程序查询→程序中断→DMA→通道→I/O处理机。每一步都在减少CPU对I/O操作的介入程度。程序查询方式下CPU全程参与效率最低。程序中断方式下CPU只在数据传送时介入但每次传送一个字节或一个字都要介入一次。DMA方式下CPU只在整批数据传送前后介入中间完全不参与。通道方式下CPU只需要发一条I/O指令通道自己执行通道程序完成整批数据的传送CPU介入程度进一步降低。I/O处理机方式下I/O处理机是一台独立的处理器有自己的指令系统可以执行完整的I/O程序CPU几乎完全不介入。DMA在这个演进链条中处于中间位置——它解决了数据搬运的效率问题但没有解决I/O控制的智能化问题。通道和I/O处理机则进一步把控制逻辑也从CPU手中接管了。8.2 DMA与通道的区别通道本质上是一个简化版的处理器它能执行通道程序由通道指令组成控制多台设备的I/O操作。DMA控制器只能控制一台或少数几台设备且只能执行固定的传送操作不能执行程序。从408考试的角度DMA和通道的区别主要体现在DMA是硬件控制器通道是处理器DMA控制单台设备通道控制多台设备DMA执行固定操作通道执行通道程序。这些区别在选择题中经常出现。8.3 DMA在现代计算机中的位置现代计算机中DMA已经无处不在。显卡通过DMA与内存交换纹理数据网卡通过DMA收发网络包硬盘通过DMA读写数据甚至CPU内部的一些加速器也通过DMA与内存交互。可以说没有DMA现代计算机的I/O性能会倒退几个数量级。408教材中讲的DMA是最基本的模型实际系统中的DMA控制器要复杂得多——支持分散-聚集scatter-gather、支持多通道、支持优先级仲裁、支持错误纠正等。但核心原理没有变CPU下达命令DMAC执行搬运完成后中断通知CPU。我在实际调试STM32的ADC多通道DMA采集时最深的体会是DMA配置中最容易出错的地方不是寄存器设置而是缓冲区对齐和传送长度的匹配。如果缓冲区没有按数据宽度对齐或者传送长度设置错误DMA会静默地传错数据而且不会报错。这种问题在408考试中不会遇到但在实际工程中非常常见。所以每次配置DMA我都会先检查这三个参数源地址、目的地址、传送长度确保它们和数据宽度、缓冲区大小完全匹配。