☰
计算机组成原理DMA方式详解:从408考研到STM32实战
2026/9/28 1:43:23 网站建设 项目流程

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

如果你正在啃计算机组成原理,尤其是唐朔飞那本教材的课后题,大概率会在I/O系统这一章卡住。24年408那道45题考的就是DMA方式下CPU与I/O设备的信息传送控制,很多人看完题干的时序图直接懵了——明明CPU已经把总线让出去了,为什么还要算“挪用”了多少个存取周期?这背后其实藏着DMA最核心的设计哲学:数据传送不经过CPU,但总线控制权要“借”。

DMA,全称Direct Memory Access,直接存储器访问。它解决的是一个非常朴素的问题:当外设(比如磁盘、网卡、ADC采集模块)需要和主存之间搬运大批量数据时,如果还让CPU一条一条执行load/store指令来中转,那CPU基本上就废了,全耗在搬砖上了。DMA的思路是找一个专门的硬件控制器(DMAC),让它直接在主存和外设之间开一条数据通道,CPU只需要在开始前告诉DMAC“从哪搬到哪、搬多少、搬完告诉我”,然后就可以去干别的事了。

这篇文章面向的是正在准备408考研的同学,以及工作中需要理解STM32 DMA、Linux DMA、SPI DMA、串口DMA这些实际应用的开发者。我会从408考点的角度切入,把DMA的三种传送方式、总线占用机制、与中断方式的对比、以及实际配置中的关键参数全部拆开讲清楚。不管你是为了做题还是为了调通一个ADC多通道DMA采集,这篇文章都能让你少走弯路。

2. DMA方式的核心设计思路拆解

2.1 为什么中断方式还不够用

要理解DMA为什么被发明出来,得先看它的前辈——程序中断方式有什么毛病。中断方式下,外设每准备好一个数据单位(比如一个字节或一个字),就向CPU发一次中断请求。CPU响应中断后,执行中断服务程序,把数据从I/O接口读到CPU寄存器,再写到主存。整个过程CPU都在参与,每传一个字都要打断一次主程序。

我拿实际数字算一下你就知道有多离谱了。假设磁盘传输速率是4MB/s,每次中断处理开销(包括保存现场、恢复现场、执行服务程序)大约需要20微秒。那么每秒需要产生100万次中断(4MB/4B),光中断处理就要花掉20秒——CPU一秒都抽不出来干别的。这就是所谓的“中断风暴”,在高速外设场景下中断方式直接不可用。

DMA的解法很直接:既然CPU只是数据搬运的中转站,那就把这个中转站去掉。DMAC自己拥有地址总线和数据总线的控制能力,可以直接把外设数据写入主存,或者把主存数据读出送到外设。CPU只在传送开始前做初始化,传送结束后处理一次中断。中间过程CPU完全不参与。

2.2 DMA控制器的内部结构长什么样

DMAC不是随便一个芯片就能干的,它内部需要几个关键部件协同工作。理解这些部件,对做题和实际配置都有帮助。

主存地址寄存器(AR):存放当前要读写的主存地址。每传送一个字,这个寄存器自动加一或减一,指向下一个位置。这就是为什么DMA适合连续数据块传送——地址自动递增,不需要CPU干预。

字计数器(WC):记录还剩多少个字没传。每传一个字减一,减到零时发出结束信号。这个计数器决定了DMA传送的长度,在STM32里对应的就是NDTR寄存器。

数据缓冲寄存器(BR):暂时存放正在传送的数据。外设和主存的速度可能不匹配,这个缓冲起到一个缓冲作用。

设备地址寄存器(DAR):存放外设的地址或接口标识,用来选中要通信的外设。

控制/状态逻辑:负责接收CPU的初始化命令、产生DMA请求信号、管理总线占用、在传送结束时发出中断请求。

中断机构:传送完成后向CPU发中断,告诉CPU“活干完了”。

这些部件协同工作的流程是:CPU初始化AR、WC、DAR和控制寄存器,然后启动DMAC。DMAC向外设发出DMA请求,外设准备好后给出应答,DMAC向CPU申请总线使用权,获得总线后直接在内存和外设之间传送数据,每传一个字AR和WC更新一次,WC归零时触发中断。

2.3 DMA与中断方式的本质区别

很多人做题时容易把DMA和中断方式搞混,因为两者都涉及“打断CPU”。但它们的打断粒度完全不同。

