☰
计算机组成原理DMA深度解析:从408真题到嵌入式实战
2026/9/30 0:01:27 网站建设 项目流程

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

如果你正在啃计算机组成原理,尤其是唐朔飞那本教材或者王道复习指导,翻到I/O那一章的时候,大概率会被一堆控制方式搞得头大——程序查询、程序中断、DMA、通道,名字听着都差不多,但考试偏偏就爱在这几个地方挖坑。2024年408第45题考的就是DMA相关的计算,很多人考完出来一查答案才发现,原来自己把传输周期和存取周期搞混了。

DMA,全称Direct Memory Access,直接存储器访问。说白了,它解决的是一个非常朴素的问题:当外设需要和主存之间搬运大量数据的时候,能不能别让CPU在那儿一个字节一个字节地当中转站?你想想,如果CPU是一个公司的CEO,程序查询方式就是CEO亲自去前台等快递,程序中断方式就是CEO留个电话让快递到了叫他,而DMA方式,相当于CEO直接雇了一个专职收发员,快递来了收发员自己处理,CEO该干嘛干嘛,只在收发员搬完一整批货之后才需要签个字确认一下。

这个“专职收发员”就是DMA控制器,简称DMAC。它在硬件层面接管了总线控制权,让数据在外设和主存之间直接传输,不需要CPU逐字干预。对于考研408来说,DMA的考点集中在几个方面:DMA控制器的组成、三种传送方式(停止CPU访存、周期挪用、交替访存)、传输过程的时间计算、以及DMA与中断方式的对比。这些内容在选择题和大题里都出现过,尤其是传输时间的计算,几乎每隔几年就要考一次。

我当年复习这一块的时候,最大的感受是:光看文字描述很容易觉得自己懂了,但一做题就露馅。因为DMA涉及总线、存储器、I/O接口三方的协调,任何一个环节的时序没搞清楚,计算就会出错。所以这篇文章我打算从底层逻辑出发,把DMA的来龙去脉、硬件结构、工作流程、三种传送方式的取舍、以及考试中最容易踩的坑,全部掰开揉碎讲一遍。不管你是正在准备408考研,还是学嵌入式开发时想搞明白STM32里的DMA到底怎么回事,这篇文章应该都能帮你把这块知识彻底打通。

2. DMA的核心原理与硬件结构拆解

2.1 为什么需要DMA:CPU当搬运工的代价

要理解DMA的价值,得先看看没有DMA的时候,数据是怎么搬的。假设你要从磁盘读1MB的数据到内存,如果用程序查询方式,CPU需要不断读取I/O接口的状态寄存器,判断数据是否准备好,准备好了就读一个字节或一个字到CPU寄存器,再写到内存。这个过程里,CPU绝大部分时间都花在等待和搬运上,真正做计算的时间被严重压缩。

程序中断方式稍微好一点,CPU不用一直轮询了,外设准备好数据后发中断,CPU响应中断,执行中断服务程序来搬运数据。但问题在于,每搬运一个字节或一个字,都要经历一次中断响应、保护现场、执行服务程序、恢复现场的过程。对于高速外设(比如磁盘、网卡、显卡)来说,这个开销太大了。你算算,如果每次中断能搬4个字节,1MB数据需要中断26万多次,每次中断就算只花几十个时钟周期,加起来也是天文数字。

DMA的思路完全不同。它在硬件层面增加了一个专门的控制器,这个控制器可以直接访问主存,也可以控制外设和主存之间的数据通路。CPU只需要在传输开始前告诉DMAC:从哪个外设读、写到内存的什么位置、传多少数据、传完之后要不要通知我。剩下的搬运工作,DMAC自己完成。CPU在此期间可以继续执行其他指令,只在DMA传输结束时才需要处理一次中断。

这里有一个关键点需要理解:DMA传输过程中,DMAC需要占用总线。也就是说,CPU和DMAC不能同时访问主存。这就引出了后面要讲的三种传送方式,本质上就是在解决“CPU和DMAC怎么分享总线”这个问题。

