Tiva TM4C123 μDMA控制器深度解析:从通道配置到Ping-Pong模式实战

Tiva TM4C123 μDMA控制器深度解析:从通道配置到Ping-Pong模式实战 1. 项目概述与μDMA核心价值在嵌入式系统开发中尤其是面对实时数据采集、高速通信或图形刷新这类任务时CPU如果被频繁的数据搬运工作所拖累整个系统的响应速度和效率就会大打折扣。想象一下你正在用微控制器处理一个音频流CPU每收到一个字节的音频数据就要停下手中的计算任务去执行一次内存读写操作这无疑是巨大的资源浪费。这时直接内存访问DMA技术就成为了解放CPU、提升系统性能的关键角色。而德州仪器TI的Tiva™系列微控制器比如我们这次深入探讨的TM4C123GE6PM其内置的微直接内存访问μDMA控制器更是将这种能力精细化、可编程化为开发者提供了强大的数据搬运引擎。简单来说μDMA允许外设如ADC、UART、SPI或软件直接与内存进行数据交换整个过程无需CPU介入。CPU只需要在传输开始前告诉μDMA“从A地址搬N个数据到B地址”然后就可以去处理其他更重要的任务了。传输完成后μDMA会通过中断通知CPU“活儿干完了数据在B地址请查收”。这种“甩手掌柜”模式对于需要维持高数据吞吐量的应用至关重要。本文将以Tiva TM4C123GE6PM的μDMA模块为蓝本为你彻底拆解其工作原理。我不会仅仅罗列寄存器手册而是结合我多年在电机控制、传感器数据流处理中实际使用μDMA的经验从通道配置的底层逻辑、中断处理的实战流程到关键寄存器的每一个比特位如何影响传输行为进行深度剖析。无论你是正在调试一个ADC多通道扫描采集还是想优化SPI Flash的读写速度理解并掌握μDMA都能让你的嵌入式系统设计如虎添翼。接下来我们就从最核心的通道控制结构开始一步步揭开它的神秘面纱。2. μDMA通道控制结构深度解析如果把μDMA控制器比作一个建筑工地那么通道控制结构Channel Control Structure就是发给每个施工队DMA通道的“施工图纸”。这张图纸详细规定了“从哪里搬砖源地址”、“搬到哪里去目的地址”、“一次搬几块数据大小”、“怎么搬地址递增模式”以及“总共要搬多少传输数量”等所有关键信息。在Tiva的μDMA架构中每个通道都拥有两张这样的图纸一张主控结构Primary一张备用控制结构Alternate这正是实现Ping-Pong、Scatter-Gather等高级传输模式的基础。2.1 核心三寄存器定义传输的骨架通道控制结构主要由三个寄存器在内存中构成它们位于由DMACTLBASE寄存器指定的通道控制表Channel Control Table中。每个通道的主控结构和备用结构在表中都有固定的偏移位置。1. DMA通道源地址结束指针DMASRCENDP这个寄存器存放的是传输源地址区域的最后一个字节的地址。这里有个非常关键且容易误解的点它叫“结束指针”但实际指向的是传输范围的末尾包含该地址。例如如果你要从数组srcBuffer[100]起始地址0x2000.0000传输100个字节且地址递增那么DMASRCENDP应设置为0x2000.0000 100 - 1 0x2000.0063。注意当源地址不递增时SRCINC字段为0x3此寄存器直接指向源外设的数据寄存器地址本身。此时μDMA会反复从这个固定地址读取数据。2. DMA通道目的地址结束指针DMADSTENDP与源地址指针同理它定义了传输目的地址区域的最后一个字节的地址。设置规则与DMASRCENDP完全一致。同样当目的地址不递增时DSTINC为0x3它指向一个固定的外设数据寄存器。3. DMA通道控制字DMACHCTL这是整个控制结构的“大脑”一个32位的寄存器包含了决定传输行为的所有控制位。我们需要逐字段理解DSTINC (位 31:30) 与 SRCINC (位 27:26)目的和源地址增量。它决定了每次传输后地址指针如何移动。可选值为0x0字节递增、0x1半字递增、0x2字递增、0x3不递增。这里有一个硬性规则增量值必须大于或等于对应的数据大小DSTSIZE/SRCSIZE。例如数据大小是字4字节那么地址增量至少要是字0x2不能是字节0x0。通常从内存到内存的传输两者都设为递增从外设到内存源外设不递增目的内存递增反之亦然。DSTSIZE (位 29:28) 与 SRCSIZE (位 25:24)目的和源数据项大小。定义每次传输操作的数据宽度0x08位、0x116位、0x232位。另一个关键规则DSTSIZE和SRCSIZE必须设置为相同的值。你不能用一次32位读取搭配一次16位写入。ARBSIZE (位 17:14)仲裁大小。这个字段决定了μDMA控制器在“抢占”总线进行传输时一次性连续传输多少个数据项然后再释放总线给其他主设备如CPU。它是以2的幂次方定义的从10x0到10240xA此时由于单次传输已达最大项数故不仲裁。设置更大的仲裁大小可以提高总线利用率和传输效率尤其是在传输大块连续数据时。但如果你需要更低的传输延迟让CPU能更频繁地介入则可以设小一些。XFERSIZE (位 13:4)传输大小减1。这是你需要传输的总数据项数量减1。这是一个10位字段最大值为1023代表一次传输最多1024个数据项。务必记住这里填写的是“项数-1”。如果你想传输200个32位字这里应填1990xC7。同时这个值指的是“数据项”的个数而非字节数。如果数据大小是半字16位传输100项实际搬运的数据量是200字节。XFERMODE (位 2:0)传输模式。这是μDMA的灵魂决定了传输如何被触发和进行。我们将在下一章详细展开。2.2 传输模式XFERMODE详解与选型策略XFERMODE字段定义了七种工作模式理解它们的区别是灵活运用μDMA的关键。停止Stop, 0x0通道未配置或配置无效传输停止。在初始化或重新配置前应确保模式为此值。基本模式Basic, 0x1最直观的模式。每次外设请求或软件请求触发一次μDMA就执行ARBSIZE所指定数量的传输。例如ARBSIZE4即8次传输那么每来一个请求就搬8个数据项直到总共完成XFERSIZE1个项。适用于需要外设频繁请求、数据流不连续的场景。自动请求模式Auto-Request, 0x2只需一次初始请求软件或外设触发μDMA就会自动完成整个XFERSIZE1个数据项的传输期间不再需要额外请求。这非常适合内存到内存的块搬运或者外设能够一次性提供大量数据的情况。乒乓模式Ping-Pong, 0x3高级双缓冲模式。该模式会同时使用主控和备用两个控制结构。假设主控结构指向缓冲区A备用结构指向缓冲区B。传输启动后控制器先用主结构A传输。当A传输完成立即产生中断并自动切换到备用结构B继续传输同时将主结构的XFERMODE改为Stop。在中断服务程序ISR中你处理完缓冲区A的数据后需要重新配置主结构例如指向一个新的缓冲区或重置参数并将其XFERMODE改回Ping-Pong。如此循环实现数据处理和传输的并行几乎无延迟。这是实现连续数据流如音频DAC输出、摄像头采集的黄金方案。内存分散-聚集模式Memory Scatter-Gather, 0x4与备用内存分散-聚集模式0x5用于执行一个由多个独立传输任务Task组成的链表。主控结构模式0x4的源地址指向一个任务描述符表每个描述符包含一个完整的备用控制结构。μDMA控制器会自动从表中读取一个任务到备用结构模式必须为0x5并执行完成后再读取下一个直到遇到一个模式不是0x5的任务为止。这允许你用一次设置完成一系列非连续地址的数据搬运。外设分散-聚集模式Peripheral Scatter-Gather, 0x6与备用外设分散-聚集模式0x7与内存分散-聚集类似但专为外设设计。区别在于备用结构0x7的每次传输需要外设为每个仲裁块ARBSIZE发出一次请求而不是一次性完成整个任务项。更适用于外设驱动的复杂传输序列。模式选择心得单次块传输用Auto-Request。外设驱动的流式数据用Basic。零延迟连续数据处理首选Ping-Pong。复杂、多目的地的传输序列考虑Scatter-Gather。3. 通道配置、使能与中断处理全流程实战理解了控制结构后我们来看如何让一个通道真正动起来。这个过程就像组装并启动一台机器放置图纸配置控制结构、接通电源使能控制器和通道、然后处理它完成工作后的汇报中断。3.1 通道配置与使能步骤假设我们要配置通道8使用Ping-Pong模式从ADC结果寄存器假设地址0x4003.8000传输到内存中的两个缓冲区adc_buffer_a[256]和adc_buffer_b[256]每个缓冲区存放256个16位的采样值。步骤1分配并初始化通道控制表首先我们需要在内存中通常是SRAM分配一块对齐的区域作为通道控制表。DMACTLBASE寄存器要求基地址必须1024字节对齐。我们可以静态定义// 确保控制表1024字节对齐。许多编译器支持此属性。 __attribute__((aligned(1024))) static uint32_t uDMA_ControlTable[256]; // 大小根据通道数定通常256字足够然后在初始化函数中设置基地址指针HWREG(UDMA_CTLBASE) (uint32_t)uDMA_ControlTable;步骤2填写主控和备用控制结构我们需要计算两个控制结构在表中的偏移。对于通道8主控结构偏移 通道号 * 0x10 8 * 16 128 字节。在uDMA_ControlTable数组中每个uint32_t是4字节所以索引偏移是 128 / 4 32。备用结构偏移 0x200 通道号 * 0x10 0x200 128 0x280 字节。数组索引为 0x280 / 4 160。接着填写结构以下为伪代码展示思路// 获取主控结构指针 tDMAControlTable *pPrimary (tDMAControlTable*)uDMA_ControlTable[32]; // 获取备用结构指针 tDMAControlTable *pAlternate (tDMAControlTable*)uDMA_ControlTable[160]; // 配置主控结构指向缓冲区A pPrimary-srcEndAddr (void*)0x40038000; // ADC数据寄存器地址不递增 pPrimary-dstEndAddr (void*)(adc_buffer_a 255); // 指向缓冲区A末尾半字递增 pPrimary-control UDMA_CHCTL_DSTINC_HALF | // 目的半字递增 UDMA_CHCTL_DSTSIZE_HALF | // 目的数据半字 UDMA_CHCTL_SRCINC_NONE | // 源不递增 UDMA_CHCTL_SRCSIZE_HALF | // 源数据半字 UDMA_CHCTL_ARBSIZE_64 | // 仲裁大小64项 ((256 - 1) 4) | // 传输大小255 UDMA_CHCTL_XFERMODE_PINGPONG; // 乒乓模式 // 配置备用结构指向缓冲区B pAlternate-srcEndAddr (void*)0x40038000; // 同上 pAlternate-dstEndAddr (void*)(adc_buffer_b 255); pAlternate-control UDMA_CHCTL_DSTINC_HALF | UDMA_CHCTL_DSTSIZE_HALF | UDMA_CHCTL_SRCINC_NONE | UDMA_CHCTL_SRCSIZE_HALF | UDMA_CHCTL_ARBSIZE_64 | ((256 - 1) 4) | UDMA_CHCTL_XFERMODE_PINGPONG;重要提示在写入control字段的最后才设置XFERMODE为非零值如PINGPONG。在初始化阶段应先将其清零Stop模式待所有参数配置完毕再启用传输模式防止误触发。步骤3使能μDMA控制器及通道首先必须确保μDMA模块的时钟已使能通过系统控制模块的RCGCUDMA寄存器。然后使能控制器主开关HWREG(UDMA_CFG) UDMA_CFG_MASTEN_ENABLE; // 设置DMACFG寄存器的MASTEN位接着使能具体的通道8HWREG(UDMA_ENASET) (1 8); // 设置DMAENASET寄存器的第8位至此通道配置完成处于就绪状态等待ADC外设发出DMA请求信号。3.2 中断处理程序ISR的编写逻辑当通道8完成一个缓冲区比如A的传输并切换到B时会产生中断。我们的ISR需要完成以下工作确定完成的是哪个缓冲区通过读取通道控制字中的XFERMODE字段来判断。在Ping-Pong模式下完成传输的那个控制结构的XFERMODE会被硬件自动改为Stop (0x0)。处理数据对已满的缓冲区进行数据处理例如计算均值、滤波、发送到下一级。重新武装缓冲区将已完成传输的控制结构重新配置指向新的或清空的缓冲区并将其XFERMODE改回Ping-Pong以便下一次传输。以下是中断处理程序的示例逻辑void UDMA_Channel8_ISR(void) { uint32_t ulStatus; // 1. 读取通道中断状态并清除标志可选取决于具体芯片的中断清除方式 ulStatus HWREG(UDMA_CHIS); // 读取DMA通道中断状态寄存器 if (ulStatus (1 8)) { // 2. 判断哪个缓冲区完成 // 读取主控结构控制字偏移需根据实际控制表基地址计算 tDMAControlTable *pPrimary ...; // 主结构地址 tDMAControlTable *pAlternate ...; // 备结构地址 uint32_t primaryControl pPrimary-control; uint32_t alternateControl pAlternate-control; // 检查XFERMODE字段最低3位 if ((primaryControl 0x7) 0) { // 主结构模式为Stop说明缓冲区A传输完成 // 3. 处理缓冲区A的数据 process_buffer(adc_buffer_a, 256); // 4. 重新武装主结构例如重置目的地址到缓冲区A开头 // 注意在乒乓模式下通常我们交换缓冲区角色这里假设简单重置 pPrimary-dstEndAddr (void*)(adc_buffer_a 255); // 重新设置控制字将模式改回PINGPONG primaryControl ~0x7; // 清除模式位 primaryControl | UDMA_CHCTL_XFERMODE_PINGPONG; pPrimary-control primaryControl; } if ((alternateControl 0x7) 0) { // 备结构模式为Stop说明缓冲区B传输完成 process_buffer(adc_buffer_b, 256); pAlternate-dstEndAddr (void*)(adc_buffer_b 255); alternateControl ~0x7; alternateControl | UDMA_CHCTL_XFERMODE_PINGPONG; pAlternate-control alternateControl; } // 清除该通道的中断标志具体寄存器可能是DMACHIS的写1清除位 HWREG(UDMA_CHIS) (1 8); // 写1清除第8通道中断 } // ... 可能还有其他通道中断需要处理 }关键点与避坑指南原子性操作在ISR中修改控制结构特别是control字时最好确保这是一个原子操作或者是在DMA传输不可能发生的时刻例如在判断和重新配置之间该通道的另一个缓冲区正在被使用是安全的因为硬件已切换。地址对齐确保源/目的地址符合数据大小的对齐要求例如32位传输要求地址4字节对齐。非对齐访问可能导致硬件错误或性能下降。传输大小限制单个XFERSIZE最大1024项。对于更大的传输需要结合Scatter-Gather或软件分多次启动。使能顺序务必先配置好控制表并使能控制器MASTEN最后再使能具体通道。关闭时顺序相反。4. 关键功能寄存器详解与应用场景除了通道控制结构μDMA控制器还有一组功能寄存器用于全局控制、状态查询和通道行为微调。理解它们能让你更精细地掌控DMA传输。4.1 配置与状态寄存器DMA配置寄存器DMACFG只有一个有效位MASTEN位0。写1使能整个μDMA控制器写0禁用。这是总开关。注意在访问任何μDMA寄存器前必须先使能其模块时钟并等待至少3个系统时钟周期。DMA状态寄存器DMASTAT提供控制器的全局状态。DMACHANS位20:16只读指示控制器支持的通道数减1。对于TM4C123此值通常为0x1F31表示有32个通道。STATE位7:4控制状态机当前状态。调试时非常有用可以查看DMA控制器是空闲Idle、正在读源数据Reading source data还是正在写目的数据Writing destination data等。MASTEN位0只读反映DMACFG.MASTEN的当前值。4.2 通道控制寄存器这些寄存器通常以“SET”和“CLR”成对出现通过写1到特定比特位来设置或清除对应通道的某个属性。寄存器名称偏移地址核心功能应用场景DMAUSEBURSTSET0x018设置某通道只响应突发Burst请求。当外设支持突发请求即一次请求可传输多个数据项时设置此位可以提升效率。如果剩余传输项数小于仲裁大小控制器会自动清除该位改用单次请求完成。DMAUSEBURSTCLR0x01C清除对应通道的USEBURST设置使其响应单次和突发请求。手动恢复通道对单次请求的响应。DMAREQMASKSET0x020屏蔽指定通道的外设DMA请求。当你希望该通道仅用于软件触发传输时屏蔽外设请求。例如进行内存到内存的复制。DMAREQMASKCLR0x024清除屏蔽允许外设请求。在软件传输完成后重新允许外设接管。DMAENASET0x028使能指定通道。通道配置完成后最后一步就是写此寄存器使能通道使其可以响应请求。DMAENACLR0x02C禁用指定通道。传输完成或需要停止通道时使用。传输完成时硬件也会自动清除使能位。DMAALTSET0x030强制通道使用备用控制结构。在Ping-Pong模式初始化后可以手动设置此位来指定从哪个缓冲区开始。通常由硬件自动管理。DMAALTCLR0x034强制通道使用主控控制结构。手动切换回主结构。DMAPRIOSET0x038设置通道为高优先级。当多个通道同时请求时高优先级通道优先获得服务。用于保障关键外设如高速ADC的数据不被丢失。DMAPRIOCLR0x03C清除通道的高优先级设置。软件请求寄存器DMASWREQ, 0x014这是一个非常有用的寄存器。向某一位写1会为该通道产生一个软件DMA请求就像外设发出请求一样。这让你可以手动启动任何配置好的DMA传输无论其请求是否被屏蔽。常用于内存到内存的传输测试或在特定时刻触发一次采集。4.3 通道映射寄存器DMACHMAPn这是一个强大的功能允许你重新映射外设到不同的μDMA通道。芯片出厂时每个外设如UART0 RX、ADC0 SS0都固定连接到一个特定的通道参见数据手册的“Channel Assignments”表。但通过DMACHMAP0~DMACHMAP3这四个寄存器你可以改变这种固定关联。每个寄存器管理8个通道的映射每个通道用4个比特位表示。这4位值指定了实际服务于该通道的“请求源”编号。例如默认情况下通道0可能映射给ADC0 SS0请求源编号假设为0x0。你可以通过编程将通道0映射给UART0 RX请求源编号0x1。应用场景冲突解决当两个高优先级外设默认分配到同一个DMA通道时分复用但你希望它们能同时使用DMA时可以将其中一个重映射到一个空闲通道。优先级管理将一个重要外设重映射到一个具有更高仲裁优先级的通道号通常低通道号有更高优先级。灵活性使软件设计不再受硬件固定连接的束缚。操作注意修改通道映射通常应在所有相关DMA通道禁用、且无进行中传输时进行。5. 高级应用模式与性能优化技巧掌握了基础配置和寄存器操作后我们可以探索一些高级用法和优化策略让μDMA发挥最大效能。5.1 Ping-Pong模式实现零延迟数据流如前所述Ping-Pong模式是处理连续流数据的利器。其核心思想是双缓冲DMA在向缓冲区A填充数据时CPU可以处理缓冲区B中的数据反之亦然。实现的关键在于中断服务程序ISR必须高效、快速。优化技巧ISR最小化在ISR中只做最必要的工作——判断缓冲区、设置数据就绪标志、重新武装DMA控制结构。复杂的数据处理应放到主循环或低优先级任务中基于标志位进行。缓冲区大小与ARBSIZE的权衡缓冲区大小最好是ARBSIZE的整数倍。例如ARBSIZE设置为64即一次突发传输64项缓冲区大小为256项这样每次中断对应4次完整的突发传输效率最高。如果缓冲区大小不是其整数倍最后一次传输会以单次请求形式完成可能略微影响时序。使用NXTUSEBURST位在控制字的NXTUSEBURST位。如果设置此位即使在最后一次传输剩余项数小于ARBSIZE时控制器也会尝试使用突发传输。这可以保证传输的突发连续性但要求外设支持。5.2 使用Scatter-Gather处理复杂传输链对于需要从多个非连续源地址向多个非连续目的地址传输数据的场景手动配置多次DMA传输很繁琐。Scatter-Gather模式可以解决这个问题。操作流程在内存中创建一个“任务描述符”数组。每个描述符就是一个完整的μDMA通道控制结构DMASRCENDP,DMADSTENDP,DMACHCTL。将主控结构的源地址指向这个任务描述符数组的起始地址目的地址指向备用控制结构所在的内存地址传输模式设置为Memory Scatter-Gather (0x4)传输大小设置为任务描述符的大小以数据项计。将备用控制结构的传输模式设置为Alternate Memory Scatter-Gather (0x5)并配置好第一次实际传输的参数源、目的、大小等。启动传输。μDMA会使用主结构将第一个任务描述符从数组“搬运”到备用结构中然后备用结构开始执行这个实际的DMA传输。第一个任务完成后硬件会自动用主结构搬运第二个任务描述符到备用结构并继续执行如此循环直到遇到一个XFERMODE不是0x5的描述符为止。这非常适合将一幅图像的多个位平面分散存储搬运到LCD显存的连续区域。从多个不同的传感器寄存器读取数据到一的数据包缓冲区。5.3 性能调优与常见问题排查1. 总线竞争与仲裁优先级μDMA与CPU、其他总线主设备共享系统总线。频繁的DMA传输可能阻塞CPU访问Flash或SRAM导致CPU性能下降。优化策略合理设置ARBSIZE增大ARBSIZE让DMA单次占用总线时间变长整体效率高但可能增加CPU的访问延迟。减小ARBSIZE则相反。需要根据系统实时性要求权衡。利用通道优先级通过DMAPRIOSET为关键数据通道设置高优先级。调整存储器加速模块确保芯片的存储器加速模块如预取指、缓存已使能可以缓解总线竞争的影响。2. 传输错误与调试总线错误如果DMA试图访问无效的或受保护的内存地址会触发总线错误BusFault。检查源/目的地址指针是否正确是否越界。传输未完成/中断不触发检查DMAENASET和DMACFG.MASTEN是否已使能。检查外设的DMA请求是否已使能例如UART的DMACTL寄存器。检查DMAREQMASKSET是否意外屏蔽了该通道的请求。使用调试器查看DMASTAT寄存器的STATE字段确认DMA状态机是否在运行。检查通道控制结构中的XFERMODE是否已正确设置为非Stop值。数据错位或损坏地址对齐确保SRCINC/DSTINC与SRCSIZE/DSTSIZE匹配且地址符合对齐要求。缓冲区溢出确保XFERSIZE设置正确且目的缓冲区足够大。时钟问题确保μDMA和外设的时钟都已使能且稳定。3. 低功耗模式下的考虑在微控制器进入深度睡眠时系统时钟可能关闭DMA传输会停止。如果需要在低功耗模式下维持DMA例如从低速ADC采样则需确保DMA时钟源如内部低速振荡器在睡眠模式下仍然有效并配置相应的功耗模式。6. 实战案例配置ADC序列采样与DMA传输让我们结合一个具体案例将上述所有知识点串联起来使用Tiva TM4C123的ADC0序列采样器Sequencer和μDMA实现连续采集4个模拟通道并通过Ping-Pong模式将数据存入内存。目标ADC0序列采样器SS3以1Msps速率循环采样AIN0-AIN3四个通道通过μDMA通道8ADC0 SS3的默认DMA通道将数据搬运到内存中的双缓冲区。步骤初始化系统与引脚使能ADC0和μDMA模块时钟配置AIN0-AIN3对应的GPIO引脚为模拟输入。配置ADC采样序列// 选择采样序列SS3配置为软件触发优先级0 ADCSequenceConfigure(ADC0_BASE, 3, ADC_TRIGGER_PROCESSOR, 0); // 为SS3的4个步进分别配置采样通道AIN0, AIN1, AIN2, AIN3 ADCSequenceStepConfigure(ADC0_BASE, 3, 0, ADC_CTL_CH0); ADCSequenceStepConfigure(ADC0_BASE, 3, 1, ADC_CTL_CH1); ADCSequenceStepConfigure(ADC0_BASE, 3, 2, ADC_CTL_CH2); ADCSequenceStepConfigure(ADC0_BASE, 3, 3, ADC_CTL_CH3 | ADC_CTL_IE | ADC_CTL_END); // 使能ADC0 SS3的DMA请求 ADCSequenceDMAEnable(ADC0_BASE, 3); // 使能采样序列SS3 ADCSequenceEnable(ADC0_BASE, 3);分配与初始化μDMA控制表及缓冲区__attribute__((aligned(1024))) static uint32_t uDMA_CtrlTable[256]; static uint16_t adc_ping_buffer[4 * 256]; // 4通道 * 256次采样 static uint16_t adc_pong_buffer[4 * 256];配置μDMA通道8为Ping-Pong模式// 设置控制表基地址 HWREG(UDMA_CTLBASE) (uint32_t)uDMA_CtrlTable; // 获取主/备结构指针通道8 tDMAControlTable *pPri (tDMAControlTable*)uDMA_CtrlTable[8 * 4]; // 8通道 * 4字/通道 tDMAControlTable *pAlt (tDMAControlTable*)uDMA_CtrlTable[(8 * 4) (0x200 / 4)]; // 配置主结构指向ping缓冲区 pPri-srcEndAddr (void*)(ADC0_BASE ADC_O_SSFIFO3); // ADC FIFO地址 pPri-dstEndAddr (void*)(adc_ping_buffer[4*256 - 1]); // 指向缓冲区末尾 pPri-control UDMA_CHCTL_DSTINC_HALF | // 目的地址半字递增 UDMA_CHCTL_DSTSIZE_HALF | UDMA_CHCTL_SRCINC_NONE | // ADC FIFO地址固定 UDMA_CHCTL_SRCSIZE_HALF | // ADC数据为12位存储在16位FIFO中 UDMA_CHCTL_ARBSIZE_16 | // 仲裁大小16项 ((4*256 - 1) 4) | // 传输总数4通道*256次 -1 UDMA_CHCTL_XFERMODE_PINGPONG; // 配置备结构指向pong缓冲区参数类似仅目的地址不同 pAlt-srcEndAddr (void*)(ADC0_BASE ADC_O_SSFIFO3); pAlt-dstEndAddr (void*)(adc_pong_buffer[4*256 - 1]); pAlt-control ... // 与主结构相同的控制字模式也为PINGPONG使能μDMA控制器与通道配置中断// 使能μDMA控制器 HWREG(UDMA_CFG) UDMA_CFG_MASTEN_ENABLE; // 使能通道8 HWREG(UDMA_ENASET) (1 8); // 配置μDMA中断使能通道8传输完成中断 // ... (依赖具体的中断控制器配置如NVIC)编写中断服务程序如前文所述在ISR中判断完成的缓冲区处理数据如求平均、发送到上位机并重新武装对应的控制结构。启动传输通过软件触发ADC序列采样或配置定时器触发。一旦ADC开始转换并产生数据DMA传输便会自动开始。ADCProcessorTrigger(ADC0_BASE, 3); // 软件触发一次 // 或者配置定时器周期性触发ADC通过这个案例你可以看到一个高效的实时数据采集系统是如何构建的。CPU几乎不参与数据搬运只在缓冲区满时被中断通知去处理数据从而有充足的时间运行复杂的控制算法或通信协议。这正是μDMA在嵌入式系统中的核心价值所在。