中断方式是每传一个数据单位就打断一次,CPU需要执行指令来完成数据搬运。DMA方式是整块数据传送只打断两次——开始前初始化一次(这甚至不算打断,是CPU主动执行的),结束后中断一次。中间的数据搬运CPU完全不参与。

从数据流向看,中断方式的数据路径是:外设→CPU寄存器→主存。DMA方式的数据路径是:外设→主存(或主存→外设),CPU被完全旁路。

从优先级看,DMA请求的优先级高于中断请求。因为DMA请求对应的是数据传送的实时性要求,如果DMA请求被中断请求打断,可能导致数据丢失。在总线仲裁中,DMAC通常拥有比CPU更高的总线优先级。

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

这是408考试的高频考点,也是实际硬件设计中三种不同的总线占用策略。每种方式对应不同的效率和应用场景,理解它们的区别对做题至关重要。

3.1 停止CPU访存方式

这种方式最粗暴:DMAC一旦获得总线控制权,就独占总线,直到整块数据传送完毕才把总线还给CPU。在DMA传送期间,CPU完全无法访问主存,只能干等着或者做那些不需要访存的操作(比如执行寄存器间的运算)。

优点是控制简单,DMAC只需要在开始时申请一次总线,传送过程中不需要反复仲裁。缺点是CPU访存被完全阻塞,如果DMA传送的数据块很大,CPU的性能损失非常明显。

这种方式适合什么场景?适合外设数据传输速率极高、且数据块不大的情况。比如某些高速ADC的突发采集,采集一批数据就结束,CPU等一小会儿可以接受。但如果是一个持续的大文件传输,用这种方式CPU基本上就废了。

在408题目中,如果题目说“DMA传送期间CPU不能访存”,那考的就是这种方式。计算CPU效率损失时,直接用DMA传送时间除以总时间即可。

3.2 周期挪用方式

这是实际系统中最常用的方式,也是考试中最常考的方式。核心思想是:DMAC每次只“偷”一个或几个存取周期,传完一个字就把总线还给CPU。如果此时CPU正在访存,DMAC就等一个周期;如果CPU不需要访存(比如正在执行加法指令),DMAC就趁虚而入。

这种方式下,DMAC需要为每个字的传送都申请一次总线,控制比停止CPU方式复杂,但CPU的访存效率高很多。CPU感觉不到明显的阻塞,只是在某些存取周期上会和DMAC产生竞争。

周期挪用方式有一个关键参数:DMA传送占用存取周期的比例。假设主存存取周期为T,DMAC每传送一个字需要占用一个存取周期,传送N个字就需要N个存取周期。如果CPU在这段时间内需要访存M次,那么实际可用的存取周期就是总周期数减去被DMA挪用的周期数。

24年那道45题考的就是这个计算。题目给出CPU执行一段程序需要多少个机器周期,其中多少涉及访存,然后问DMA挪用多少个存取周期。解题的关键是:DMA只在CPU不访存的周期才能挪用,如果CPU正在访存,DMA需要等待。所以实际挪用的周期数取决于CPU访存的密度。

我拿一个具体例子算一下。假设主存存取周期为0.5微秒,CPU执行一条指令平均需要2个机器周期,其中1个是访存周期。现在有一个DMA请求要传送1000个字。如果采用周期挪用方式,DMAC每传一个字需要一个存取周期,总共需要1000个存取周期,即500微秒。在这500微秒内,CPU如果一直在执行程序,大约可以执行500/1=500条指令(每条指令2个机器周期,其中1个访存),也就是需要500个访存周期。但主存总共只有1000个存取周期,DMA占用了1000个,CPU就没得用了。实际上DMAC会和CPU竞争,最终DMA传送1000个字的时间会拉长,因为要等CPU不访存的间隙。

这个计算在考试中通常会简化:题目会告诉你CPU访存概率或者访存周期占比,然后让你算DMA实际占用多少周期。核心公式是:DMA实际传送时间 = 数据量 × 存取周期 / (1 - CPU访存占比)。

3.3 交替访存方式

这种方式最适合CPU和DMAC速度匹配的场景。它把存取周期分成两个时间片,一个给CPU用,一个给DMAC用。两者交替访问主存,互不干扰。