2.2 DMA控制器的内部组成:不只是个搬运工

DMAC不是一个简单的数据通道,它内部有一组寄存器来管理传输过程。标准的DMAC通常包含以下几个关键部件:

主存地址寄存器(AR):存放当前要访问的主存地址。每传输一个数据,这个地址会自动加1或减1,指向下一个存储单元。初始值由CPU在传输开始前写入。

字计数器(WC):记录还剩多少数据需要传输。每传输一个数据,计数器减1。当计数器减到0时,表示传输完成,DMAC会向CPU发出中断请求。初始值也是CPU预先设置的。

数据缓冲寄存器(DR):暂时存放正在传输的数据。对于输入(外设到主存),数据先从外设读到DR,再写到主存;对于输出(主存到外设),数据先从主存读到DR,再写到外设。

控制/状态逻辑:负责协调整个传输过程,包括总线请求信号的发出、总线响应信号的接收、传输方向的设置、以及中断请求的生成。

中断机构:当字计数器归零时,向CPU发出中断请求,通知传输完成。

除了这些内部寄存器,DMAC还需要与总线连接的接口,包括数据线、地址线和控制线。在DMA传输期间,DMAC会接管地址总线和数据总线,成为总线的主控设备。

这里有一个容易混淆的点:DMAC内部的寄存器和CPU的寄存器是两套独立的硬件。CPU通过I/O指令来读写DMAC的寄存器,这个过程和读写普通I/O接口的寄存器没有本质区别。但一旦DMA传输启动,DMAC就不再依赖CPU的指令来工作了,它按照预设的参数自主运行。

2.3 DMA与中断的本质区别:从“谁来搬”到“怎么搬”

很多人学到这里会把DMA和中断搞混,因为两者都涉及“CPU暂停当前工作去处理某件事”。但它们的本质区别在于:

中断方式是程序切换,CPU需要执行中断服务程序来完成数据搬运,数据要经过CPU寄存器。DMA方式是硬件切换,数据不经过CPU,直接在内存和外设之间传输,CPU只是最后处理一下“传完了”这个通知。

打个比方:中断方式像是你正在写代码,快递员打电话让你下楼取快递,你只能停下手里的活,下楼、签字、把快递搬回工位,然后再重新进入写代码的状态。DMA方式像是你告诉前台:“今天会有快递来,帮我放到我工位上。”快递到了前台直接处理,你完全不受打扰,只在所有快递都放好之后收到一条消息:“都放好了。”

从数据流向来看,中断方式的数据通路是:外设→CPU寄存器→主存。DMA方式的数据通路是:外设→主存(或主存→外设),CPU完全不参与数据搬运。

从响应时机来看,中断方式在每个数据准备好后都可能触发中断,响应频率高;DMA方式在一整块数据传完之后才触发一次中断,响应频率低。

从优先级来看,DMA请求的优先级通常高于中断请求。因为DMA传输如果被长时间打断,高速外设的数据可能会丢失。而中断请求可以稍微延迟处理,不会导致数据丢失。

3. 三种DMA传送方式:停止CPU访存、周期挪用与交替访存

3.1 停止CPU访存方式:简单粗暴但效率低

这是最容易理解的一种方式。当DMAC需要传输数据时,它向CPU发出总线请求信号(HOLD)。CPU收到信号后,在当前总线周期结束后,让出总线的控制权,将总线置为高阻态。DMAC获得总线控制权后,开始进行数据传送。一整块数据全部传完之后,DMAC释放总线,CPU重新获得总线控制权,继续执行程序。

这种方式的优点是控制简单,DMAC的硬件实现不复杂。但缺点也很明显:在DMA传输期间,CPU完全无法访问主存。如果传输的数据量很大,CPU就会被“冻结”很长时间。比如传输1MB数据,假设每个总线周期传4个字节,需要26万多个总线周期,这段时间CPU什么都干不了。

