深入解析DMA通道优先级、地址指针与传输控制机制

发布时间:2026/7/21 10:49:53
深入解析DMA通道优先级、地址指针与传输控制机制 1. 项目概述与DMA核心价值在嵌入式系统开发里尤其是面对像高速ADC采样、多路串口通信、图像传感器数据搬运这类实时性要求极高的场景CPU如果亲自下场去搬数据那基本就啥也别干了光顾着当“数据搬运工”了。这时候DMADirect Memory Access直接内存访问就成了解放CPU、提升系统吞吐量的“王牌外设”。它的核心思想很简单在内存和外设之间开辟一条“数据高速公路”让一个专用的DMA控制器来接管繁琐的复制、搬运工作CPU只需要发号施令然后就可以去处理更复杂的计算和逻辑任务实现真正的并行处理。但用好DMA远不是配置个源地址、目标地址然后启动那么简单。它的强大和复杂都藏在细节里。比如当多个外设同时需要DMA服务时谁先谁后这就是通道优先级要解决的问题。再比如我们希望DMA搬完一块数据后能自动跳到下一块内存继续或者循环覆盖一个缓冲区这背后就是地址指针的自动步进与回绕机制在起作用。还有一次触发搬多少数据搬完一轮后是停下来还是继续这就涉及到传输控制模式如ONESHOT、CONTINUOUS的配置。这些机制共同构成了DMA灵活高效处理数据流的基石。本文将以广泛应用的TI C2000系列微控制器中的DMA模块为蓝本抛开手册式的罗列结合我实际在电机控制、数字电源项目中调试DMA数据采集和传输的经验深入解析其通道优先级仲裁策略、地址指针的管理哲学以及传输控制的状态机逻辑。我会重点讲清楚“为什么”要这么设计并给出在具体场景如ADC同步采样、乒乓缓冲下的配置实例和避坑指南。无论你是刚开始接触DMA的新手还是想深入了解其内部机制的老手这篇文章都能帮你把这块硬骨头啃明白。2. DMA通道优先级机制深度解析当系统中有多个DMA通道例如C2000的DMA通常有6个独立通道同时被使能并等待服务时DMA控制器必须有一套明确的规则来决定先响应哪个通道的请求。这套规则就是优先级机制它直接影响了多外设并发场景下的数据实时性和系统确定性。2.1 轮询调度模式与复位在默认情况下大多数DMA模块采用轮询Round-Robin调度。你可以把它想象成一个依次服务的队列。假设CH2、CH3、CH4、CH5、CH6都被使能并且都处于等待状态即其对应的外设触发了请求。DMA状态机会按照CH2 → CH3 → CH4 → CH5 → CH6 → CH2 → … 的顺序依次检查并服务。每个通道服务完一个突发传输Burst后状态机就会移动到下一个使能的通道无论该通道是否有新的请求。这种机制保证了所有通道都能获得均等的服务机会避免了某个低优先级通道被“饿死”。但轮询的顺序并非一成不变。这里有一个关键的操作优先级复位PRIORITYRESET。通过设置DMACTRL寄存器的PRIORITYRESET位为1可以强制将轮询状态机重置到空闲状态。当状态机再次启动时它会从第一个被使能的通道通常是编号最小的那个重新开始轮询。实操心得这个功能在动态管理DMA通道时非常有用。例如在系统初始化阶段你可能会先使能几个通道运行一段时间后又需要动态开启或关闭某些通道。如果不进行优先级复位新加入的通道可能会被插入到当前轮询位置的“后面”导致其服务时机不确定。在关键任务初始化完成后执行一次优先级复位可以确保轮询顺序从已知的起点开始增强系统的可预测性。2.2 通道1高优先级模式详解轮询虽公平但无法应对紧急任务。为此DMA模块通常会给某个通道在C2000中是通道1赋予高优先级模式。这是一种硬中断式的抢占机制。当通道1被配置为高优先级模式后其行为规则如下抢占条件只要通道1的触发事件发生无论当前正在服务哪个通道假设是CH4DMA控制器都会在完成当前正在进行的单字传输后注意是完成当前这个word的传输而不是完成整个突发传输立即挂起当前通道CH4的操作。紧急服务随后DMA控制器会全力服务通道1完成其配置的整个突发传输。现场恢复通道1的突发传输全部完成后DMA控制器会回到之前被挂起的通道CH4从其被中断的地方继续执行。手册里举了一个很典型的例子CH1、CH4、CH5使能CH1为高优先级。当前正在服务CH4。此时CH1和CH5的触发信号几乎同时到达。裁决由于CH1是高优先级系统会先响应它。但前提是要等CH4当前的这个字传输完成。执行CH4的当前字传输结束CH4被挂起。DMA开始服务CH1完成其整个突发比如32个字。恢复CH1完成后恢复CH4继续完成CH4剩余的传输或整个突发取决于中断点。后续CH4全部完成后再去服务在排队中的CH5。核心设计逻辑为什么是“完成当前字”而不是“完成当前突发”再响应这是对实时性的一种极致平衡。如果等整个突发可能多达32个字完成高优先级通道的响应延迟会非常大可能丢失数据。而“完成当前字”则能将响应延迟控制在几个时钟周期内满足了像ADC这种高速、连续数据流对实时性的苛刻要求。2.3 优先级模式下的配置禁忌这里有一个非常重要的配置禁忌手册中明确用NOTE标出通道1的高优先级模式High-priority mode和单次传输模式ONESHOT mode不能同时启用。为什么我们来分析一下冲突点。ONESHOT模式意味着通道一旦被触发就会连续进行多次突发传输直到TRANSFER_COUNT减到零期间不会释放总线控制权。而高优先级模式的设计初衷是让通道1能快速抢占并完成一个紧急的突发传输。如果通道1同时开启了ONESHOT它一旦抢占就可能因为要完成一个非常长的传输由TRANSFER_SIZE决定而长时间霸占总线这实质上破坏了高优先级“快速响应、快速释放”的设计原则可能导致其他所有通道包括原本被它中断的通道被“饿死”很长时间系统实时性完全崩溃。对其他通道的影响这个限制仅针对通道1。当通道1处于高优先级模式时其他通道CH2-CH6仍然可以自由使用ONESHOT模式。因为它们的优先级平等在轮询机制下每个通道的ONESHOT传输完成后控制权都会交还给仲裁器从而轮到下一个通道不会造成全局阻塞。避坑指南在配置通道1用于处理最高速数据流如ADC时常见的做法是将其设为高优先级但不要开启ONESHOT。相反应该根据ADC的采样率合理设置BURST_SIZE例如设置为ADC序列器的长度让每次ADC序列完成触发一次DMA搬运一个突发的数据。这样既能保证ADC数据被及时响应又不至于阻塞系统太久。3. 地址指针与传输控制DMA状态机的双循环引擎如果说优先级机制是DMA的“交通规则”那么地址指针和传输控制就是驱动DMA工作的“发动机和导航系统”。理解了这个部分你才能真正驾驭DMA去实现复杂的存储访问模式。3.1 核心概念突发与传输DMA的状态机本质上由两层嵌套循环构成这是理解所有配置寄存器的基础。内层循环突发传输这是DMA工作的最小原子操作单元。当DMA通道接收到一个来自外设的触发信号如ADC转换完成中断时就会启动一次突发传输。这次传输的数据量由BURST_SIZE寄存器定义单位是字16-bit。例如BURST_SIZE设置为15表示16个字那么一次触发就会连续搬运16个字的数据。BURST_SIZE的最大值受硬件限制C2000的DMA通常支持最多32个字。外层循环传输一个完整的传输由多次突发传输组成。次数由TRANSFER_SIZE寄存器定义。例如BURST_SIZE1516字/次TRANSFER_SIZE3132次突发那么完成整个传输需要32次触发总共搬运 16字/次 * 32次 512个字的数据。TRANSFER_SIZE是16位寄存器其能表示的传输总量远超一般应用需求。每次传输即外层循环完成时可以产生一个CPU中断如果使能了这个中断可以配置为在传输开始时或传输结束时产生通过MODE.CHx[CHINTMODE]位控制。3.2 地址指针的“影子”与“活动”双寄存器机制这是DMA设计中的一个精妙之处为实现乒乓缓冲等高级功能提供了硬件支持。每个DMA通道的源地址和目标地址都有两套寄存器影子寄存器SRC_ADDR_SHADOW,DST_ADDR_SHADOW,SRC_BEG_ADDR_SHADOW,DST_BEG_ADDR_SHADOW。这些寄存器由软件读写。你在配置DMA时操作的就是这些影子寄存器。活动寄存器SRC_ADDR,DST_ADDR,SRC_BEG_ADDR,DST_BEG_ADDR。这些寄存器由硬件自动更新和使用是DMA状态机实际工作时使用的当前地址指针。关键的工作流程当一次新的传输开始时例如通道被使能或连续模式下一次传输结束、下一次传输开始硬件会自动将所有影子地址寄存器的值拷贝到对应的活动寄存器中。此后在传输进行过程中硬件只修改活动寄存器。这种设计带来的巨大优势无干扰配置你可以在DMA正在忙于当前传输使用活动寄存器集的同时从容地通过软件为下一次传输准备好新的地址参数写入影子寄存器集。当前传输一结束下一次传输开始时新的配置即刻生效实现了无缝衔接。实现乒乓缓冲这是最典型的应用。你可以准备两个缓冲区Buffer A和Buffer B。当DMA正在向Buffer A写数据时使用活动寄存器指向Buffer A你可以通过软件把影子目标地址寄存器修改为Buffer B的起始地址。一旦Buffer A写满当前传输结束下一次传输自动开始DMA就会使用新的影子寄存器值指向Buffer B开始写入。同时CPU可以安全地读取已经写满的Buffer A。如此循环实现了数据生产和消费的并行几乎没有延迟。3.3 地址指针的步进控制BURST_STEP, TRANSFER_STEP, WRAP_STEP地址指针不是静态的DMA硬件会在传输过程中自动更新它们这通过三个“步进”寄存器来控制它们都是有符号的二进制补码意味着地址可以递增或递减。寄存器作用时机功能描述典型应用场景SRC/DST_BURST_STEP突发内循环每传输完一个字之后。更新当前活动的SRC_ADDR或DST_ADDR。线性地址增长。例如从内存连续区域读取数据BURST_STEP设为216位地址步进若数据为32位则每次地址2。访问外设固定寄存器如ADC结果寄存器时设为0。SRC/DST_TRANSFER_STEP传输外循环每完成一次突发传输之后。在默认模式下非回绕模式更新活动的SRC_ADDR或DST_ADDR。实现数据块之间的间隔。例如将一个二维数组的行数据分散存储每次突发传输一行后地址需要跳转到下一行的起始位置。SRC/DST_WRAP_STEP回绕发生时当WRAP_COUNT减到0时。更新活动的SRC/DST_BEG_ADDR然后将其加载到SRC/DST_ADDR。实现多缓冲区的循环访问。与WRAP_SIZE配合可以在一个大的传输中让地址指针在几个缓冲区之间循环跳转。一个综合示例假设我们需要用DMA将ADC的4个通道采样结果每个结果32位循环存入两个缓冲区每个缓冲区容纳10组数据即10*4个32位字。配置DST_BURST_STEP 2因为每个ADC结果是32位地址需2BURST_SIZE 34个字为一次突发因为SIZE寄存器值字数-1DST_WRAP_SIZE 9每10次突发后回绕因为WRAP_SIZE值突发数-1DST_TRANSFER_STEP 0回绕发生时此值无效DST_WRAP_STEP 80假设Buffer A起始地址为0x8000Buffer B为0x8050。10组4字/组2字节/字80字节。从A回绕到B地址需80。注意STEP寄存器值针对16位地址所以80字节对应40个地址单位但这里WRAP_STEP加载到BEG_ADDRBEG_ADDR是字节地址这里需要根据具体手册确认地址单位通常这些寄存器值以字为单位。这是一个易错点TRANSFER_SIZE设置得足够大或者启用CONTINUOUS模式。过程DMA从DST_ADDR0x8000开始写。每次突发写4个字地址按BURST_STEP2递增。写完10次突发即写满Buffer A后WRAP_COUNT减到0触发回绕。回绕动作首先DST_BEG_ADDR DST_WRAP_STEP即DST_BEG_ADDR从0x8000变为0x8050Buffer B起始。然后DST_ADDR DST_BEG_ADDR。同时WRAP_COUNT被重载为WRAP_SIZE9。继续DMA接着向Buffer B写入数据。如此循环往复。重要提示手册中特别强调无论DATASIZE位控制传输数据宽度是16位还是32位如何设置SIZE和STEP类寄存器的值都是针对16位地址单元而言的。这意味着如果你想传输3个32位字BURST_SIZE应该设置为5(3个字 * 2个16位单元/字 - 1)。如果你想在每次传输后让32位字的地址指针递增1SRC_BURST_STEP应该设置为2。 忽略这一点是导致DMA地址错乱、数据覆盖的常见原因。3.4 传输控制模式ONESHOT, CONTINUOUS, CHINTMODE这三个模式位决定了DMA状态机在触发、传输完成时的行为。ONESHOT单次触发模式禁用默认每次外设触发信号到来DMA只执行一次突发传输。即使这个通道的整个传输TRANSFER_SIZE定义还没完成DMA也会在本次突发后释放总线让优先级状态机去服务其他通道。这保证了总线带宽的公平共享。启用一次外设触发会导致DMA连续执行突发传输直到TRANSFER_COUNT减到零完成整个传输。这会独占DMA总线直到传输结束可能阻塞其他通道。手册警告这可能导致外设带宽被过度占用和CPU长时间停顿。使用时需非常谨慎通常需要配合定时器来限制其运行时间。CONTINUOUS连续模式禁用当一次传输TRANSFER_COUNT到零完成后该通道的RUNSTS位会被自动清除通道停止。需要软件重新设置RUN位才能开始下一次传输。启用传输完成后RUNSTS位保持置位通道保持使能状态。一旦再次收到触发信号立即开始新一轮的传输使用最新的影子寄存器值。这是实现连续不断的数据流传输的常用模式例如持续不断的ADC采样。CHINTMODE通道中断模式0在每次传输开始时产生DMA通道中断如果中断使能。1在每次传输结束时产生DMA通道中断。选择策略在配合乒乓缓冲和连续模式时通常选择在传输开始时中断。因为中断发生时DMA已经将影子寄存器拷贝到了活动寄存器即将开始向下一个缓冲区写入。此时CPU可以安全地处理刚刚写满的上一个缓冲区的数据实现了完美的生产-消费同步。如果选择传输结束中断则会有半个传输周期的延迟。4. ADC同步与溢出检测应对实时系统的特殊挑战在高速数据采集系统中DMA与ADC的协同工作至关重要。C2000的DMA提供了专门的硬件同步机制来应对ADC在连续转换模式下的同步问题。4.1 ADC同步功能原理当ADC配置为连续转换模式且启用了序列器覆盖功能时ADC会不停地循环转换一个通道序列且序列器指针不会在每次序列结束时复位。问题来了DMA在收到ADC触发信号时它并不知道当前ADC的序列器指针指向哪个RESULT寄存器。如果DMA总是从固定的RESULT0开始读而ADC的序列器已经指向了RESULT2那么数据对应关系就完全乱套了。为了解决这个问题ADC硬件会在其序列器指针回到RESULT0时向DMA发送一个同步信号。DMA期望这个同步信号与其自身的回绕操作或传输开始的时机对齐。同步成功如果对齐则一切正常。同步错误如果DMA在非预期的时刻收到了同步信号例如因为DMA繁忙错过了一个触发导致步调不一致就会发生同步错误。此时DMA硬件会自动执行一个再同步过程将WRAP_COUNT寄存器重新加载为WRAP_SIZE值。将活动的地址指针ADDR可能是SRC_ADDR或DST_ADDR由SYNCSEL选择加载为BEG_ADDR的值。设置CONTROL寄存器中的SYNCERR位向软件报告发生了同步错误。这个过程相当于强制将DMA的读写指针“拉回”到缓冲区的起始位置与ADC的序列器指针重新对齐确保后续数据的正确性。4.2 溢出检测逻辑DMA的溢出检测是针对事件触发丢失的防护机制。其逻辑如下当DMA通道收到一个外设事件触发时会设置CONTROL寄存器中的PERINTFLG位表示该通道有一个传输请求待处理。当DMA状态机开始为该通道服务即开始一个突发传输时会清除PERINTFLG位。关键风险窗口在PERINTFLG被置位后、到被清除前的这段时间内如果同一个外设又产生了第二个触发事件那么这个后续事件就会被DMA硬件丢失。一旦检测到这种丢失情况DMA会设置OVRFLG溢出标志位。如果使能了溢出中断还会产生一个通道中断通知CPU。问题排查实录在调试一个高速SPI接收DMA时我发现偶尔会丢失数据包。检查代码逻辑无误最后查看DMA状态寄存器发现OVRFLG位被置位了。这说明SPI数据来的太快DMA还没处理完上一个突发下一个触发就已经到来。解决方案不是一味提高DMA优先级而是需要从系统层面优化减小BURST_SIZE让每次触发搬运的数据量变小缩短DMA占用总线的时间加快响应速度。优化缓冲区设计使用更大的缓冲区并配合WRAP机制允许一定程度的触发堆积只要平均数据率不超过DMA处理能力即可。检查外设时钟与DMA时钟确保DMA控制器的工作时钟不低于外设的数据时钟避免处理能力不足。5. 寄存器配置实战与心得理解了原理最终都要落到寄存器配置上。下面我以一个具体的例子——用DMA实现ADC四通道同步采样并循环存入双缓冲——来串联上述所有知识点并分享配置步骤和心得。5.1 场景与目标ADC序列器1SEQ1连续采样4个通道A0, A1, A2, A3。采样率1MHz即每1us完成一次4通道的序列转换并触发DMA。DMA目标将采样结果每个结果32位循环存入两个内存缓冲区Ping-Buffer和Pong-Buffer每个缓冲区容纳100组数据100组 * 4通道 400个32位字。CPU当DMA写满一个缓冲区后通过中断通知CPUCPU处理该缓冲区数据如进行滤波、计算。5.2 配置步骤详解步骤1计算关键参数每次ADC序列完成产生一次触发对应DMA的一次突发传输。每个通道结果32位 2个16位字。4个通道 8个字。因此BURST_SIZE 7(8 - 1)。我们希望每100组数据即100次突发切换一次缓冲区。因此DST_WRAP_SIZE 99(100 - 1)。缓冲区大小100组 * 4字/组 * 2字节/字 800字节。假设Ping-Buffer起始地址为0x8000Pong-Buffer起始地址为0x8300(0x8000 0x300)。DST_WRAP_STEP需要让BEG_ADDR在这两个地址间跳转即步进值为0x300。注意WRAP_STEP寄存器的值代表16位地址单元的增量。0x300字节 0x180个16位单元。所以DST_WRAP_STEP 0x180。目标地址在突发内需要递增以存储连续的数据每个32位数据占2个地址单元所以DST_BURST_STEP 2。我们不希望在一次突发完成后地址有额外跳转因为数据是连续存储的所以DST_TRANSFER_STEP 0。为了持续运行设置CONTINUOUS 1。为了实现乒乓缓冲中断设置CHINTMODE 0传输开始中断并使能通道中断。因为ADC数据速率高且需要及时响应将通道1设为高优先级。同时绝对不能开启ONESHOT。步骤2寄存器配置代码C语言伪代码// 假设使用DMA通道1 volatile struct DMA_REGS *DmaCh1 DmaRegs.CH1; // 指向通道1寄存器组 // 1. 停止并复位通道可选初始化时做 DmaCh1-CONTROL.bit.RUN 0; // 等待DMA停止或进行软复位 // 2. 配置模式寄存器 (MODE) DmaCh1-MODE.bit.CHINTMODE 0; // 传输开始时产生中断 DmaCh1-MODE.bit.CONTINUOUS 1; // 连续模式 DmaCh1-MODE.bit.ONESHOT 0; // 禁用ONESHOT与高优先级冲突。 DmaCh1-MODE.bit.PERINTSEL ...; // 选择ADC SEQ1作为触发源根据具体型号查表 DmaCh1-MODE.bit.SYNCE 1; // 使能同步功能如果ADC使用连续模式 DmaCh1-MODE.bit.SYNCSEL 0; // 同步目标地址通常为目标地址 // 3. 配置大小寄存器 DmaCh1-BURST_SIZE 7; // 突发大小8个字 (4个32位结果) DmaCh1-TRANSFER_SIZE 0xFFFF; // 传输大小设到最大靠WRAP_SIZE控制缓冲区切换 DmaCh1-DST_WRAP_SIZE 99; // 每100次突发后回绕 // 4. 配置步进寄存器 DmaCh1-DST_BURST_STEP 2; // 突发内每字地址2 (32位数据) DmaCh1-DST_TRANSFER_STEP 0; // 突发间地址不变由WRAP控制跳转 DmaCh1-DST_WRAP_STEP 0x180; // 回绕时BEG_ADDR增加0x180个字地址单位 (0x300字节) // 5. 配置地址寄存器 (影子寄存器) DmaCh1-DST_BEG_ADDR_SHADOW (Uint32)pingBuffer; // Ping缓冲区起始地址 DmaCh1-DST_ADDR_SHADOW (Uint32)pingBuffer; // 当前目标起始地址 // 源地址寄存器配置假设ADC结果寄存器地址固定 DmaCh1-SRC_BEG_ADDR_SHADOW (Uint32)AdcResult.ADCRESULT0; DmaCh1-SRC_ADDR_SHADOW (Uint32)AdcResult.ADCRESULT0; DmaCh1-SRC_BURST_STEP 0; // 源地址固定因为总是从ADC结果寄存器读取 // 6. 配置控制寄存器并启动 DmaCh1-CONTROL.bit.PERINTE 1; // 使能外设中断触发必须 DmaCh1-CONTROL.bit.CHINTE 1; // 使能DMA通道中断用于乒乓缓冲 DmaCh1-CONTROL.bit.OVRINTE 1; // 使能溢出中断建议开启用于调试 DmaCh1-CONTROL.bit.RUN 1; // 启动DMA通道 // 7. 全局配置将通道1设为高优先级 DmaRegs.PRIORITYCTRL1.bit.CH1PRIORITY 1;步骤3中断服务程序ISR处理当DMA通道中断触发时因为CHINTMODE0这发生在下一次传输开始即切换缓冲区的时刻在ISR中首先判断是哪个缓冲区刚被写满可以通过一个全局的标志变量与当前DST_BEG_ADDR_SHADOW的指向来判断。将DST_BEG_ADDR_SHADOW和DST_ADDR_SHADOW修改为另一个缓冲区的地址。这样当DMA完成当前传输正在写的新缓冲区后下一次传输会自动使用你刚设置的新地址。处理刚刚写满的缓冲区中的数据。清除DMA通道中断标志。5.3 常见问题排查清单现象可能原因排查步骤与解决方案DMA不启动1.RUN位未置位。2. 外设触发源未正确配置或未产生触发。3. 通道未使能(PERINTE)。1. 确认CONTROL.RUN1。2. 检查MODE.PERINTSEL并用示波器或IO翻转确认外设触发信号是否到达。3. 确认CONTROL.PERINTE1。数据地址错乱1.BURST_STEP/TRANSFER_STEP/WRAP_STEP值计算错误未考虑16位地址单位。2. 影子寄存器和活动寄存器概念混淆错误地写了活动寄存器。3. 同步错误(SYNCERR)发生导致地址被重置。1.反复核对STEP和SIZE寄存器的值牢记它们针对16位地址。这是最高发的错误。2. 配置时只写xxx_SHADOW寄存器。调试时可读取xxx活动寄存器观察其变化。3. 检查CONTROL.SYNCERR位并确认ADC与DMA的同步配置是否正确。丢失数据/溢出1. DMA处理速度跟不上外设数据速率。2.BURST_SIZE过大导致单次占用总线时间太长其他高优先级任务或通道导致其触发丢失。3. 未处理溢出中断。1. 检查OVRFLG位。优化方法见第4.2节。2. 尝试减小BURST_SIZE。3. 使能并处理溢出中断至少将其作为错误标志记录。乒乓缓冲中断不对1.CHINTMODE设置错误。2. 在中断中切换缓冲区地址时写错了影子寄存器。3. 缓冲区大小或WRAP_SIZE计算错误导致未写满就切换或写溢出。1. 乒乓缓冲通常设CHINTMODE0传输开始中断。2. 确保在ISR中修改的是DST_BEG_ADDR_SHADOW和DST_ADDR_SHADOW。3. 仔细计算缓冲区能容纳的“突发”次数确保WRAP_SIZE 突发次数 - 1。通道1高优先级失效通道1同时配置了ONESHOT模式。绝对禁止同时启用通道1的高优先级和ONESHOT模式。检查MODE.ONESHOT位是否为0。调试DMA时善用调试器观察活动寄存器的变化至关重要。单步执行代码查看SRC_ADDR、DST_ADDR、BURST_COUNT、TRANSFER_COUNT、WRAP_COUNT这些活动寄存器的实时变化是理解DMA状态机行为和定位配置错误的最直接方法。把DMA想象成一个由硬件精确执行的循环程序而这些寄存器就是它的程序计数器和变量观察它们你就能看到数据流是如何被搬运的。