☰
计算机组成原理:DMA方式原理、408考点与嵌入式实战
2026/9/28 3:32:21 网站建设 项目流程

1. 从一道408真题说起:DMA到底在考什么

如果你正在准备计算机408统考,或者本科学计算机组成原理时被I/O那一章折磨过,那你一定对“DMA方式”这四个字不陌生。每年考研季,唐朔飞和白中英两位老师的教材里,DMA这一节都是绕不过去的重点。2024年408第45题就考了DMA相关的计算,很多同学考完出来一脸懵——明明背了“DMA是直接存储器访问”,为什么一到算传输时间、算周期挪用就卡壳?

问题的根源在于:大多数人学DMA只记住了结论,没搞懂它到底在解决什么问题,以及它是怎么一步步从程序查询、中断方式演化过来的。这篇文章我就按一个从业者的视角,把DMA方式从头到尾拆一遍。不管你是考研党、期末突击选手,还是做嵌入式开发时天天跟STM32的DMA打交道但没深究过原理的工程师,这篇内容都能帮你把这块知识焊死在脑子里。

先说清楚这篇文章能给你什么:第一,把I/O设备与主机之间信息传送的三种控制方式(程序查询、中断、DMA)的演化逻辑讲透,让你明白DMA为什么必须存在;第二,把DMA控制器的内部结构、工作流程、三种数据传送方式(停止CPU访存、周期挪用、交替访问)逐一拆解,配合计算示例;第三,把408考试里DMA常考的题型和坑点整理出来,给你一套可以直接用的解题框架;第四,补充一些实际工程中DMA配置的经验,比如STM32的DMA通道选择、缓冲区对齐这些教材上不会细讲但实际会踩坑的地方。

2. I/O信息传送方式的演化逻辑:为什么会有DMA

2.1 程序查询方式:CPU当“保姆”的时代

要理解DMA的价值,得先看看没有DMA的时候,主机是怎么跟I/O设备打交道的。最早的方式叫程序查询方式,也叫程序直接控制方式。它的逻辑特别简单粗暴:CPU要读一个数据,就发一条I/O指令启动设备,然后进入一个循环,不停地读设备的状态寄存器,看数据准备好了没有。没准备好就继续循环等,准备好了就把数据从设备的数据寄存器搬到内存。

这种方式的问题用脚想都知道——CPU的时间全浪费在“等”上面了。假设一个键盘输入,人打字的速度跟CPU主频比起来慢得像蜗牛爬,CPU在循环里空转几百万次才等到一个字符。这就像你点了个外卖,然后站在门口一直盯着猫眼等骑手,啥也干不了。CPU和I/O设备是串行工作的,效率极低。

但这种方式也不是一无是处。它的硬件结构最简单,不需要额外的控制器,一根I/O指令就能搞定。所以在一些极低端的嵌入式场景里,至今还能看到它的影子。只是在408考试里,它主要作为对比的起点出现。

2.2 中断方式:CPU终于能“分身”了

中断方式的出现是一次巨大的进步。它的核心思想是:CPU启动I/O设备后不用傻等,直接去干别的事。等I/O设备把数据准备好了,主动给CPU发一个中断信号,CPU收到信号后暂停当前的工作,转去执行中断服务程序,把数据读进来。

这就好比你点了外卖之后去干自己的事,骑手到了会打电话给你,你再下楼拿。CPU的利用率一下子就上去了。

但中断方式也有它的瓶颈。每次传送一个数据(比如一个字节或一个字),都要经历“中断请求→中断响应→保护现场→执行中断服务程序→恢复现场→返回”这一整套流程。这套流程本身要执行很多条指令,开销不小。如果I/O设备的数据传输率很高,比如磁盘读一个扇区512字节,每个字节都中断一次,CPU光处理中断就忙不过来了,真正干正事的时间反而被挤没了。

所以中断方式适合的是低速、少量数据的场景,比如键盘、鼠标。一旦遇到高速、大批量的数据传输,中断方式就力不从心了。

2.3 DMA方式:让数据自己“跑”起来