在实际系统中,这种方式通常用于数据传输率极高的场景,比如硬盘的整块数据读写。因为如果不用这种方式,CPU频繁地被DMA请求打断,反而效率更低。但对于低速外设,这种方式就很不划算了。

考试中如果考到这种方式,通常会让你计算CPU被“阻塞”的时间比例。计算方法是:DMA传输占用的总线周期数除以总时间。比如CPU主频100MHz,总线周期50ns,传输1MB数据每次传4字节,那么DMA占用总线的时间是(1MB/4B)×50ns=13.1ms。如果这1MB数据是连续传输的,CPU在这13.1ms内完全无法访存。

3.2 周期挪用方式:偷一个周期就走

周期挪用,也叫周期窃取,是目前最常用的一种DMA传送方式。它的核心思想是:DMAC不需要一直占用总线,它只在需要传输一个数据的时候,向CPU“借”一个总线周期。借完之后,CPU继续使用总线。

具体来说,当外设准备好一个数据时,DMAC向CPU发出总线请求。CPU在当前总线周期结束后,响应请求,让出一个总线周期给DMAC。DMAC利用这个周期完成一次数据传送(从外设读到主存,或从主存写到外设),然后立即释放总线。CPU继续执行下一条指令。

这种方式的好处是CPU和DMAC可以交替使用总线,CPU不会长时间被阻塞。但代价是DMAC的硬件控制逻辑更复杂,需要精确的时序协调。

这里有一个关键的计算点:周期挪用方式下,DMA传输对CPU的影响取决于DMA请求的频率。如果外设速度很快,DMA请求很频繁,CPU可能需要频繁让出总线周期,实际可用带宽会下降。如果外设速度较慢,DMA请求间隔较长,CPU几乎感觉不到影响。

考试中常考的一个场景是:CPU执行一条指令需要若干个机器周期,每个机器周期包含若干个时钟周期。DMA请求在每个机器周期结束时被采样。如果DMA请求频繁到每个机器周期都要挪用一次,那么CPU的执行速度会明显下降。

3.3 交替访存方式:各走各的路

交替访存方式是一种更精细的方案。它把每个存储周期分成两个时间片,一个给CPU用,一个给DMAC用。比如存储周期是1μs,前500ns归CPU,后500ns归DMAC。两者交替访问主存,互不干扰。

这种方式的优点是CPU和DMAC都不需要等待对方,各自按照自己的节奏访问主存。但缺点也很明显:首先,存储器的访问速度必须足够快,能够在一个存储周期内完成两次访问;其次,CPU和DMAC的访存频率必须匹配,如果一方不需要访问,另一方也不能占用它的时间片,会造成浪费。

这种方式在实际系统中用得不多,因为对存储器硬件的要求太高。但在考试中,它是一个重要的概念考点,经常出现在选择题里,让你判断某种场景下应该采用哪种传送方式。

3.4 三种方式的对比与选型逻辑

对比维度停止CPU访存周期挪用交替访存
总线占用DMA期间独占按需借用单个周期固定时间片交替
CPU影响完全阻塞轻微影响几乎无影响
硬件复杂度低中高
适用场景高速块传输通用场景高速缓存类存储器
传输效率高(连续传输)中高(并行)

选型的核心逻辑是:看外设的速度和传输的连续性。如果外设速度极快且需要连续传输大块数据,停止CPU访存方式反而效率最高,因为减少了总线仲裁的开销。如果外设速度中等,周期挪用方式最灵活。交替访存方式则适用于对实时性要求极高的场景,但硬件成本也最高。

4. DMA传输的完整流程与实操计算

4.1 从CPU初始化到传输结束:一步步走完DMA流程

DMA传输的完整流程可以分为三个阶段:初始化阶段、数据传输阶段、结束处理阶段。