优点是CPU和DMA都不需要等待,效率最高。缺点是硬件控制复杂,需要精确的时序配合,而且要求CPU和DMAC的存取周期匹配。如果CPU的存取周期和DMAC不一致,就需要额外的同步逻辑。

在实际芯片设计中,这种方式常见于CPU和DMA共享同一块双端口RAM的场景。但在408考试中,这种方式考得相对少一些,因为计算比较简单——直接按时间片分配即可。

3.4 三种方式的对比与选型

对比维度停止CPU访存周期挪用交替访存
总线占用整块独占按字申请固定时间片
CPU阻塞程度完全阻塞部分阻塞几乎不阻塞
控制复杂度简单中等复杂
适用场景高速小数据块通用场景CPU与DMA速度匹配
408考试频率中等最高较低

选型的核心逻辑是:看外设的数据速率和CPU的访存需求。如果外设速率极高且数据块小,停止CPU方式可以接受;如果外设速率中等且CPU需要持续访存,周期挪用是首选;如果两者速度匹配且硬件支持,交替访存效率最高。

4. DMA传送的完整实操流程与关键参数

4.1 从CPU初始化到传送结束的完整时序

DMA传送不是一瞬间完成的,它有一个完整的流程。我以磁盘读取为例,把每一步拆开讲。

第一步:CPU初始化DMAC。CPU执行几条输出指令,把主存起始地址写入AR,把传送字数写入WC,把外设地址写入DAR,把传送方向(读/写)、传送方式(周期挪用/停止CPU)、是否自动重装等控制信息写入控制寄存器。这一步是CPU主动执行的,不涉及总线仲裁。

第二步:CPU启动外设。CPU向外设接口发启动命令,外设开始准备数据。比如磁盘开始寻道、旋转等待扇区。

第三步:外设发出DMA请求。当外设准备好一个数据单位(比如一个扇区的数据已经读到接口的缓冲区),它向DMAC发出DMA请求信号(DREQ)。

第四步:DMAC向CPU申请总线。DMAC收到DREQ后,向CPU发出总线请求信号(HOLD)。CPU在当前总线周期结束后,发出总线响应信号(HLDA),把总线控制权交给DMAC。

第五步:DMAC传送数据。DMAC获得总线后,把外设接口中的数据读到BR,然后写入主存AR指向的地址。或者反过来,从主存读出写入外设。每传一个字,AR加一(或减一),WC减一。

第六步:释放总线。如果是周期挪用方式,传完一个字DMAC就释放总线,CPU可以继续访存。如果是停止CPU方式,DMAC继续持有总线直到WC归零。

第七步:传送结束,发出中断。WC减到零时,DMAC向CPU发出中断请求。CPU响应中断,执行中断服务程序,检查传送是否成功,然后进行后续处理(比如处理下一块数据或通知应用程序)。

这个流程在408题目中经常以时序图的形式出现,要求你标出各个信号的变化时刻。关键点是:DMA请求可以在CPU总线周期的任意时刻发出,但总线响应必须等到当前总线周期结束。这就是为什么DMA传送会“挪用”存取周期——它只能在一个完整的存取周期结束后才能接管总线。

4.2 关键参数的计算方法

DMA传送涉及几个关键参数,考试和实际配置中都需要计算。

传送字数:由WC决定,等于数据块大小除以数据单位宽度。比如要传送4KB数据,数据宽度为4字节,则WC=1024。

传送时间:如果采用停止CPU方式,传送时间 = 字数 × 存取周期。如果采用周期挪用方式,传送时间 = 字数 × 存取周期 / (1 - CPU访存占比)。这个公式的推导逻辑是:在每个存取周期内,DMA和CPU竞争总线,DMA能拿到的概率是(1 - CPU访存占比)。

CPU效率损失:停止CPU方式下,损失 = DMA传送时间 / 总时间。周期挪用方式下,损失 = DMA挪用的周期数 / 总周期数。

我拿一个典型题目算一遍。假设主存存取周期为0.5微秒,CPU平均每2个存取周期访存一次(访存占比50%)。现在要传送2000个字。采用周期挪用方式,DMA实际传送时间 = 2000 × 0.5 / (1 - 0.5) = 2000微秒。在这2000微秒内,CPU可以执行2000/0.5 = 4000个存取周期,其中2000个用于访存,2000个被DMA挪用。CPU的效率损失是50%。