DMA,全称Direct Memory Access,直接存储器访问。它的核心思路是:既然CPU在数据搬运这件事上只是个“二传手”,那干脆把这个活交给一个专门的硬件——DMA控制器(DMAC)来干。CPU只需要告诉DMAC:从哪个设备读、写到内存的哪个位置、传多少个字节、传完了告诉我一声。剩下的搬运工作DMAC自己完成,CPU该干嘛干嘛去。

这个逻辑就像你不再自己下楼拿外卖,而是雇了一个跑腿小哥。你只需要告诉他取餐码和你的地址,他就帮你把外卖送到门口,送到了再通知你一声。你全程不用离开工位。

DMA方式的关键优势在于:数据传送不经过CPU,直接在I/O设备和内存之间进行。CPU只在传送开始前和结束后介入,中间过程完全不参与。这就把CPU从繁重的数据搬运中彻底解放出来了。

三种方式的对比可以用一个表格来直观呈现:

对比维度程序查询方式中断方式DMA方式
CPU参与程度全程参与,忙等每个数据都参与仅首尾参与
数据传送路径设备→CPU→内存设备→CPU→内存设备→内存(直接)
CPU利用率极低中等高
适用场景极低速设备低速、少量数据高速、大批量数据
硬件复杂度最低中等最高
传输单位字/字节字/字节数据块

这张表在408选择题里出现的频率极高,尤其是“数据传送路径”这一行,经常拿来出干扰项。记住一个核心区别:只有DMA方式的数据不经过CPU寄存器。

3. DMA控制器的内部结构与工作机理

3.1 DMA控制器的核心组成部件

DMA控制器不是随便一块电路就能当的,它内部有几个关键部件,每个部件在408考试里都可能单独出题。

内存地址寄存器(AR):存放数据要读写的内存起始地址。传送过程中每传一个数据,这个寄存器的值会自动加一(或减一),指向下一个内存单元。你可以把它理解成一个自动前进的“书签”。

字计数器(WC):记录还剩多少个数据没传。每传一个数据自动减一,减到零时表示传送完毕,向CPU发出中断请求。这个计数器决定了传送的数据块大小。

数据缓冲寄存器(DR):暂时存放每次传送的数据。从设备读来的数据先放在这里,再写到内存;或者从内存读出的数据先放在这里,再送到设备。

设备地址寄存器(DAR):存放I/O设备的地址,用来选中要通信的设备。

控制/状态逻辑:负责解析CPU发来的控制命令(读/写、传送方向等),管理DMA的请求和应答时序,以及产生中断信号。

中断机构:当字计数器减到零时,向CPU发出DMA结束中断。

这些部件协同工作的过程,就是DMA传送的全过程。408考试里经常考“DMA控制器中有哪些寄存器”或者“字计数器的作用是什么”,属于送分题,但前提是你得记住。

3.2 DMA的三种数据传送方式

DMA控制器和CPU都要访问内存,这就产生了一个资源竞争问题:内存同一时刻只能被一个部件访问。怎么协调?有三种经典方案。

停止CPU访存方式。当DMA控制器要传送数据时,它向CPU发出一个“总线请求”信号(HOLD),CPU收到后在当前总线周期结束后让出总线控制权(发出HLDA信号),DMA控制器接管总线,完成一个数据传送后再把总线还给CPU。在DMA传送期间,CPU完全不能访问内存。

这种方式控制简单,但CPU在DMA传送期间基本处于“停机”状态。如果DMA传送的数据块很大,CPU的性能损失就很可观。它适合数据传输率极高的场景,比如高速磁盘。

周期挪用方式,也叫周期窃取。这种方式下,DMA控制器每次需要传送数据时,只“偷”一个或几个内存周期。具体来说,DMA控制器向CPU申请总线,CPU让出一个总线周期给DMA用,用完立刻还回去。CPU的指令执行可能会被短暂暂停一两个周期,但整体影响很小。

这种方式的关键在于:DMA控制器每次只占用一个内存周期,不会长时间霸占总线。它适合大多数中高速I/O设备。408考试里考得最多的就是这种方式,因为它涉及“周期挪用”这个概念的理解和计算。

交替访问方式。这种方式下,内存的访问时间被分成两个交替的时段,一半给CPU用,一半给DMA用。比如内存周期为1微秒,前500纳秒CPU访存,后500纳秒DMA访存。双方各用各的,互不干扰。