初始化阶段:CPU通过I/O指令向DMAC写入传输参数。具体包括:主存起始地址写入AR,传输字数写入WC,传输方向(读/写)写入控制寄存器,外设地址写入设备寄存器。然后CPU启动DMAC,DMAC开始等待外设的数据准备好信号。

数据传输阶段:以外设到主存为例。外设准备好一个数据后,向DMAC发出请求信号。DMAC向CPU发出总线请求(HOLD)。CPU在当前总线周期结束后,发出总线响应(HLDA),让出总线控制权。DMAC获得总线后,从外设读取数据放入DR,然后将DR中的数据写入主存AR指向的单元。AR加1,WC减1。DMAC释放总线,CPU继续执行。重复这个过程,直到WC减到0。

结束处理阶段:当WC归零时,DMAC向CPU发出中断请求。CPU响应中断,执行中断服务程序,检查传输是否成功,然后进行后续处理(比如通知应用程序数据已就绪)。

这里有一个细节容易被忽略:在周期挪用方式下,DMAC每次传输一个数据都需要经历“请求-响应-传输-释放”的过程。而在停止CPU访存方式下,DMAC获得总线后可以连续传输多个数据,直到整块数据传完才释放总线。

4.2 传输时间计算:408真题的经典套路

DMA传输时间的计算是408的高频考点。我们来看一个典型的计算场景:

假设CPU主频为500MHz,CPI为4(即每条指令平均需要4个时钟周期),总线宽度为32位,总线周期为2个时钟周期。现在要用DMA方式从磁盘读取4KB数据到内存,磁盘的数据传输率为20MB/s。问:在周期挪用方式下,DMA传输占用了CPU多少时间?

解题思路:首先计算DMA需要传输的次数。总线宽度32位=4字节,4KB数据需要传输4096/4=1024次。每次传输需要一个总线周期,总线周期为2个时钟周期,所以DMA占用总线的时间为1024×2=2048个时钟周期。CPU主频500MHz,时钟周期为2ns,所以DMA占用总线的时间为2048×2ns=4096ns=4.096μs。

但这里要注意,题目问的是“DMA传输占用了CPU多少时间”。在周期挪用方式下,CPU让出的是总线周期,而不是时钟周期。CPU在这段时间内无法访存,但可能仍在执行不需要访存的指令(比如寄存器运算)。如果题目简化处理,认为CPU完全被阻塞,那么答案就是4.096μs。

如果题目进一步问“CPU在这段时间内本来可以执行多少条指令”,那么需要计算CPU在这4.096μs内原本可以执行的指令数。CPU执行一条指令需要4个时钟周期=8ns,4.096μs内可以执行4096/8=512条指令。也就是说,DMA传输让CPU少执行了512条指令。

这类题目的关键在于区分“总线周期”和“时钟周期”,以及“DMA占用总线的时间”和“CPU被阻塞的时间”。很多考生出错就是因为把总线周期当成了时钟周期,或者忽略了CPI的影响。

4.3 一个完整的计算实例:从参数设置到结果验证

我们来看一个更完整的例子,模拟408大题的出题风格:

某计算机系统采用DMA方式从外设读取数据到主存。外设的数据传输率为2MB/s,主存的数据传输率为50MB/s。DMA控制器采用周期挪用方式,每次传输4字节。CPU主频为100MHz,CPI为5。问:当外设连续传输10MB数据时,DMA传输对CPU执行指令的影响有多大?

第一步,计算DMA传输的总次数:10MB/4B=2.5M次。

第二步,计算每次DMA传输占用的总线周期。主存数据传输率50MB/s,传输4字节需要4B/50MB/s=80ns。但DMA传输还需要考虑外设的准备时间。外设数据传输率2MB/s,传输4字节需要4B/2MB/s=2μs。所以DMA请求的间隔是2μs,每次占用总线80ns。

第三步,计算DMA占用总线的总时间:2.5M×80ns=200ms。

