CC323x DMA寄存器深度解析:从原理到实战配置与调试 1. 项目概述从CPU的“搬运工”到系统性能的“加速器”在嵌入式系统开发中尤其是面对CC323x这类集成了Wi-Fi功能的微控制器时我们常常需要处理大量的数据流比如从UART接收传感器数据、通过SPI读写Flash、或者最典型的——在Wi-Fi射频模块和系统内存之间搬运网络数据包。如果这些数据搬运工作全部交给CPU通过“读取-处理-写入”的循环来完成CPU的算力将被大量消耗在简单的复制操作上导致系统响应变慢、功耗增加甚至无法处理实时性要求高的任务。这时候DMA直接内存访问技术就从一个“好用的功能”变成了“不可或缺的核心”。我接触过不少项目初期为了快速验证功能都采用CPU轮询或中断搬运数据在小数据量时看似没问题。一旦数据吞吐量上来比如Wi-Fi持续传输视频流或音频流系统立马“卡壳”CPU占用率飙升。后来引入DMA进行优化性能提升往往是数量级的。DMA的本质是系统内部的一个“专职快递员”。CPU这个“老板”只需要告诉快递员DMA控制器取货地址源地址、送货地址目的地址、货物数量传输量和打包方式传输宽度、突发模式就可以去处理其他更重要的“商务决策”应用逻辑计算了。快递员会自己完成整个搬运流程搬完后才敲门触发中断通知老板“任务完成”。TI SimpleLink™ CC323x系列芯片的DMA控制器就是这个一个高度专业化、可配置的“快递中心”。它支持多达32个独立的“快递通道”DMA Channel每个通道可以服务一个不同的外设如UART、SPI、ADC等。而配置和管理这个“快递中心”的核心就是一系列内存映射寄存器。理解这些寄存器就像拿到了快递中心的“管理后台”权限你能精确调度每一个快递员的工作模式、优先级和路线。本文就将深入这个“后台”结合CC323x的技术手册不仅告诉你每个寄存器是干什么的更会分享在实际配置中“为什么”要这么设置以及我踩过的一些“坑”。2. DMA控制器架构与CC323x实现特点在深入寄存器细节之前我们需要先建立对CC323x DMA控制器整体架构的认知。这有助于理解后续每个寄存器配置的意图和它们之间的关联。2.1 核心工作流程与“控制表”概念CC323x的DMA控制器采用了一种非常典型且高效的“描述符”或“控制表”架构。这是理解其所有寄存器功能的关键。你可以把这个“控制表”想象成快递中心给每个快递员DMA通道准备的任务工单。这个工单Channel Control Structure并不在DMA控制器内部的固定存储区而是由程序员在系统内存SRAM中任意位置定义的一个数据结构。这个设计非常巧妙它带来了极大的灵活性动态管理可以运行时创建、修改或销毁任务工单。链式任务一个工单可以指向下一个工单的地址从而实现复杂的“分散-聚集”Scatter-Gather传输即把不连续的多块内存数据通过一次DMA设置搬运到另一个不连续的目的地。乒乓缓冲可以定义两套工单主用和备用当DMA正在执行主用工单传输时CPU可以准备备用工单的数据实现无缝连续传输零延迟切换。这个工单里具体包含了哪些信息呢虽然技术手册的4.3.4节主要描述的是DMA控制器本身的寄存器但控制表的结构是其灵魂。一个典型的控制表条目通常包括源地址指针数据从哪里取。目的地址指针数据送到哪里去。传输数量要搬多少数据单位可以是字节、半字、字。控制字定义传输的数据宽度8/16/32位、地址递增模式、传输完成后的行为是否产生中断、是否自动加载下一个工单等。而DMA控制器内部的两个关键寄存器DMA_CTLBASE和DMA_ALTBASE就是用来告诉DMA控制器“所有快递员的工单表放在内存的哪个地址”DMA_CTLBASE以及“备用工单表又放在哪里”DMA_ALTBASE。DMA_CTLBASE指向的地址必须1024字节对齐这是硬件设计的要求确保了访问效率。2.2 通道管理与仲裁机制CC323x的DMA支持32个通道。但并不是所有通道在任何时刻都能工作。通道的启用、暂停、优先级和请求响应模式都需要通过寄存器精细控制。通道使能DMA_ENASET和DMA_ENACLR寄存器用于独立地启用或禁用每个通道。一个通道只有在使能后才会响应传输请求。这里有个关键点即使通道使能了如果它的请求被屏蔽了通过DMA_REQMASKSET它依然不会响应外设的硬件请求但可以被软件请求DMA_SWREQ触发。这为灵活控制传输时机提供了可能。优先级控制DMA_PRIOSET和DMA_PRIOCLR寄存器可以为每个通道设置高优先级。当多个通道同时发出请求时仲裁器会优先服务高优先级通道。这在处理音频高实时性和日志打印低实时性同时需要DMA时非常有用。请求模式DMA_USEBURSTSET和DMA_USEBURSTCLR决定了通道是响应“单次请求”还是“突发请求”。这需要和外设配合。有些外设如某些模式的SPI每准备好一个数据就产生一个请求单次而有些如内存到内存传输则希望一次性请求传输一整块数据突发。设置不当会导致传输效率低下甚至失败。2.3 外设与通道的映射DMA_CHMAPx寄存器这是CC323x DMA设计中一个非常强大的功能但也容易让人困惑。芯片内部有多个可能产生DMA请求的外设如UARTA0, UARTA1, SPIA0, I2C等但DMA通道只有32个。DMA_CHMAP0到DMA_CHMAP3这4个寄存器每个管理8个通道就是用来定义哪个外设事件连接到哪个DMA通道。每个通道如通道0在DMA_CHMAP0寄存器中对应一个4位的字段CH0SEL_n。这个4位值就是一个“选择码”指向一个特定的外设请求源。具体哪个码对应哪个外设需要查阅CC323x数据手册的“DMA Channel Mapping”表格。一个常见的误区是以为一个外设只能固定用一个通道。实际上通过配置DMA_CHMAPx你可以动态地将例如UARTA0的发送请求分配给通道0而将其接收请求分配给通道1从而实现全双工DMA传输。这种灵活性对于优化复杂系统的DMA资源分配至关重要。3. 核心寄存器功能深度解析与配置实战了解了架构我们就可以逐个拆解那些关键的寄存器了。手册里列出了20多个寄存器我们挑出最核心、最常用的几个结合代码片段讲解如何配置。3.1 全局控制与状态寄存器3.1.1 DMA_CFGDMA控制器的总开关这是整个DMA模块的“总闸”。其最低位MASTENMaster Enable控制DMA控制器的全局开关。// 假设已定义DMA_BASE为0x400FF000 #define DMA_BASE 0x400FF000 #define DMA_CFG_OFFSET 0x004 // 启用DMA控制器 HWREG(DMA_BASE DMA_CFG_OFFSET) | 0x00000001; // 设置MASTEN位为1 // 禁用DMA控制器 HWREG(DMA_BASE DMA_CFG_OFFSET) ~0x00000001; // 清除MASTEN位重要提示技术手册明确提到在访问任何DMA模块寄存器之前必须确保DMA模块时钟已使能并且在时钟使能后需要等待至少3个系统时钟周期。在实际编程中我们通常通过调用TI驱动库的API如PRCMPeripheralClkEnable()来使能外设时钟库函数内部会处理好必要的延迟。如果直接操作寄存器务必手动插入等待。3.1.2 DMA_STAT洞察控制器内部状态这是一个只读寄存器用于诊断和监控。其中几个字段非常有用DMACHANS(Bits 20-16)指示控制器支持的通道数减1。读出的值如果是0x1F十进制31则表示支持32个通道。这个值在芯片设计时固定但读取它可以作为驱动初始化时验证硬件配置的依据。STATE(Bits 7-4)显示DMA控制器内部状态机的当前状态。状态从0空闲到9完成描述了DMA控制器当前正在进行的操作例如“正在读取源数据”4或“正在写入目的数据”5。这个寄存器在调试复杂的DMA传输错误时极其有用。如果DMA传输卡住读取STATE可以知道它卡在了哪个环节。MASTEN(Bit 0)反映DMA_CFG中MASTEN位的当前状态用于确认总开关是否已打开。3.2 通道控制寄存器组Set与Clear的配对设计你会发现很多寄存器都是成对出现的XXXSET和XXXCLR。这种设计是ARM Cortex-M系列芯片外设的常见模式目的是实现原子性的位操作避免“读-改-写”过程被中断打断可能造成的数据竞争问题。DMA_ENASET/DMA_ENACLR通道使能开关。向DMA_ENASET的bit n写入1使能通道n。向DMA_ENACLR的bit n写入1禁用通道n。读取DMA_ENASET可以获取所有通道的当前使能状态。// 使能通道0和通道2 HWREG(DMA_BASE DMA_ENASET_OFFSET) (1 0) | (1 2); // 仅禁用通道2 HWREG(DMA_BASE DMA_ENACLR_OFFSET) (1 2); // 读取通道使能状态 uint32_t enabled_channels HWREG(DMA_BASE DMA_ENASET_OFFSET);DMA_REQMASKSET/DMA_REQMASKCLR外设请求掩码。设置DMA_REQMASKSET的bit n为1将屏蔽通道n的外设硬件请求。此时该通道只能通过软件触发DMA_SWREQ。这个功能常用于软件控制的单次传输或调试。例如你想手动触发一次DMA传输来测试路径可以先屏蔽硬件请求然后配置好通道最后向DMA_SWREQ写1来启动。DMA_PRIOSET/DMA_PRIOCLR通道优先级设置。默认所有通道优先级相同采用类似轮询的仲裁。将某个通道设为高优先级后当它和普通优先级通道同时请求时它会优先得到服务。使用心得不要滥用高优先级。如果多个通道都设为高优先级它们之间又会竞争。通常只将最实时、最不能容忍延迟的通道如音频DAC的填充请求设为高优先级。DMA_ALTSET/DMA_ALTCLR主用/备用控制结构选择。这个寄存器通常不需要手动操作。当你在控制表中配置了Ping-Pong或Scatter-Gather模式时DMA控制器会在一次传输完成后自动切换这个位从而指向下一组控制结构备用表。手动操作它可能会打乱DMA控制器的内部状态管理。3.3 软件请求与等待状态寄存器DMA_SWREQ软件请求寄存器。向该寄存器的某个bit写1会立即对相应通道产生一个DMA传输请求就像外设发出了一个请求一样。这个请求是“一次性”的传输完成后该bit会自动清零。注意该寄存器是只写的读取它没有意义。// 手动触发通道5的DMA传输 HWREG(DMA_BASE DMA_SWREQ_OFFSET) (1 5); // 注意无需手动清零该位传输完成后硬件自动清零。DMA_WAITSTAT等待状态寄存器。这是一个只读寄存器每一位表示对应通道是否正在“等待请求”。这是什么意思在某些高性能传输场景外设可以通知DMA“我暂时没准备好你先别发突发请求”。当外设拉低这个信号对应通道的WAITREQ_n位就会置1DMA会暂停向该外设发起突发传输直到外设准备好。这个机制是为了防止DMA以过高速度“淹没”尚未就绪的外设是提升系统稳定性的重要设计。在调试时如果发现某个通道的传输意外停止可以查一下这个寄存器看是否是外设端出现了“未就绪”状态。3.4 错误处理与通道映射DMA_ERRCLR总线错误清除寄存器。如果DMA控制器在传输过程中访问了一个无效的地址例如访问了未使能的内存区域或外设就会发生总线错误并在此寄存器的ERRCLR位bit 0上体现。一旦发生总线错误出错的通道会被硬件自动禁用以防止错误扩散。其他通道不受影响。处理流程通常是读取DMA_ERRCLR确认错误发生。检查出错通道的控制表修正错误的源/目的地址。向DMA_ERRCLR寄存器的ERRCLR位写1以清除错误标志这是一个W1C位写1清零。重新使能该通道如果需要。if (HWREG(DMA_BASE DMA_ERRCLR_OFFSET) 0x01) { // 1. 发生了总线错误 // 2. 这里添加调试代码检查通道配置尤其是地址 // 3. 清除错误标志 HWREG(DMA_BASE DMA_ERRCLR_OFFSET) 0x01; // 4. 例如重新初始化通道0 // ... 重新配置通道0控制表 ... HWREG(DMA_BASE DMA_ENACLR_OFFSET) (1 0); // 先确保禁用 // ... 可能需要重新设置DMA_CTLBASE等 ... HWREG(DMA_BASE DMA_ENASET_OFFSET) (1 0); // 重新使能 }DMA_CHMAPx与DMA_CHASGN通道映射与选择。这是配置的难点。DMA_CHMAP0-DMA_CHMAP3负责将物理通道0-31映射到具体的外设请求源如UARTA0_TXUARTA0_RX。DMA_CHASGN寄存器则允许你在“主映射”和“次映射”两套映射方案间切换。这为动态重定向DMA通道提供了可能但绝大多数应用只使用主映射DMA_CHASGN所有位为0。配置DMA_CHMAPx时必须严格参照数据手册中的映射表。例如要将UARTA0的发送请求映射到通道0接收请求映射到通道1// 假设根据数据手册UARTA0_TX的请求源编码是0x0A, UARTA0_RX是0x0B #define UARTA0_TX_SRC 0x0A #define UARTA0_RX_SRC 0x0B // DMA_CHMAP0控制通道0-7。每个通道占4bit。 // 配置通道0使用UARTA0_TX作为请求源 uint32_t chmap0_val HWREG(DMA_BASE DMA_CHMAP0_OFFSET); chmap0_val ~(0xF 0); // 清零通道0的4bit字段 (bits 3:0) chmap0_val | (UARTA0_TX_SRC 0); // 设置源编码 // 配置通道1使用UARTA0_RX作为请求源 chmap0_val ~(0xF 4); // 清零通道1的4bit字段 (bits 7:4) chmap0_val | (UARTA0_RX_SRC 4); // 设置源编码 HWREG(DMA_BASE DMA_CHMAP0_OFFSET) chmap0_val;4. CC323x DMA配置完整实战流程与代码剖析理论说再多不如一行代码。下面我们以一个具体的例子讲解如何在CC323x上配置DMA实现从内存数组到UART的自动发送。4.1 场景设定与准备工作目标使用DMA通道0将一段存储在SRAM中的字符串“Hello DMA!”通过UARTA0自动发送出去无需CPU参与数据搬运。前提系统时钟、UART外设时钟、DMA控制器时钟已正确初始化通常通过TI驱动库完成。UARTA0已初始化配置为合适的波特率、数据位、停止位等。已了解UARTA0的发送FIFO和DMA请求触发条件例如当发送FIFO有空位时产生DMA请求。4.2 步骤一定义并初始化DMA控制表这是最关键的一步。我们需要在内存中分配一个对齐的空间作为控制表。由于CC323x的DMA控制表条目结构是芯片定义的我们需要按照其要求定义数据结构。通常TI的驱动程序或更底层的内核软件如TI-RTOS的UDMA驱动会提供这个结构体。这里我们展示其原理。#include stdint.h #include stdbool.h // 假设的DMA控制表条目结构具体字段偏移需参考TRM typedef struct _DMA_ControlTableEntry { uint32_t srcEndAddr; // 源数据结束地址 (指向最后一个数据后的地址) uint32_t dstEndAddr; // 目的地址结束地址 uint32_t controlWord; // 控制字包含传输数量、数据宽度、地址模式等 // ... 可能还有其他字段如链接到下一个描述符的指针 } DMA_ControlTableEntry; // 为通道0分配控制表条目。通常需要对齐到一定边界如32字节这里简化为普通变量。 // 在实际使用中应使用特定对齐指令如GCC的 __attribute__((aligned(32))) DMA_ControlTableEntry dmaControlTable __attribute__((aligned(1024))); // 注意1024字节对齐要求 // 待发送的数据 const char transmitData[] Hello DMA!\r\n; uint32_t dataLength sizeof(transmitData) - 1; // 减去末尾的\0 void initDMAControlTable(void) { // 1. 设置源地址我们的数据在内存中 dmaControlTable.srcEndAddr (uint32_t)(transmitData dataLength); // 结束地址 起始地址 长度 // 2. 设置目的地址UARTA0的数据寄存器 (假设地址为UARTA0_DATA_REG) #define UARTA0_DATA_REG 0x4000C000 // 示例地址需查手册确认 dmaControlTable.dstEndAddr (uint32_t)(UARTA0_DATA_REG); // 3. 配置控制字 (这是最复杂的一步需要根据TRM逐位设置) // 假设控制字格式为[传输数量] | [目的地址增量模式] | [源地址增量模式] | [数据宽度] | ... // 例如传输dataLength个字节源地址递增目的地址不变外设寄存器数据宽度8位使能中断... uint32_t ctrl 0; ctrl | (dataLength 0); // 假设bits [15:0]是传输数量 ctrl | (0x1 26); // 假设bit26控制源地址递增 (1递增) ctrl | (0x0 27); // 假设bit27控制目的地址递增 (0不变) ctrl | (0x0 28); // 假设bits[29:28]定义数据大小 (008位字节) ctrl | (0x1 30); // 假设bit30使能传输完成中断 // ... 其他位根据需求设置 dmaControlTable.controlWord ctrl; }4.3 步骤二配置DMA控制器全局与通道寄存器void configureDMAChannel(void) { // 0. 确保DMA时钟已使能并等待稳定通常由驱动库完成 // PRCMPeripheralClkEnable(PRCM_DMA, PRCM_RUN_MODE_CLK); // 1. 设置控制表基址寄存器 (DMA_CTLBASE) // 地址必须1024字节对齐我们的dmaControlTable已对齐。 HWREG(DMA_BASE DMA_CTLBASE_OFFSET) (uint32_t)dmaControlTable; // 2. 配置通道映射 (DMA_CHMAP0): 将UARTA0_TX请求源映射到通道0 uint32_t chmap0 HWREG(DMA_BASE DMA_CHMAP0_OFFSET); chmap0 ~(0xF 0); // 清零通道0的映射字段 chmap0 | (UARTA0_TX_SRC 0); // 设置映射 HWREG(DMA_BASE DMA_CHMAP0_OFFSET) chmap0; // 3. 可选配置通道为高优先级 // HWREG(DMA_BASE DMA_PRIOSET_OFFSET) (1 0); // 4. 可选配置通道使用突发请求模式如果UART支持 // 通常UART是单字节请求所以这里不设置使用默认的单次/突发皆可模式。 // HWREG(DMA_BASE DMA_USEBURSTSET_OFFSET) (1 0); // 5. 清除任何可能存在的通道使能和错误状态 HWREG(DMA_BASE DMA_ENACLR_OFFSET) (1 0); // 禁用通道0 HWREG(DMA_BASE DMA_ERRCLR_OFFSET) 0x01; // 清除总线错误标志如果是1 // 6. 使能DMA控制器主开关 HWREG(DMA_BASE DMA_CFG_OFFSET) | 0x01; // 7. 使能通道0 HWREG(DMA_BASE DMA_ENASET_OFFSET) (1 0); }4.4 步骤三启动传输与中断处理配置完成后DMA通道已经就绪等待请求。对于UART发送我们需要先确保UART本身的DMA发送功能已启用这通常在UART的配置寄存器中例如使能TX DMA。一旦UART的发送FIFO有空位它就会向映射好的DMA通道0发出请求。我们也可以手动发起一次软件请求来启动传输适用于内存到内存等没有硬件请求信号的场景// 手动启动通道0的传输对于UART TX通常由硬件自动请求此步非必须 HWREG(DMA_BASE DMA_SWREQ_OFFSET) (1 0);当DMA传输完成即dataLength个字节全部搬完后如果我们在控制字中使能了完成中断就会触发DMA中断。我们需要在中断服务程序ISR中处理// DMA中断服务例程 (假设中断号已正确配置和使能) void DMA_IRQHandler(void) { // 1. 检查是哪个通道触发的中断通常有状态寄存器指示这里简化 // 2. 处理传输完成后的工作例如 // - 设置一个软件标志通知主循环“发送完成”。 // - 如果使用Ping-Pong缓冲切换缓冲区并重新配置DMA控制表。 // - 清除DMA中断标志具体寄存器请查手册。 // 示例设置完成标志 extern volatile bool dmaTransferComplete; dmaTransferComplete true; // 3. 清除中断源非常重要否则会持续进入中断 // 通常需要操作特定的中断清除寄存器例如 // HWREG(DMA_BASE DMA_IRQ_CLR_REG) (1 0); // 清除通道0中断 }5. 常见问题排查与调试技巧实录即使按照手册配置DMA也常常是调试的“重灾区”。以下是我在实际项目中总结的几个典型问题和排查思路。5.1 问题一DMA传输完全没有启动症状数据没有移动外设没有反应CPU也没有收到中断。排查清单时钟检查确认DMA控制器和外设如UART的时钟是否已经使能这是最容易被忽略的第一步。使用调试器读取相关外设时钟使能寄存器确认。主开关检查DMA_CFG寄存器的MASTEN位是否为1通道使能检查DMA_ENASET寄存器中对应通道的位是否为1请求屏蔽检查DMA_REQMASKSET寄存器中对应通道的位是否为0即未屏蔽如果被屏蔽只有软件请求能触发。控制表地址检查DMA_CTLBASE寄存器设置的值是否正确是否1024字节对齐可以用调试器查看该地址内存的内容确认你写的控制表数据结构是否被正确写入。外设DMA使能很多外设有独立的DMA请求使能位。例如UART需要配置其控制寄存器来使能TX DMA或RX DMA。只配置DMA端不开启外设端的DMA请求是常见错误。硬件请求信号如果依赖硬件请求用逻辑分析仪或示波器检查外设的DMA请求信号线是否有效触发。5.2 问题二DMA传输部分数据后停止或传输数据量不对症状只传输了部分数据或者传输的数据量远大于/小于预期。排查清单控制字配置重点检查控制表中的控制字。传输数量字段是否正确数据宽度8/16/32位是否与外设寄存器宽度匹配例如向32位外设寄存器传输8位数据时如果设置成32位宽度会导致一次写入4字节可能覆盖相邻寄存器。地址递增模式源地址递增和目的地址递增模式设置是否正确对于外设寄存器如UART数据寄存器目的地址通常应设为非递增。对于内存到内存的传输双方通常都需要递增。缓冲区溢出/下溢检查源和目的缓冲区的大小是否足够。DMA可不会帮你检查数组越界它会忠实地按照你给的地址和数量搬运数据即使会覆盖其他重要数据。仲裁与优先级如果多个DMA通道同时工作低优先级通道可能被高优先级通道持续抢占导致其传输看似“卡住”或极慢。检查DMA_PRIOSET和通道使能情况。使用DMA_WAITSTAT如果外设使用了“等待请求”功能传输可能会暂停。读取DMA_WAITSTAT寄存器查看对应通道位是否为1。5.3 问题三系统进入总线错误HardFault症状DMA启动后系统很快触发HardFault。排查清单立即检查DMA_ERRCLR寄存器如果ERRCLR位为1说明DMA访问了非法地址。这是最直接的证据。检查地址仔细核对控制表中的源结束地址和目的结束地址。确保源地址指向有效的、可读的内存区域如SRAM Flash。目的地址指向有效的、可写的外设寄存器或内存区域。对于外设寄存器地址务必使用从数据手册查到的物理地址或经过MMU映射后的正确地址。内存保护单元MPU如果系统启用了MPU确保DMA试图访问的内存区域在MPU配置中具有正确的访问权限如可读、可写。DMA作为总线主机同样受MPU规则约束。缓存一致性如果源或目的地址位于带有缓存的内存区域如CC323x的某些RAM可能被配置为可缓存在DMA操作前后需要执行缓存维护操作Clean Invalidate以确保DMA看到的是最新数据CPU也能看到DMA写入的结果。忘记处理缓存一致性是导致数据错误的最隐蔽原因之一。5.4 调试技巧利用DMA_STAT寄存器当DMA行为异常时DMA_STAT寄存器是你的第一站。STATE字段如果传输卡住看看状态机停在了哪个状态如0x8表示“Stalled”。停滞状态可能意味着它正在等待一个永远不会到来的请求或响应。MASTEN字段确认控制器是否真的已启用。DMACHANS字段验证硬件支持的通道数是否符合预期。一个实用的调试流程在DMA初始化后和启动前在调试器中设置一个数据观察点Data Watchpoint或内存访问断点地址设为你的DMA目的地址。当DMA第一次向该地址写入数据时CPU会暂停此时你可以检查所有DMA相关寄存器和内存中的控制表一切配置都将是“现场状态”比单步跟踪代码有效得多。6. 高级应用模式Ping-Pong与Scatter-Gather对于需要连续、零延迟处理数据流的应用如音频采集/播放、图像处理基础的单次DMA传输不够用。CC323x的DMA支持更高级的模式。6.1 Ping-Pong乒乓模式这种模式使用主用和备用两套控制表通过DMA_ALTBASE指向备用表基址。工作流程DMA首先使用主用控制表进行传输。传输完成后自动切换DMA_ALTSET标志位开始使用备用控制表进行下一次传输同时触发中断。CPU角色在中断中CPU处理刚刚被DMA填满的数据例如对音频数据进行滤波同时为刚刚被DMA取空的主用控制表重新填充新的源/目的地址或数据缓冲区。优势实现了数据传输和数据处理的重叠几乎没有缓冲区切换的延迟非常适合实时流处理。配置关键需要正确初始化两个控制表条目。在控制字的模式字段中启用“Ping-Pong”或“自动切换”功能具体位需查TRM。DMA_ALTBASE寄存器需要指向备用控制表的起始地址。6.2 Scatter-Gather分散-聚集模式这种模式允许一个DMA通道处理一段不连续的数据传输任务。它通过在一个控制表条目中设置“下一个控制表描述符的地址”链表指针来实现。工作流程DMA完成当前描述符定义的传输后不是结束而是自动加载链表指针指向的下一个描述符并开始新的传输。如此重复直到某个描述符中标记“传输结束”。应用场景将多个分散在内存中的小数据包如网络协议栈的多个数据帧一次性搬运到一块连续的发送缓冲区或者从一块连续的接收缓冲区将数据解析后分散存放到多个不同的目标数据结构中。优势极大减轻了CPU在管理多个不连续数据传输时的负担用一次DMA配置完成了复杂的多段搬运。配置关键需要在内存中构建一个描述符链表。每个描述符的控制字中包含“链表指针有效”和“传输类型”等字段。第一个描述符的地址写入DMA_CTLBASE。DMA控制器会自动遍历链表。个人体会在CC323x上实现Wi-Fi数据包的高效搬运Scatter-Gather模式是核心。网络数据包往往由协议头、载荷、校验等不连续的部分组成。利用Scatter-Gather DMA网卡驱动可以一次性将整个数据包从网络缓冲区搬移到硬件FIFO或者反之从而最大化吞吐量降低CPU负载。在实现时务必注意描述符链表的内存对齐要求和缓存一致性操作描述符本身也最好放在非缓存区或确保其缓存行被正确维护。