CC35xx DMA控制器核心机制:块传输、地址对齐与通道优先级详解 1. DMA控制器核心概念与CC35xx HOST_DMA模块概览在嵌入式系统开发中当我们需要处理UART接收一串数据、SPI发送一个图像缓冲区或者ADC连续采样时最原始的方式是让CPU通过轮询或者中断来一个个字节地搬运数据。这种方式效率低下CPU被大量简单重复的I/O操作所占用无法执行更有价值的计算任务。这时直接内存访问DMA控制器就扮演了“专职搬运工”的角色。它是一块独立的硬件能够在内存和外设之间或者内存与内存之间直接建立数据传输通道整个过程无需CPU介入。CPU只需要告诉DMA“从A地址开始搬N个字节到B地址”然后就可以去处理其他任务等DMA干完活再发个中断通知一下即可。德州仪器TI的CC35xx系列无线MCU作为集成Wi-Fi 6和蓝牙低功耗的复杂片上系统SoC其内部集成了一个功能相当强大的HOST_DMA控制器。这个控制器不仅仅是简单的数据搬运它设计了许多精细化的控制机制来应对真实场景中的复杂需求。比如外设数据可能不是一次性到达的例如UART以特定波特率接收DMA如何高效地组织传输又比如源地址或目标地址没有按照内存的自然边界对齐DMA该如何处理而不出错再比如当多个外设同时请求DMA服务时谁先谁后这些问题的答案就藏在块传输Block Transfer、地址对齐Address Alignment和通道优先级Channel Priority这几个核心机制里。理解这些机制对于在CC35xx这类资源受限但要求实时性的嵌入式设备上实现高效、稳定的数据流处理至关重要。它直接影响到你的应用能否流畅地播放音频、能否及时响应网络数据包、能否保证传感器数据不丢失。下面我们就结合HOST_DMA的寄存器手册把这些机制掰开揉碎了讲清楚。2. 块传输Block Transfer机制深度解析块传输是DMA提升效率的核心手段之一。你可以把它理解为“批发”和“零售”的区别。如果没有块传输DMA每搬运一个“字”Word大小可以是8、16或32位都需要向外设或内存发起一次请求和响应这会产生大量的总线仲裁和握手开销。而块传输则允许DMA一次性申请一笔“批发”额度然后连续搬运多个字期间独占总线从而大幅减少开销。2.1 块传输的基本工作流程在CC35xx的HOST_DMA中块传输的粒度由CHxJCTL.BLKSIZE寄存器字段定义它指定了一个块包含多少个“字”Word。而“字”的大小则由CHxJCTL.WORDSIZE决定0032位0116位108位。当一次传输任务Job启动后DMA控制器会尝试以块为单位进行传输。每次传输触发可能是外设的请求信号也可能是内存到内存的软件触发DMA会尽可能搬运一个完整块的数据。但问题来了如果总传输字节数不是块大小的整数倍怎么办手册里给出了非常清晰的逻辑DMA会先进行尽可能多的完整块传输最后剩余不足一个块的数据则以单字Word为单位进行传输。这个行为可以通过CHxTCTL.BURSTREQ位进行微调。2.2 块传输的实例拆解与计算我们来看手册中的两个例子这能帮你彻底理解计算过程实例一UART接收字大小8位块大小4字任务参数UART要读取30字节数据。DMA字大小配置为8位即1字节1字。块大小配置为4字。计算过程总字数 30字节 / 1字节/字 30字。完整块数 总字数 / 块大小 30 / 4 7块 余数 2字。因此DMA会执行7次块传输每次传输4字节和2次单字传输每次传输1字节。传输序列7个块传输 (4,4,4,4,4,4,4字节) 2个单字传输 (1,1字节) 总共9次事务Transaction。实例二SPI接收字大小16位块大小8字任务参数SPI要读取40字节数据。DMA字大小配置为16位即2字节1字。块大小配置为8字。计算过程总字数 40字节 / 2字节/字 20字。完整块数 总字数 / 块大小 20 / 8 2块 余数 4字。因此DMA会执行2次块传输每次传输8字 * 2字节/字 16字节和4次单字传输每次传输1字 * 2字节/字 2字节。传输序列2个块传输 (16,16字节) 4个单字传输 (2,2,2,2字节) 总共6次事务。关键点这里务必注意“字Word”和“字节Byte”的转换。BLKSIZE定义的是“字数”而TRANSBTransaction Bytes寄存器配置的是总“字节数”。在计算时必须根据WORDSIZE进行换算。这是新手最容易混淆和配置错误的地方。2.3 BURSTREQ位的高级控制CHxTCTL.BURSTREQBurst Request位提供了一个优化选项。默认情况下该位为0当剩余待传输数据量小于一个块时DMA会切换为单字请求模式。但有些场景下即使数据量不足我们仍希望DMA等待并凑足一个块的请求例如从某个具有固定突发长度的FIFO中读取。此时可以将BURSTREQ置1。这样DMA会等待外设发出一个“块请求”信号然后将所有剩余数据在一个块周期内传输完毕这对于维持某些外设的时序或提高总线利用效率可能有帮助。配置心得对于UART、SPI这类通常以字节或字为单位产生请求的外设通常保持BURSTREQ0即可。但对于像SDMMCSD卡接口或某些特定总线从设备它们可能以固定的突发长度操作此时设置BURSTREQ1可以更好地匹配其工作模式避免产生不必要的总线周期。3. 地址对齐Address Alignment支持与实战处理内存访问对齐是计算机体系结构中的一个基本概念。简单说访问一个N字节的数据其内存地址最好是N的整数倍这样硬件效率最高。非对齐访问可能导致性能下降甚至在有些架构上引发硬件异常。CC35xx的HOST_DMA在字大小为32位时提供了对非对齐起始地址和非对齐作业大小的硬件支持这大大简化了驱动程序的编写。3.1 对齐规则与支持矩阵手册中的表格清晰地定义了四种情况。我们首先明确两个关键概念作业起始地址对齐传输任务的源或目标起始地址是否是当前WORDSIZE的整数倍。例如字大小为32位4字节那么地址0x0、0x4、0x8...是对齐的0x1、0x2、0x3、0x5...就是非对齐的。作业大小对齐需要传输的总字节数TRANSB是否是当前WORDSIZE的整数倍。支持矩阵总结如下起始地址作业大小DMA事务处理方式对齐对齐所有传输都是地址和字对齐的效率最高。对齐非对齐所有传输地址对齐但最后一次传输的数据量会小于一个字即只传输有效字节。非对齐对齐第一次传输地址非对齐且数据量小于一个字最后一次传输地址对齐且数据量小于一个字中间所有传输都对齐。非对齐非对齐第一次传输地址非对齐且数据量小于一个字最后一次传输可能地址对齐且数据量小于一个字中间所有传输都对齐。3.2 非对齐访问实例详解手册举了多个例子我们挑最复杂的“地址非对齐作业大小非对齐”来看这最能体现控制器的“智能”之处。场景字大小32位4字节起始地址0x1作业大小14字节。分析起始地址0x1不是4的倍数非对齐。作业大小14字节不是4的倍数非对齐。总数据需要覆盖从0x1到0xE0x1 14 - 1的内存范围。DMA的实际操作手册表格事务1从地址0x0开始读注意地址对齐到了0x0。但它只取这个32位字0x0-0x3中的后3个字节对应地址0x1, 0x2, 0x3作为本次传输的第一个字节。这就是“第一次传输地址非对齐且字”。事务2传输地址0x4对齐的完整4字节0x4-0x7。事务3传输地址0x8对齐的完整4字节0x8-0xB。事务4传输地址0xC对齐的4字节0xC-0xF。但作业在0xE结束所以它只取这个字的前2个字节0xC, 0xD。这就是“最后一次传输地址对齐且字”。关键理解DMA硬件在内部处理了非对齐的复杂性。从程序员视角你只需要设置好起始地址和大小DMA会保证数据被正确地搬运。它通过“读-修改-写”或类似机制在总线接口处处理字节使能Byte Enable信号确保只访问有效的字节而不破坏相邻内存的数据。配置注意事项性能影响非对齐访问尤其是起始地址非对齐通常会导致额外的总线周期或内部处理开销比完全对齐的传输效率要低。在性能敏感的路径上应尽量确保数据缓冲区的地址对齐。32位限制手册明确指出非对齐访问支持仅在字大小为32位时有效。如果你配置字大小为8位或16位起始地址必须对齐到相应的边界1字节或2字节否则行为可能是未定义的或导致错误。缓冲区分配在C代码中定义用于DMA传输的缓冲区时可以使用编译器指令如GCC的__attribute__((aligned(4)))来强制进行4字节对齐这是一个好习惯。4. 通道优先级与仲裁机制剖析CC35xx的HOST_DMA支持多达14个独立通道Channel 0-13。当多个通道同时有传输请求时就需要一个仲裁器来决定谁先谁后。这个仲裁策略直接影响了高实时性任务如音频播放和低优先级任务如后台日志传输的响应表现。4.1 优先级配置寄存器PRIOCFG仲裁逻辑主要由PRIOCFG寄存器控制PRIOEN 全局优先级使能位。为0时所有通道采用简单的轮询Round-Robin仲裁。CH1ST 第一优先级通道号。CH2ND 第二优先级通道号。MAXBLOCKS最高优先级通道连续传输块数限制。这是一个防止“饿死”低优先级通道的关键机制。4.2 混合仲裁策略详解手册描述的策略是一种混合优先级轮询的机制高优先级通道优先如果使能了优先级PRIOEN1且CH1ST或CH2ND指定的通道有请求它们会优先获得服务。防饿死机制为了防止高优先级通道霸占总线MAXBLOCKS定义了高优先级通道能连续传输的最大块数。达到这个限制后仲裁器会强制切换到轮询队列给其他通道机会。轮询队列未被设置为高优先级的通道组成一个轮询队列。仲裁器按照通道编号顺序0,1,2...依次服务它们。三级优先级实际形成了三级优先级CH1ST最高 CH2ND次高 其他通道轮询。4.3 仲裁实例推演我们结合手册的例子来理解假设系统有11个通道0-10例1MAXBLOCKS 4配置通道1为最高优先级CH1ST连续请求3次通道4为次高优先级CH2ND请求1次。仲裁序列1, 1, 1, 4, 2, 3, 5, 1, 1, 1, 4, 6, 7, 8, 1, 1, 1, 4, 9, 10, 11分析通道1连续执行3个块传输未超MAXBLOCKS4。由于通道1暂时没有新请求或已达上限仲裁器检查次高优先级通道4执行1次。然后进入轮询队列从通道2开始服务通道0可能未使能或无请求服务通道2、3、5。轮询一圈后再次检查高优先级。通道1再次获得3次连续服务通道4获得1次如此循环。例2MAXBLOCKS 3配置同例1。仲裁序列1, 1, 1, 2, 4, 3, 5, 1, 1, 1, 6, 4, 7, 8, 1, 1, 1, 9, 4, 10, 11分析与例1关键区别在于通道1连续执行3个块达到MAXBLOCKS限制后必须让出总线。因此通道4没有立即得到服务而是先服务了轮询队列中的通道2然后才服务通道4。这更严格地保障了轮询通道的延迟上限。实战配置建议实时性通道将最不能容忍延迟的通道如音频DAC的DMA、高速ADC采样DMA设置为CH1ST。根据其数据量设置合理的MAXBLOCKS。例如音频DMA通常需要连续填充一个缓冲区MAXBLOCKS可以设置得大一些但不宜超过缓冲区对应的块数以减少切换开销。次重要通道将带宽要求较高但实时性稍弱的通道如显示刷新DMA设置为CH2ND。后台任务像SD卡读写、网络数据包搬运等可以容忍一定延迟的任务放在轮询队列即可。MAXBLOCKS的权衡此值并非越大越好。设置过大会导致轮询通道等待时间过长可能引发其数据缓冲区上溢或下溢。需要根据各通道的数据速率和缓冲区大小精细计算。一个实用的方法是用示波器或逻辑分析仪抓取DMA请求信号观察其服务延迟来调整此参数。5. DMA通道的完整配置与操作流程理解了核心机制后我们来看如何实际操作CC35xx的DMA。每个通道都有一套独立的寄存器集其基地址有规律地偏移如通道0在0x1000通道1在0x2000以此类推。配置一个DMA传输通常遵循以下步骤5.1 通道初始化与任务配置通道映射通过CHCTL0或CHCTL1寄存器将物理DMA通道映射到特定的外设如UART0、SPI1。例如将通道0分配给UART0接收CHCTL0.CH0 0x0。配置作业控制在CHxJCTL寄存器中设置传输的“元数据”。WORDSIZE 根据外设数据宽度选择UART通常是8位。BLKSIZE 设置块大小。需要权衡效率与延迟。对于UART可以设置为接收FIFO的深度。SRCDSTCFG 方向控制。0表示从外设读到内存外设是源1表示从内存写到外设外设是目标。BLKMODESRC/BLKMODEDST 设置地址是否循环Wrap Around。这在处理循环缓冲区Circular Buffer时非常有用例如音频双缓冲区。配置传输控制在CHxTCTL寄存器中。TRANSB 本次传输任务的总字节数。这是最重要的参数之一。BURSTREQ 根据外设特性选择是否使能突发请求。ENDIANESS 处理字节序在涉及不同字节序的系统间传输数据时需要关注。设置地址指针CHxTIPTR 输入源地址指针。如果是内存到外设这里填内存源地址如果是外设到内存这里通常由硬件自动关联外设数据寄存器地址但有时也需要配置。CHxTOPTR 输出目标地址指针。解释上一条相反。5.2 启动、停止与状态查询启动传输向CHxTCTL2.CMD字段写入1Run命令。DMA控制器会立即尝试获取总线并开始传输。监控状态轮询或通过中断检查CHxSTA寄存器。RUN位表示通道正在运行或等待仲裁。FSMSTATE 显示通道精确的有限状态机状态对于调试复杂的挂起问题非常有用。HWEVENT 硬件事件状态如传输完成TRANS DONE、异常EXCEPTION。停止传输向CHxTCTL2.CMD字段写入2Abort命令。注意DMA会在完成当前正在进行的整个块传输后才会停止。停止后CHxTSTA.REMAINB会显示剩余的字节数CHxTIPTR和CHxTOPTR会停留在当前地址。你可以选择继续Resume或重新初始化Init。处理完成与异常正常完成传输完成后HWEVENT会置位TRANS DONE并可能产生中断如果使能了。FSMSTATE变为DONE。异常如果总线访问出错如访问了非法地址HWEVENT会置位EXCEPTIONFSMSTATE变为EXCEPTION。通道会卡在此状态。必须向CMD写入4Init命令来清除异常状态然后才能重新配置并启动新的传输。5.3 中断与事件管理DMA传输完成或出错通常通过中断通知CPU。CC35xx将多个DMA通道的中断信号汇聚到了事件管理器Event Manager。你需要在DMA控制器层面可能需要在相关通道使能中断具体寄存器需参考芯片的系统中断控制器文档手册片段未详述。在NVIC嵌套向量中断控制器中使能对应的DMA中断线。在中断服务程序ISR中读取事件管理器的状态寄存器确定是哪个DMA通道产生的中断然后查询该通道的CHxSTA.HWEVENT来区分是完成中断还是异常中断并进行相应处理。处理完成后通常需要清除事件管理器中的中断标志位。6. 常见问题排查与实战技巧在实际开发中DMA配置出错会导致数据错误、系统挂死等棘手问题。以下是一些典型的排查思路和技巧问题1DMA传输启动后数据没有搬运或者只搬运了一部分。检查TRANSB寄存器确认设置的字节数是否正确。这是最常犯的错误之一误将字数当作字节数设置。检查地址指针确认TIPTR和TOPTR指向的地址是有效的、可访问的内存区域。特别是目标地址是否有写权限。检查外设触发对于外设触发的DMA确认外设是否正确配置并产生了DMA请求例如UART的RX FIFO是否达到触发阈值。检查通道映射确认CHCTLx寄存器是否正确地将DMA通道映射到了目标外设。监控CHxSTA.RUN和FSMSTATE如果RUN一直为0可能是仲裁失败或根本没有请求。观察FSMSTATE是否从IDLE进入了PENDING ARB或COPY状态。问题2系统在DMA传输期间偶尔挂死或访问异常。检查内存对齐如果字大小是32位确保源和目标地址是4字节对齐的除非你确信当前场景支持非对齐访问且配置正确。检查缓冲区溢出确保DMA配置的传输大小不会超过目标缓冲区的实际大小。特别是使用循环缓冲区模式时计算好BLKSIZE和缓冲区大小的关系。检查总线冲突如果CPU和其他主设备如另一个DMA控制器、USB控制器同时访问同一块内存可能引发总线错误。考虑使用内存屏障指令或确保访问互斥。查看异常状态检查CHxSTA.HWEVENT是否有EXCEPTION标志。如果有说明发生了总线错误需要检查地址并执行Init命令复位通道。问题3高优先级通道“饿死”了低优先级通道。调整MAXBLOCKS这是最主要的手段。减少高优先级通道的MAXBLOCKS值给轮询通道更多的服务机会。优化块大小高优先级通道的BLKSIZE不宜设置过大。大的块虽然效率高但会长时间占用总线。根据实际数据流量选择一个平衡值。拆分任务如果单个高优先级任务数据量巨大考虑将其拆分成多个较小的DMA任务中间插入软件延时或等待主动释放总线。问题4如何调试复杂的DMA传输问题寄存器快照在出问题时将相关通道的所有寄存器STA, TCTL, JCTL, TSTA等内容通过调试接口打印或保存下来。使用状态机FSMSTATE字段是极佳的调试信息。它告诉你DMA卡在了哪个环节例如PENDING ARB说明在等待仲裁COPY说明正在传输EXCEPTION说明出错了。逻辑分析仪如果条件允许使用逻辑分析仪抓取DMA相关的总线信号如HRDATA, HWDATA, HADDR以及外设的请求和应答信号可以最直观地看到传输时序和问题所在。简化测试先配置一个最简单的内存到内存的DMA传输验证DMA控制器基本功能是否正常。然后再逐步加入外设和复杂模式。一个配置技巧动态重配置CC35xx的DMA支持在传输完成后自动重载参数通过双缓冲区或链表模式具体需参考芯片手册其他部分。但手册也提到了“Dynamic Switch”的配置CHCTLx.CHx 0xF。这通常用于实现乒乓缓冲区Ping-Pong Buffer当DMA正在从缓冲区A向外设传输数据时CPU可以准备缓冲区B的数据并在A传输完成后通过动态切换配置让DMA立即开始传输B而CPU则处理A的数据实现无缝流水线操作。这是实现高效、零等待数据流的关键高级特性。

本周精选

本月热点