第四步,计算CPU在这200ms内原本可以执行的指令数。CPU主频100MHz,时钟周期10ns,CPI=5,所以每条指令需要50ns。200ms/50ns=4M条指令。

也就是说,DMA传输让CPU少执行了约400万条指令。但注意,这200ms是分散在2.5M次传输中的,每次只占用80ns。在周期挪用方式下,CPU在这80ns内无法访存,但可能仍在执行其他操作。如果题目简化处理,认为CPU完全被阻塞,那么影响就是400万条指令。

这个计算过程的关键在于:先算DMA传输的总时间,再算CPU在这段时间内原本能执行多少指令。两个时间维度的转换是考生最容易出错的地方。

5. 常见问题与排查技巧实录

5.1 DMA与中断的优先级冲突怎么处理

在实际系统中,DMA请求和中断请求可能同时发生。这时候需要一套优先级仲裁机制。通常的原则是:DMA请求优先于中断请求。因为DMA传输如果被延迟,高速外设的数据可能会丢失(比如磁盘的扇区数据如果不能及时读走,就会被下一圈的数据覆盖)。而中断请求延迟几个周期通常不会导致数据丢失。

但在某些系统中,如果中断请求来自一个实时性要求极高的外设(比如故障检测),可能会设置更高的优先级。这取决于具体的系统设计。

考试中如果考到优先级问题,通常的答案是:DMA请求优先级高于中断请求。但要注意题目中是否有特殊说明。

5.2 周期挪用方式下CPU访存冲突的排查

在周期挪用方式下,如果DMA请求非常频繁,CPU可能会频繁让出总线周期,导致性能下降。排查这个问题的思路是:

首先,计算DMA请求的频率。如果DMA请求间隔小于CPU的一个总线周期,那么CPU几乎无法完成一次完整的访存操作。这时候需要考虑改用停止CPU访存方式,或者提高总线速度。

其次,检查DMA传输的数据块大小。如果每次DMA传输的数据量很小,但请求很频繁,总线仲裁的开销会很大。可以考虑增大DMA传输的块大小,减少请求次数。

最后,检查存储器的访问速度。如果存储器速度不够快,DMA和CPU的访存请求会互相等待,进一步降低效率。

5.3 408考试中DMA相关题目的常见陷阱

陷阱一:混淆总线周期和时钟周期。题目中可能给出总线周期为2个时钟周期,但考生直接用时时钟周期计算,导致结果差一倍。

陷阱二:忽略CPI的影响。题目问“CPU少执行了多少条指令”,需要用到CPI来计算每条指令的时间,不能直接用时钟周期数除以1。

陷阱三:混淆传输次数和传输字节数。总线宽度32位,传输4KB数据需要1024次,而不是4096次。这个错误非常常见。

陷阱四:忽略DMA传输的启动和结束开销。有些题目会考虑DMA初始化的时间,以及传输结束后中断处理的时间。如果题目明确给出了这些参数,需要加上。

陷阱五:周期挪用方式下,DMA占用总线的时间不等于CPU被阻塞的时间。CPU可能在这段时间内执行不需要访存的指令。如果题目没有特别说明,通常简化处理为完全阻塞。

5.4 从考试到实战:STM32中的DMA配置避坑

如果你学完408的DMA之后去玩STM32,会发现实际配置DMA时有几个坑和考试完全不一样。

第一个坑:STM32的DMA有多个通道,每个通道对应不同的外设请求。配置时需要查手册确认哪个外设对应哪个DMA通道,不能随便选。比如STM32F103的USART1_TX对应DMA1_Channel4,USART1_RX对应DMA1_Channel5。

第二个坑:DMA传输模式有单次模式和循环模式。单次模式传完指定数量就停止,循环模式会自动重装载计数器。串口接收通常用循环模式,串口发送通常用单次模式。