如果采用停止CPU方式,DMA传送时间 = 2000 × 0.5 = 1000微秒。在这1000微秒内,CPU完全不能访存,效率损失100%。但传送时间短了一半。这就是典型的“效率换时间”权衡。

4.3 STM32中DMA的实际配置要点

虽然408考的是原理,但很多同学学完之后会去玩STM32,这里我把STM32 DMA配置中的关键点和408知识点对应起来讲。

STM32的DMA控制器有多个通道,每个通道可以独立配置。关键寄存器包括:

  • CPAR(外设地址寄存器):对应DMAC的DAR,存放外设数据寄存器的地址。
  • CMAR(存储器地址寄存器):对应DMAC的AR,存放主存缓冲区地址。
  • CNDTR(数据项数寄存器):对应DMAC的WC,设置要传送的数据个数。
  • CCR(通道配置寄存器):配置传送方向、数据宽度、优先级、循环模式、中断使能等。

配置流程和408讲的完全一致:先使能DMA时钟,然后配置CPAR、CMAR、CNDTR,最后配置CCR并使能通道。传送完成后,CNDTR归零,如果使能了传输完成中断,就会触发中断。

有一个实际配置中容易踩的坑:数据宽度对齐。如果外设数据宽度是8位,存储器数据宽度是16位,DMA会怎么处理?STM32的DMA支持独立配置外设和存储器的数据宽度,但传送时以较小的宽度为准,可能会产生数据对齐问题。比如外设8位、存储器16位,DMA会把两个8位数据拼成一个16位写入存储器。如果顺序搞反了,数据就乱了。这个细节在408中不考,但实际调试中经常遇到。

另一个坑是循环模式与普通模式的选择。循环模式下,CNDTR归零后自动重装,DMA持续不断地传送。这适合ADC连续采集、串口持续接收等场景。普通模式下,CNDTR归零后DMA停止,需要重新配置才能再次传送。选错了模式,要么数据只传一次就停了,要么DMA停不下来。

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

5.1 408做题中的典型陷阱

陷阱一:混淆DMA请求和中断请求的优先级。DMA请求的优先级高于中断请求,因为DMA请求对应的是数据传送的实时性,如果被中断打断可能导致数据丢失。在总线仲裁中,DMAC的优先级也高于CPU。题目如果问“DMA请求和中断请求同时发生,CPU先响应哪个”,答案是DMA请求。

陷阱二:误以为DMA传送完全不经过CPU。严格来说,DMA传送的初始化(写寄存器)和结束处理(中断服务)还是需要CPU参与的。DMA只是把数据搬运的过程从CPU手中拿走了,但控制流仍然需要CPU。题目如果问“DMA方式下CPU完全不参与”,这是错的。

陷阱三:周期挪用方式下DMA传送时间的计算。很多人直接用字数乘以存取周期,忽略了CPU访存的竞争。正确的做法是考虑CPU访存占比,DMA实际传送时间会拉长。如果题目给出“CPU访存概率为p”,则DMA传送一个字平均需要的时间是存取周期/(1-p)。

陷阱四:DMA传送与CPU访存的冲突处理。当DMA和CPU同时请求访存时,通常DMA优先级更高。但有些题目会设定“CPU正在访存时DMA等待”,这时DMA的实际传送时间取决于CPU访存的密度。需要根据题目给出的时序图或访存模式来具体分析。

5.2 实际调试中的常见问题速查表

问题现象可能原因排查方法解决方案
DMA传送不启动通道未使能或DREQ未触发检查CCR的EN位和外设的DMA请求配置使能通道,确认外设已启动
传送数据错位数据宽度不匹配检查CPAR和CMAR的数据宽度配置统一数据宽度或调整对齐方式
传送一半就停了CNDTR设置错误或传输模式选错检查CNDTR值和循环/普通模式修正CNDTR,选择正确模式
传送完成后没有中断中断未使能或中断标志未清除检查CCR的TCIE位和中断标志寄存器使能传输完成中断,清除标志
CPU访存变慢DMA占用总线过多检查DMA优先级和传送方式降低DMA优先级或改用周期挪用
数据覆盖循环模式下缓冲区未及时处理检查CNDTR重装和缓冲区大小增大缓冲区或降低传送速率

5.3 独家避坑经验