这种方式不需要总线请求和应答,控制简单,但要求内存的存取速度足够快,能在一个内存周期内完成两次访问。实际上这种方式用得不多,但408选择题里偶尔会考它的特点。

三种方式的对比:

传送方式CPU是否暂停适用场景408考查频率
停止CPU访存完全暂停高速设备、大数据块中等
周期挪用短暂暂停1-2个周期中高速设备最高
交替访问不暂停内存速度足够快较低

3.3 DMA传送的完整流程

把上面的部件和方式串起来,一次完整的DMA传送流程是这样的:

  1. CPU执行初始化程序,设置DMA控制器的内存地址寄存器、字计数器、设备地址寄存器和传送方向。
  2. CPU启动I/O设备,然后继续执行其他程序。
  3. I/O设备准备好一个数据后,向DMA控制器发出DMA请求。
  4. DMA控制器向CPU发出总线请求(HOLD信号)。
  5. CPU在当前总线周期结束后,发出总线响应信号(HLDA),让出总线控制权。
  6. DMA控制器接管总线,在I/O设备和内存之间直接传送一个数据。
  7. 内存地址寄存器加一(或减一),字计数器减一。
  8. 判断字计数器是否为零。如果不为零,回到步骤3继续传送下一个数据。
  9. 如果字计数器为零,DMA控制器向CPU发出中断请求,表示传送完毕。
  10. CPU响应中断,执行中断服务程序,做传送结束后的处理工作。

这个流程在408大题里经常以“描述DMA传送过程”的形式出现,或者结合时序图来考。关键节点是第4、5步的总线请求与响应,以及第9步的中断请求。

4. 408考试中DMA相关题型的解题框架

4.1 周期挪用方式下的时间计算

这是408最常考的DMA计算题型。典型题目长这样:某磁盘的传输率为4MB/s,内存的存取周期为500ns,采用周期挪用方式进行DMA传送。问DMA控制器占用内存带宽的百分比是多少?

解题思路:磁盘每秒传4MB,也就是4×10^6字节。每个字节需要挪用一次内存周期,每次500ns。所以DMA每秒需要的内存时间为4×10^6 × 500×10^-9 = 2秒。也就是说,DMA每秒需要占用2秒的内存时间,这显然超过了1秒,说明内存带宽不够,磁盘传输率受限于内存。

如果题目改成磁盘传输率为1MB/s,那么DMA每秒需要的内存时间为1×10^6 × 500×10^-9 = 0.5秒,占用内存带宽的50%。

这类题的核心公式是:DMA占用内存带宽百分比 = 数据传输率 × 内存存取周期 × 100%。

注意单位换算,MB和字节、纳秒和秒之间的转换是高频出错点。我见过太多人把4MB/s当成4×2^20字节/秒来算,结果跟标准答案差一截。408考试里通常用10^6来算,但具体要看题目给的条件。

4.2 DMA传送时间与CPU执行时间的关系

另一类常考题是:在DMA传送一个数据块的过程中,CPU能执行多少条指令?

比如:某DMA控制器采用周期挪用方式,每次挪用1个内存周期(500ns),传送1000个字节。CPU的主频为500MHz,每条指令平均需要2个时钟周期。问在DMA传送期间CPU能执行多少条指令?

解题:DMA传送1000个字节,每个字节挪用1个内存周期,总共挪用1000 × 500ns = 500微秒。但CPU并不是在这500微秒里完全停机,只是在每个内存周期被挪用的时候暂停一下。实际上,CPU执行指令和DMA挪用周期是交替进行的。

更准确的计算方式是:CPU每个时钟周期为1/500MHz = 2ns。每条指令2个时钟周期,即4ns。在DMA传送的500微秒内,CPU理论上可以执行500×10^-6 / 4×10^-9 = 125000条指令。但每次DMA挪用内存周期时,CPU会暂停一个内存周期(500ns),1000次挪用总共暂停500微秒。所以CPU实际可执行的时间是总时间减去暂停时间。

这里有个容易混淆的点:DMA挪用周期时,CPU暂停的是一个内存周期,而不是一个指令周期。如果CPU正在执行的指令需要访问内存,那么这条指令会被拉长。如果CPU正在执行的指令不需要访问内存(比如寄存器运算),那么DMA挪用周期对它的影响很小。