第三个坑:数据对齐方式。如果外设数据宽度是8位,内存数据宽度是32位,需要配置数据对齐方式,否则会出现数据错位。STM32的DMA支持外设和内存数据宽度独立配置,但要注意对齐规则。

第四个坑:DMA传输完成中断和半传输中断。传输完成中断在计数器归零时触发,半传输中断在传输了一半数据时触发。对于大数据块传输,可以用半传输中断来实现双缓冲,提高效率。

这些实战经验和408考试的内容互为补充。考试考的是原理和计算,实战考的是配置和调试。两者结合起来,才能真正把DMA这块知识吃透。

6. 从408到嵌入式:DMA知识的延伸与串联

6.1 DMA在串口通信中的应用

串口通信是DMA最典型的应用场景之一。以STM32为例,如果不使用DMA,串口发送数据需要CPU不断查询发送寄存器是否为空,然后写入数据。对于波特率115200的串口,每发送一个字节需要约87μs,如果发送1KB数据,CPU需要花费约87ms在轮询上。

使用DMA之后,CPU只需要把数据缓冲区的首地址和长度告诉DMA控制器,DMA会自动把数据从内存搬到串口发送寄存器。CPU在此期间可以处理其他任务。发送完成后,DMA触发中断,CPU处理后续逻辑。

这里有一个细节:串口的DMA发送通常配置为“内存到外设”模式,外设地址固定为发送数据寄存器,内存地址递增。传输完成后,需要清除DMA标志位,否则下次传输会出错。

6.2 DMA在ADC多通道采集中的应用

ADC多通道采集是另一个DMA的经典应用。如果不用DMA,CPU需要在每次ADC转换完成后读取转换结果,然后切换到下一个通道。对于高速采样,CPU根本来不及处理。

使用DMA之后,ADC的转换结果会自动搬运到内存数组中。CPU只需要在DMA传输完成后处理整个数组。STM32的ADC支持DMA循环模式,可以实现连续采集而不需要CPU干预。

配置时需要注意:ADC的DMA请求需要在ADC配置中使能,DMA的传输方向是“外设到内存”,外设地址固定为ADC数据寄存器,内存地址递增,数据宽度根据ADC分辨率设置(12位ADC通常用16位半字)。

6.3 DMA在SPI通信中的应用

SPI通信的全双工特性使得DMA的应用更加复杂。SPI发送和接收是同时进行的,所以需要两个DMA通道:一个用于发送(内存到SPI数据寄存器),一个用于接收(SPI数据寄存器到内存)。

配置时需要注意:SPI的DMA请求需要在SPI配置中使能,发送和接收分别使能。两个DMA通道需要协调工作,通常发送通道先启动,接收通道紧随其后。传输完成后,需要检查两个通道的状态,确保数据完整。

6.4 从考试到实战的知识迁移

408考试中的DMA知识是高度抽象的,它剥离了具体硬件的细节,只保留了最核心的原理和计算。而嵌入式实战中的DMA是具体的,它涉及寄存器配置、中断处理、时序调试等细节。

两者之间的关系是:考试知识帮你理解“为什么”,实战经验帮你掌握“怎么做”。如果你只学考试内容,配置DMA时可能会一头雾水,不知道为什么要有这么多寄存器。如果你只学实战配置,遇到DMA传输效率的问题时,可能不知道从原理层面去分析。

我个人的经验是:先把408的DMA原理吃透,理解三种传送方式的区别、传输时间的计算方法、以及DMA与中断的本质差异。然后再去玩STM32或其他嵌入式平台,把理论映射到具体的寄存器配置上。这样学下来,无论是考试还是做项目,都能游刃有余。

最后再分享一个小技巧:如果你在调试DMA时遇到数据传输不完整或数据错位的问题,先检查三个地方——数据宽度配置是否匹配、地址递增模式是否正确、传输完成标志是否清除。这三个地方是DMA配置中最容易出错的地方,排查顺序也应该是这个顺序。

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

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

立即咨询