经验一:DMA传送方向别搞反。STM32的CCR寄存器中DIR位决定方向:0表示从外设读到存储器,1表示从存储器写到外设。我见过有人调串口发送,结果DIR设成了0,数据从串口DR读到内存,当然发不出去。记住:外设到内存是“读”,内存到外设是“写”。

经验二:CNDTR的单位是“数据项”不是“字节”。如果你配置数据宽度为16位,CNDTR设为100,实际传送的是200字节。很多人按字节数设置CNDTR,结果传送的数据量翻倍或减半。正确做法是:CNDTR = 总字节数 / 数据宽度。

经验三:DMA和CPU同时访问同一块内存会出问题。如果CPU正在读写某个缓冲区,DMA同时也在传送数据到这块缓冲区,数据可能被覆盖或读到中间状态。解决方案是使用双缓冲(DMA传一块,CPU处理另一块)或者使用内存屏障确保顺序。

经验四:传输完成中断里别做耗时操作。DMA传输完成中断的服务程序应该尽量短,只做标志设置或缓冲区切换。如果在中断里做大量数据处理,会阻塞后续DMA请求的响应,导致数据丢失。我一般是在中断里只置一个标志,主循环里检查标志再处理数据。

经验五:注意DMA的地址对齐。有些平台要求DMA传输的源地址和目的地址必须对齐到数据宽度。比如16位传输要求地址是2的倍数,32位传输要求地址是4的倍数。不对齐可能导致传输错误或硬件异常。配置前先检查缓冲区地址的对齐情况。

6. DMA在408考试中的出题规律与备考建议

6.1 历年真题中的DMA考点分布

翻一遍408历年真题,DMA相关的题目主要集中在几个方向:DMA与中断方式的对比、DMA三种传送方式的效率计算、DMA控制器的组成部件、DMA传送的时序分析。其中周期挪用方式的效率计算出现频率最高,几乎每隔几年就会考一次。

24年那道45题考的是DMA传送过程中CPU访存被挪用的周期数计算。题目给出了一段程序的执行时序和DMA请求的时刻,要求计算DMA挪用了多少个存取周期。解题的关键是画出时间轴,标出CPU访存周期和DMA请求时刻,然后看哪些CPU访存周期被DMA“抢走”了。

这类题目的通用解法是:先确定DMA请求发生的时刻,然后看从该时刻开始,CPU还有哪些访存周期。DMA会优先占用CPU不访存的周期,如果CPU一直在访存,DMA就需要等待。实际挪用的周期数等于DMA需要传送的字数,但传送时间会拉长。

6.2 备考策略与复习重点

如果你时间有限,DMA这部分优先掌握以下内容:

第一,三种传送方式的区别和效率计算。这是必考内容,尤其是周期挪用方式。把公式记牢:DMA实际传送时间 = 字数 × 存取周期 / (1 - CPU访存占比)。

第二,DMA控制器的组成部件。AR、WC、BR、DAR、控制/状态逻辑、中断机构,每个部件的功能要能说出来。考试可能以选择题或简答题形式出现。

第三,DMA与中断方式的对比。从数据路径、打断粒度、优先级、适用场景四个维度对比。这个知识点经常以选择题形式出现。

第四,DMA传送的完整流程。从CPU初始化到传送结束中断,每一步的信号变化要清楚。时序图题需要能标出关键信号。

第五,DMA方式下的CPU效率分析。停止CPU方式和周期挪用方式下,CPU的效率损失分别是多少。这个和第一点有重叠,但更侧重效率分析。

6.3 从考试到实战的衔接

408考的是原理,但原理和实战是相通的。你在STM32里配置DMA时遇到的每个寄存器,在408教材里都有对应的部件。CPAR对应DAR,CMAR对应AR,CNDTR对应WC,CCR对应控制/状态逻辑。把教材里的原理图和实际芯片的框图对照看,理解会深很多。

我当年备考时,就是一边看唐朔飞的教材,一边拿STM32的参考手册对照。教材讲的是通用原理,参考手册讲的是具体实现。两者结合,既能把题做对,又能把代码调通。后来工作中用到Linux DMA、SPI DMA、串口DMA,发现底层逻辑完全一样——都是初始化、申请总线、传送、中断这几步。

DMA这个知识点,考试考的是计算和对比,实战考的是配置和调试。但核心思想只有一个:把CPU从数据搬运中解放出来,让专门的硬件干专门的事。理解了这个思想,不管是做题还是调代码,都不会跑偏。

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

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

立即咨询