408考试里通常简化处理,直接认为DMA挪用周期会导致CPU暂停相应的时间。具体计算时,先算DMA传送的总时间,再算CPU在这段时间内能执行的指令数,最后减去因DMA挪用而损失的时间。

4.3 DMA与中断的优先级问题

408选择题里经常考:DMA请求和中断请求同时发生时,CPU先响应哪个?

答案是DMA请求优先。原因很简单:DMA请求对应的是高速设备的数据传送,如果不及时响应,数据可能丢失。而中断请求通常对应的是低速设备的服务请求,晚一点处理问题不大。另外,DMA请求的是总线控制权,中断请求的是CPU的执行权,两者不在一个层面上,DMA请求的实时性要求更高。

这个知识点在唐朔飞教材里有明确说明,白中英教材也有类似表述。考试里经常把它包装成一个场景题,比如“磁盘和键盘同时发出请求,CPU先处理哪个”,答案永远是磁盘(DMA)优先。

4.4 DMA方式与中断方式的对比分析题

这类题通常以简答题或选择题的形式出现,要求你从多个维度对比DMA和中断。除了前面表格里列的那些维度,还有几个容易被忽略的点:

响应时间:中断方式在每条指令执行结束后检查中断请求,响应时间受指令长度影响。DMA方式在每个总线周期结束后就可以响应,响应更快。

数据传送方向:中断方式的数据传送方向由CPU控制,DMA方式的数据传送方向由DMA控制器控制。

优先级:DMA请求的优先级高于中断请求。

对CPU的依赖:中断方式完全依赖CPU完成数据传送,DMA方式不依赖CPU。

这些对比点在408大题里经常要求“至少列出三点区别”,把上面这些记住,随便挑三点都能拿分。

5. 从教材到实战:DMA在嵌入式开发中的真实面目

5.1 STM32的DMA配置:教材知识怎么落地

如果你学过408的DMA,再去看STM32的DMA配置,会发现很多概念是相通的。STM32的DMA控制器有多个通道,每个通道可以配置源地址、目的地址、传输数据量、传输方向等参数。这些参数对应的就是DMA控制器里的设备地址寄存器、内存地址寄存器、字计数器和控制逻辑。

以STM32的串口DMA接收为例,配置步骤大致如下:

// 使能DMA时钟 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); // 配置DMA通道 DMA_InitTypeDef DMA_InitStructure; DMA_InitStructure.DMA_Channel = DMA_Channel_4; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR; // 设备地址 DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)rxBuffer; // 内存地址 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; // 传送方向 DMA_InitStructure.DMA_BufferSize = BUFFER_SIZE; // 字计数器 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 设备地址不变 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // 内存地址递增 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; // 普通模式 DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_Init(DMA1_Channel4, &DMA_InitStructure); // 使能DMA DMA_Cmd(DMA1_Channel4, ENABLE);

这段代码里的每个配置项,都能在408教材里找到对应的概念。DMA_PeripheralBaseAddr对应设备地址寄存器,DMA_Memory0BaseAddr对应内存地址寄存器,DMA_BufferSize对应字计数器,DMA_DIR对应传送方向控制。你在教材上学的是原理,在STM32上用的是寄存器配置,但底层逻辑完全一致。

5.2 DMA缓冲区对齐:一个教材不会讲的坑

在实际嵌入式开发中,DMA对缓冲区的地址对齐有要求。很多STM32的DMA控制器要求源地址和目的地址按照数据宽度对齐。比如传输半字(16位)时,地址必须是2字节对齐;传输字(32位)时,地址必须是4字节对齐。如果不对齐,DMA可能传输错误数据,甚至触发硬件异常。

这个问题在408教材里不会讲,因为教材关注的是原理而不是具体芯片的实现。但如果你做嵌入式开发,这就是必踩的坑。我当初调串口DMA接收时就遇到过:定义了一个uint8_t rxBuffer[64],地址是奇数的,结果DMA传回来的数据全是乱的。后来改成__attribute__((aligned(4)))强制4字节对齐,问题立刻解决。

5.3 DMA传输完成中断:和408中断概念的呼应

STM32的DMA支持传输完成中断、半传输中断和传输错误中断。传输完成中断对应的就是408教材里说的“字计数器减到零时向CPU发出中断请求”。在代码里,你需要配置NVIC使能对应的中断通道,然后写中断服务函数:

void DMA1_Channel4_IRQHandler(void) { if(DMA_GetITStatus(DMA1_IT_TC4)) { DMA_ClearITPendingBit(DMA1_IT_TC4); // 处理传输完成后的逻辑 processReceivedData(rxBuffer, BUFFER_SIZE); } }

这段代码的逻辑跟408教材里描述的DMA传送结束中断处理完全一致:DMA控制器在传送完毕后发出中断,CPU响应中断后执行中断服务程序,做后续处理。你在教材上学的中断响应流程、中断服务程序的概念,在这里全都能对上号。

6. DMA学习中的常见误区与排查技巧

6.1 误区一:DMA传送完全不经过CPU

这是最常见的误解。很多人以为DMA方式下CPU完全不参与数据传送,这是不对的。准确的说法是:DMA方式下数据传送不经过CPU的寄存器,但CPU仍然要参与传送的初始化和结束处理。CPU要设置DMA控制器的各个寄存器,要在传送结束后响应中断做后续处理。只是在数据传送的过程中,CPU不介入。

408选择题里经常用“DMA方式下CPU不参与任何操作”作为干扰项,记住这是错的。

6.2 误区二:DMA的优先级总是高于中断

这个说法在大多数情况下成立,但不是绝对的。DMA请求的优先级高于中断请求,这是由硬件优先级仲裁机制决定的。但在某些系统中,如果中断请求对应的是紧急故障处理(比如电源故障),可能会被赋予更高的优先级。不过在408考试的语境下,你只需要记住:DMA请求优先于中断请求。

6.3 误区三:周期挪用方式下CPU完全不停

周期挪用方式下,DMA控制器每次只挪用一两个内存周期,CPU在这期间确实会暂停。暂停的时间取决于DMA挪用了多少个周期。如果DMA连续挪用多个周期,CPU就会连续暂停多个周期。所以“CPU完全不停”是错的,只是暂停时间很短而已。

6.4 常见问题速查表

问题现象可能原因排查思路
DMA传送的数据错位地址未对齐检查源地址和目的地址是否按数据宽度对齐
DMA传送不完整字计数器设置错误核对BufferSize是否与实际数据量一致
DMA传送完成后无中断中断未使能检查NVIC配置和DMA中断使能位
DMA传送速度低于预期通道优先级低调整DMA通道优先级或检查总线仲裁
DMA与CPU访问内存冲突未使用周期挪用确认DMA传送方式配置是否正确

6.5 一个实用的记忆口诀

408考试前,我用一个简单的口诀记DMA的核心考点:“一器三方式,两请一中断”。一器指的是DMA控制器,三方式指的是停止CPU访存、周期挪用、交替访问三种传送方式,两请指的是DMA请求和总线请求,一中断指的是传送结束中断。把这个口诀展开,基本能覆盖DMA选择题的所有考点。

7. 从408到工程实践:DMA思维的迁移价值

学DMA不只是为了考试。DMA背后的核心思想——“把重复性的数据搬运工作交给专用硬件,让通用处理器专注于计算和逻辑”——在现代计算机体系结构中无处不在。GPU的显存拷贝、网络卡的数据包收发、NVMe SSD的数据传输,底层都是DMA在支撑。你理解了DMA的原理,再去看这些技术,会发现它们只是DMA思想在不同场景下的具体实现。

对于考研的同学来说,DMA这一节的知识点不算多,但考法很灵活。关键是把三种传送方式的区别、DMA控制器的组成、周期挪用的计算这三块吃透。对于做嵌入式的工程师来说,STM32的DMA配置是基本功,但很多人只会抄配置代码,不理解每个参数的含义。把408教材里的DMA原理和实际配置对照着看,你会发现那些寄存器配置项突然就有了意义。

我在实际调试DMA时踩过最深的坑是缓冲区对齐问题,当时查了两天才定位到。后来养成了一个习惯:凡是DMA要访问的缓冲区,一律用__attribute__((aligned(4)))强制对齐,不管当前传输的数据宽度是多少。这个习惯帮我省了很多调试时间。如果你也在做嵌入式开发,建议把这个习惯刻进肌肉记忆里。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询