MSC711x DSP TDM与DMA配置实战:实现多通道音频数据高效搬运

发布时间:2026/6/9 15:35:04

MSC711x DSP TDM与DMA配置实战:实现多通道音频数据高效搬运 1. 项目概述当TDM遇上DMA如何让MSC711x DSP的数据吞吐飞起来在嵌入式音频处理、电信网关或者任何需要处理多路数字音频流的场景里你肯定遇到过这样的问题CPU吭哧吭哧地搬运数据结果宝贵的MIPS每秒百万条指令全耗在I/O上了真正用于算法处理的算力所剩无几。如果你正在使用Freescale现NXP的MSC711x系列DSP那么恭喜你你手头有一个强大的武器组合——时分复用TDM接口和直接内存访问DMA控制器。这个组合拳能把你从繁琐的数据搬运中解放出来让数据像坐上了高速传送带一样在内存和外设之间自动、高效地流转。我最早在做一个VoIP媒体网关项目时需要处理多达128路的E1时隙语音数据。如果每路数据都让CPU去读TDM寄存器、再写入内存那系统早就卡成幻灯片了。正是通过深入研究MSC711x的TDM和DMA机制才实现了稳定、低延迟的百路语音处理。今天我就把自己踩过的坑、调通的参数和验证过的代码掰开揉碎了分享给你。无论你是要对接E1/T1 framer芯片还是要构建一个多通道音频矩阵这篇文章都能帮你把MSC711x的TDMDMA这套组合拳打好。简单来说TDM负责把多路数据流打包成一条高速串行流而DMA则负责在后台默默地把这些数据搬到正确的地方全程无需CPU干预。这听起来简单但里面的门道可不少时钟怎么生成才精准帧同步信号如何对齐数据是交织存放还是解交织存放更高效DMA通道又该如何配置才能实现“乒乓缓冲”或定期中断别急我们一步步来。2. TDM模块深度解析不止是串口那么简单很多人会把TDM接口简单地理解为一个“多通道串口”这其实低估了它的能力。MSC711x的TDM模块是一个高度可配置的同步串行通信引擎专为高密度、实时数据流设计。理解它的架构是进行一切高级配置的基础。2.1 核心架构与数据通路MSC711x的TDM模块在设计上充分考虑了灵活性和性能。其核心是一个双工全双工的串行通信引擎分为独立的发送Tx和接收Rx两部分。这两部分可以共享时钟和帧同步信号也可以独立工作这为连接不同时序要求的设备提供了可能。从数据通路来看发送数据从内部的发送数据寄存器TDMxTDR出发。这里有一个关键设计一个4行深的发送FIFO。启用这个FIFO通过设置TDMxTIR[TFEN]位是实现稳定、无丢失数据传输的关键。当DMA来不及填充数据时FIFO可以作为缓冲防止TDM接口“断流”。数据从TDR或FIFO进入发送移位寄存器然后在时钟驱动下从TDMxTD引脚一位一位地移出。如果启用了A-law或μ-law压缩硬件编解码器Compander会自动将16位线性PCM数据压缩成8位对数格式这对于电信应用是极大的便利。接收端则是一个镜像过程。数据从TDMxRD引脚移入接收移位寄存器凑齐一个时隙的数据8或16位后存入接收数据寄存器TDMxRDR或接收FIFO。同样如果检测到压缩数据硬件会自动将其扩展为线性格式。整个数据通路通过64位的ASTH总线与内存系统连接而配置寄存器则通过32位的APB总线访问这种分离保证了配置灵活性和数据高带宽。实操心得FIFO水位的艺术发送和接收FIFO的水位Watermark设置是平衡响应速度和中断频率的杠杆。以发送为例TDMxTIR[TFWM]位控制何时触发“FIFO空”事件进而触发DMA请求。如果设置为00FIFO中有一个或以上空位就触发那么DMA响应会非常及时数据断流风险低但中断/DMA请求频率会很高。如果设置为11FIFO完全空才触发则DMA请求频率最低但对DMA服务的延迟要求也最苛刻一旦DMA响应慢就可能出现“下溢”Underflow输出错误数据。我的经验是在系统负载较轻或DMA优先级最高时可以设为00以求最稳在系统复杂、DMA可能被阻塞时设为01或10半空触发是更保险的选择为DMA响应留出一些时间余量。2.2 信号定义与GPIO复用配置每个TDM模块对外暴露6个信号引脚它们是连接外部世界的物理桥梁TDMxTCK/RCK发送/接收位时钟。数据在此时钟的边沿被采样或驱动。TDMxTFS/RFS发送/接收帧同步信号。一个脉冲标志着一帧数据的开始。TDMxTD/RD发送/接收数据线。这些引脚与GPIO复用因此上电后第一件事就是正确配置引脚功能。MSC711x的GPIO配置稍显繁琐需要操作四个寄存器设备配置寄存器DEVCFG、端口控制寄存器PxCTL、数据方向寄存器PxDDR和数据寄存器PxDR。对于TDM0和TDM1它们使用GPIO A口的“次要功能”Secondary Function。你需要将DEVCFG寄存器中的PASPort A Select位清零。然后在PACTL寄存器中将对应引脚的控制位设置为1以选择外设功能而非GPIO功能。例如TDM0的6个信号占用PA[11:6]那么就需要设置PACTL[11:6] 0xFC0。最后将PADDR和PADR中对应位清零因为方向和数据由TDM模块控制。对于TDM2情况特殊一些它使用了GPIO A口和D口的“附加功能”Additional Function。此时需要将DEVCFG中的PAS和PDS位都置1。然后TDM2TCK、TDM2RFS、TDM2TD在PD口PDCTL[6:4]TDM2RCK、TDM2TFS、TDM2RD在PA口PACTL[29:27]需要分别设置。下面是一个配置TDM0、TDM1和TDM2引脚功能的代码示例它清晰地展示了如何操作这些寄存器void InitGPIO(void) { GPIO *pstGPIO; BTM *pstBTM; pstGPIO (GPIO *)(GPIO_BASE); pstBTM (BTM *)(BTM_BASE); // 配置TDM0和TDM1使用GPIO A口的次要功能 // 将PA[11:0]配置为外设功能方向和数据寄存器清零 pstGPIO-astPort[0].vuliPortControl 0x00000FFF; // PACTL[11:0] 1 pstGPIO-astPort[0].vuliPortDataReg 0; pstGPIO-astPort[0].vuliPortDataDirReg 0; // 为TDM2配置芯片功能选择使用附加功能 // 设置DEVCFG寄存器的PAS和PDS位 pstBTM-vuliCHPCFG pstBTM-vuliCHPCFG | 0x00000009; // 配置TDM2在PA口的引脚T2TFS(PA29), T2RD(PA28), T2RCK(PA27) pstGPIO-astPort[0].vuliPortControl pstGPIO-astPort[0].vuliPortControl | 0x38000000; // 配置TDM2在PD口的引脚T2TD(PD6), T2TCK(PD5), T2RFS(PD4) pstGPIO-astPort[3].vuliPortControl pstGPIO-astPort[3].vuliPortControl | 0x00000070; }注意事项上电默认状态芯片复位后所有引脚默认为GPIO输入且上拉。在配置为TDM功能前如果外部设备已经开始发送时钟和数据可能会在GPIO引脚上产生不必要的电流或信号冲突。安全的做法是在系统初始化早期就完成GPIO的功能配置或者确保外部设备在DSP初始化完成后再启动。2.3 时钟与帧同步系统的节拍器TDM通信的基石是精确的时钟和帧同步。时钟TDMxTCK/RCK决定了每一位数据的时间长度帧同步TDMxTFS/RFS则告诉接收方一帧数据从哪里开始。时钟生成有两种模式外部输入和内部生成。对于需要主导通信时序的设备如主设备通常选择内部生成。MSC711x巧妙地利用其Timer B模块作为时钟源。Timer B的输入可以是APB时钟通常为内核频率的一半或外部时钟经过预分频器和比较寄存器可以产生非常灵活的时钟频率。假设我们需要一个标准的8.192 MHz TDM位时钟这是8 kHz帧频、8位时隙、128通道的典型时钟而SC1400内核运行在200 MHzAPB时钟则为100 MHz。计算过程如下目标位时钟频率f_bit 8.192 MHzTimer B需要输出一个方波其翻转频率是位时钟频率的两倍因为每个位周期需要一个上升沿和一个下降沿即f_toggle 2 * f_bit 16.384 MHz。Timer B的输入时钟f_in 100 MHz。比较寄存器TMRBCMP1的值决定了多少个输入时钟周期后翻转输出。计算公式为Compare_Value f_in / f_toggle 100 MHz / 16.384 MHz ≈ 6.1035。取整后设置TMRBCMP1 6。这样产生的实际频率约为100 MHz / (2 * 6) 8.333 MHz与目标有微小偏差。对于严格的电信应用如E1/T1这点偏差可能无法接受此时必须选择能被目标频率整数分频的输入时钟源例如使用专用的外部晶振作为Timer的时钟源。帧同步生成则完全由TDM模块内部的帧同步发生器完成。它基于位时钟工作首先根据TDMxTFP/RFP[TCS/RCS]设置的通道宽度8或16位将位时钟分频得到“字时钟”Word Clock标志每个时隙的开始。然后再根据TDMxTFP/RFP[TNCF/RNCF]设置的每帧时隙数最大128且必须为偶数将字时钟分频最终产生帧同步信号。例如8.192 MHz位时钟、8位时隙、128通道帧同步频率就是8.192 MHz / 8 / 128 8 kHz。帧同步的极性高有效/低有效、长度1位或多位周期以及相对于数据位的延迟0-3位都可以通过TDMxTIR/RIR寄存器精细配置以匹配不同厂商的编解码器或Framer芯片的时序要求。3. TDM配置实战从寄存器到波形理论说再多不如一行代码。我们以一个典型的应用场景为例配置TDM0工作在内部环回Loopback模式位时钟8.192 MHz帧频8 kHz每帧128个时隙使用其中16个活跃的8位通道。这个配置常用于自测试和初步调试。3.1 关键寄存器配置详解配置TDM本质上是配置一组寄存器。我们需要关注以下几个核心寄存器TDM0通用接口寄存器TDM0GIR设置全局模式。对于内部环回我们设置LPBK1。同时为了简化让发送和接收部分共享时钟和帧同步CTS1,RTS1。这样我们只需要使用TDM0TCK、TDM0TFS、TDM0TD和TDM0RD这四根线实际上环回时TD内部连接到RD。TDM0接收接口寄存器TDM0RIR控制接收侧行为。RFEN1, RWEN1启用接收FIFO并设置为宽模式64位访问。RFWM00FIFO中只要有1个数据就产生“FIFO满”事件触发DMA请求。这保证了最低延迟。RCOE1, RSO1时钟和帧同步配置为输出因为我们是主设备。RSL0, RSA0帧同步脉冲高电平有效持续1个位时钟周期。RFSE1帧同步信号在时钟下降沿被驱动输出或采样输入。RDE0接收数据在时钟上升沿采样。这是最常用的模式。TDM0发送接口寄存器TDM0TIR在环回模式下发送侧配置必须与接收侧完全一致以保证时序匹配。因此其设置与TDM0RIR相同。TDM0接收/发送帧参数寄存器TDM0RFP/TDM0TFPRNCF/TNCF 0x7F表示每帧有128个时隙0x7F 1。RCS/TCS 00每个通道时隙为8位数据。将这些设置转化为代码如下所示void InitTDMParams(void) { TDM *pstTDM0; pstTDM0 (TDM *)(TDM0_BASE); // 配置TDM0通用接口环回模式收发共享时钟和同步 // LPBK1, RTS1, CTS1 pstTDM0-vuliGIR 0x00000007; // 配置接收接口寄存器 (RIR) // RFEN1, RWEN1, RFWM00, RSO1, RSL0, RSA0, RCOE1, RDMA1, RDE0, RFSE1 pstTDM0-vuliRIR 0x0000E242; // 配置发送接口寄存器 (TIR)设置与RIR一致 // TFEN1, TWEN1, TFWM00, TSO1, TSL0, TSA0, TCOE1, TDMA1, TDE0, TFSE1 pstTDM0-vuliTIR 0x0000E242; // 配置接收帧参数128时隙8位/通道 // RNCF0x7F (128 slots), RCS00 (8-bit) pstTDM0-vuliRFP 0x007f0000; // 配置发送帧参数128时隙8位/通道 // TNCF0x7F, TCS00 pstTDM0-vuliTFP 0x007f0000; }3.2 时序波形验证配置完成后最直观的验证方法就是用示波器或逻辑分析仪抓取TDM0TCK、TDM0TFS和TDM0TD的波形。根据上面的配置你应该能看到TDM0TCK一个8.192 MHz或接近的方波。TDM0TFS一个8 kHz的脉冲信号每个脉冲高电平持续恰好一个TDM0TCK周期。脉冲的下降沿因为RFSE1标志着帧的开始。TDM0TD在TDM0TFS有效后的第一个TDM0TCK上升沿因为TDE0开始输出第一个时隙通道0的最高位MSB。数据会连续传输128个时隙每个时隙8位。调试技巧先环回再外联在连接外部设备如编解码器之前强烈建议先在内部环回模式下进行测试。你可以让DMA向TDM发送缓冲区写入一个已知的模式例如递增的数列然后配置DMA从TDM接收缓冲区读取数据。如果读回的数据与发送的完全一致就证明TDM模块的时钟、帧同步、数据通路配置都是正确的。这能极大降低硬件联调的复杂度把问题隔离在软件配置层面。4. DMA引擎配置精要数据搬运的自动化流水线TDM接口把数据收发了但数据还躺在它的数据寄存器TDMxRDR/TDMxTDR里。我们需要DMA这个“搬运工”把它们及时地搬到内存中供CPU处理或者把内存中处理好的数据搬到TDM接口发送出去。MSC711x的DMA控制器功能强大支持复杂的传输描述符TCD能实现自动化的、无需CPU干预的数据搬运。4.1 DMA通道与TDM的映射关系首先要记住TDM模块与DMA通道的固定映射关系这是硬件决定的DMA 通道TDM 分配0TDM0 发送1TDM0 接收2TDM1 发送3TDM1 接收12TDM2 发送13TDM2 接收例如如果你想用DMA来处理TDM0的接收数据就必须使用DMA通道1。发送则使用通道0。4.2 核心概念交织(Interleaved) vs 解交织(Deinterleaved)这是TDM数据处理中最关键的概念之一决定了数据在内存中的排列方式也直接影响后续算法处理的效率。交织数据这是数据从TDM接口出来的“自然”顺序。内存中一个帧的所有通道数据连续存放。即[帧0,通道0], [帧0,通道1], ..., [帧0,通道127], [帧1,通道0], [帧1,通道1], ...。如果你需要对完整的帧进行整体处理如某些帧级别的加密或封装这种格式很方便。解交织数据这是按通道组织的顺序。内存中同一个通道的所有帧数据连续存放。即[通道0,帧0], [通道0,帧1], ..., [通道0,帧N], [通道1,帧0], [通道1,帧1], ...。如果你需要对每个通道进行独立的处理如每路语音单独做增益控制、滤波这种格式是最高效的因为同一通道的数据在内存中是连续的缓存命中率高。DMA控制器通过巧妙配置传输属性SSIZE/DSIZE、地址偏移SOFF/DOFF和次循环字节数NBYTES可以自动完成这两种格式的转换。4.3 实战一使用DMA接收交织数据假设我们配置TDM为16个活跃的8位通道。TDM每次会收满8个字节64位对应8个通道后才产生一次“接收FIFO满”事件触发DMA传输。因此DMA的每次传输次循环就是搬运这8个字节。我们需要配置DMA通道1TDM0接收的传输控制描述符TCDSADDR源地址固定为TDM0RDR的AHB总线地址TDM0AHB_BASE。DADDR目的地址是我们的接收缓冲区首地址。注意如果缓冲区在M1内存0x01800000起始需要在地址上加上这个偏移。SOFF源地址偏移为0因为每次都是从同一个TDM0RDR寄存器读。DOFF目的地址偏移为8。因为第一次DMA传输搬了通道0-7的数据到缓冲区起始位置下一次传输搬通道8-15的数据需要放在偏移8字节的地方。SSIZE/DSIZE传输大小都设为64位0x3因为TDM FIFO是64位宽一次读8字节效率最高。NBYTES次循环字节数设为8。CITER/BITER主循环次数。假设我们要接收80帧数据。总字节数 80帧 × 16通道/帧 × 1字节/通道 1280字节。每次DMA传输搬8字节所以需要1280 / 8 160次传输。CITER和BITER都设为160。DLAST_SGA当主循环160次传输完成后DMA会自动将目的地址DADDR调整DLAST_SGA的值。这里我们设为-1280这样目的地址就回到了缓冲区开头实现了环形缓冲可以持续接收新数据覆盖旧数据。// 接收交织数据的DMA通道1配置示例 pstDMA-astTCD[1].vuliSAddr TDM0AHB_BASE; // 源TDM接收寄存器 pstDMA-astTCD[1].vusiTransferAttr 0x0303; // SSIZE64位, DSIZE64位 pstDMA-astTCD[1].vusiSOff 0; // 源地址固定 pstDMA-astTCD[1].vuliNBytes 8; // 每次传8字节 pstDMA-astTCD[1].vuliSLast 0; // 源地址最后不调整 UWord32 addr (UWord32)(Rx_Interleaved_Buffer); pstDMA-astTCD[1].vuliDAddr COMP_DMA_ADDR(addr); // 目的交织缓冲区 #define SZ_BUF (80 * 16 * 1) // 1280字节 pstDMA-astTCD[1].vusiCIter SZ_BUF / 8; // 主循环次数160 pstDMA-astTCD[1].vusiDOff 8; // 每次传输后目的地址8 pstDMA-astTCD[1].vuliDLastSGA -(SZ_BUF); // 主循环后目的地址回退1280字节 pstDMA-astTCD[1].vusiBIter pstDMA-astTCD[1].vusiCIter; // BITER CITER这种配置的优点是DMA可以无限循环自动覆盖缓冲区实现“乒乓操作”CPU只需要定期来读取处理好的数据块即可。缺点也很明显数据是交织的如果要对某个特定通道进行连续处理就需要在内存中“跳着”访问数据缓存效率低软件处理开销大。4.4 实战二使用DMA直接接收解交织数据解交织模式更符合多通道独立处理的直觉。DMA配置的巧妙之处在于它通过一次读取8字节然后执行多次不同目的地址的写入来实现解交织。关键配置变化在于DSIZE目的传输大小设为8位0x0而不是64位。这意味着DMA控制器从TDM0RDR一次读取8字节后会将其拆分成8次独立的1字节写入操作。DOFF目的地址偏移设为每个通道缓冲区的大小。假设我们为16个通道分别分配了缓冲区每个缓冲区存放80帧数据80字节。那么DOFF就设置为80。这样第一次写入的1字节通道0数据进入通道0缓冲区的第0个位置第二次写入的1字节通道1数据会写入通道1缓冲区的第0个位置地址正好偏移了80字节以此类推。CITER/BITER现在每次DMA请求对应TDM收满8个通道只能完成一帧内8个通道的数据摆放。要收齐一帧16个通道的数据需要2次DMA请求。所以CITER设为2。CITER减到0表示一帧数据收齐触发主循环结束。DLAST_SGA主循环结束后我们需要把目的地址调整到下一个帧的起始位置。当前目的地址指向的是通道7缓冲区的第0个位置假设刚写完一帧。下一帧通道0的数据应该写到通道0缓冲区的第1个位置。所以地址需要回退(总缓冲区大小 - 一个通道缓冲区大小)。总缓冲区大小是16通道 * 80字节/通道 1280字节一个通道缓冲区是80字节所以DLAST_SGA -(1280 - 80) -1200。这样下一次主循环开始时目的地址又指向了通道0缓冲区的下一个位置索引1。// 接收解交织数据的DMA通道1配置示例 pstDMA-astTCD[1].vuliSAddr TDM0AHB_BASE; // 源TDM接收寄存器 pstDMA-astTCD[1].vusiTransferAttr 0x0300; // SSIZE64位, DSIZE8位 pstDMA-astTCD[1].vusiSOff 0; pstDMA-astTCD[1].vuliNBytes 8; // 一次读8字节 pstDMA-astTCD[1].vuliSLast 0; UWord32 addr (UWord32)(Rx_Deinterleaved_Buffer[0][0]); // 指向通道0缓冲区起始 pstDMA-astTCD[1].vuliDAddr COMP_DMA_ADDR(addr); #define NUM_CH 16 // 通道数 #define SZ_CH 80 // 每个通道缓冲区的帧容量字节 #define NUM_FRM 80 // 总帧数 pstDMA-astTCD[1].vusiCIter 2; // 收齐一帧(16通道)需要2次DMA请求 pstDMA-astTCD[1].vusiDOff SZ_CH * NUM_FRM; // 80跳到下一个通道的缓冲区 pstDMA-astTCD[1].vuliDLastSGA -( (SZ_CH * NUM_FRM * NUM_CH) - (SZ_CH * NUM_FRM) ); // -1200 pstDMA-astTCD[1].vusiBIter pstDMA-astTCD[1].vusiCIter;核心要点理解NBYTES与SSIZE/DSIZE的配合NBYTES定义了一次“次循环”要搬运的总字节数。而SSIZE和DSIZE定义了每次“读”或“写”操作的粒度。在解交织例子中NBYTES8SSIZE64位所以DMA执行1次64位读操作从源地址读取8字节。DSIZE8位所以DMA接着执行8次8位写操作将刚读来的8字节依次写入8个不同的目的地址由DADDR和DOFF决定。这个过程完全由DMA硬件自动完成效率极高。4.5 高级技巧链接通道实现定期中断在很多应用中我们不想让DMA无限循环而是希望每收集完N帧数据后通知CPU来进行批量处理例如每10ms处理80帧。这可以通过DMA的通道链接Channel Linking功能实现。思路是让负责数据搬运的DMA通道如通道1在完成一次主循环即收齐一帧解交织数据后自动启动另一个“辅助”DMA通道例如通道6。这个辅助通道不执行实际的数据传输只作为一个计数器。我们配置它的CITER为N例如4并启用主循环完成中断INT_MAJ。这样当通道1每完成一帧传输就触发通道6执行一次“传输”实际上是计数减一。当通道6的CITER从4减到0时就会产生一个DMA中断此时CPU就知道已经收集了4帧数据可以进行处理了。配置要点在通道1的TCD中设置MAJOR.E_LINK1并设置MAJOR.LINKCH6使其主循环完成后链接到通道6。配置通道6的TCDSADDR和DADDR可以指向一个虚拟的缓冲区dummy buffer。SSIZE/DSIZE任意NBYTES任意例如8。关键是CITER设为想要的帧数N例如4并设置INT_MAJ1。在DMA中断服务程序ISR中判断是通道6的中断即可进行数据处理并重新使能通道1和通道6或重新赋值CITER/BITER以开始下一轮收集。// 配置通道1使其主循环后链接到通道6 pstDMA-astTCD[1].vusiChannelCtrlStat | 0x0020; // 设置 MAJOR.E_LINK1 // 注意LINKCH字段通常在TCD的另一个字中这里仅为示意实际需查寄存器手册。 // 配置通道6作为计数器 UWord32 dummy_addr (UWord32)(dummy_buffer); pstDMA-astTCD[6].vuliSAddr COMP_DMA_ADDR(dummy_addr); pstDMA-astTCD[6].vuliDAddr COMP_DMA_ADDR(dummy_addr); pstDMA-astTCD[6].vusiTransferAttr 0x0303; // 传输属性随意 pstDMA-astTCD[6].vuliNBytes 8; pstDMA-astTCD[6].vusiCIter 4; // 每4帧中断一次 pstDMA-astTCD[6].vusiBIter 4; pstDMA-astTCD[6].vusiChannelCtrlStat 0x0002; // INT_MAJ1启用主循环完成中断这种方法将CPU从轮询缓冲区的任务中彻底解放实现了基于事件的、准确定时的批处理是构建高效实时系统的关键。5. 系统调优与避坑指南配置通了只是第一步要让系统稳定高效地跑起来还需要进行细致的调优。5.1 DMA优先级与仲裁MSC711x的DMA控制器有多个通道当多个通道同时请求时需要通过优先级仲裁。优先级在DMA_CPRx寄存器中设置。对于TDM这种实时数据流必须将其对应的DMA通道设置为最高优先级。因为TDM数据流是连续不断的如果DMA响应不及时就会导致FIFO上溢或下溢造成数据丢失或错误。例如TDM0接收通道1和发送通道0的优先级应该设为最高如0级或1级。同时要避免让高带宽、高优先级的DMA通道如与SDRAM交互的通道长时间霸占总线这可能会阻塞TDM DMA的访问。有时需要调整不同内存访问的突发长度Burst Size来优化总线利用率。5.2 交叉开关Crossbar Switch调优MSC711x内部有多条总线如AHB、APB、ASTH通过交叉开关互联。TDM模块通过ASTH总线与内存交互。你需要确保TDM和DMA访问的内存通常是M1 SRAM在交叉开关中的配置是最优的例如使能预取Prefetch和缓冲Buffer功能以减少访问延迟。5.3 常见问题排查没有数据或数据全零检查时钟和帧同步用示波器测量TDMxTCK和TDMxTFS引脚确认波形、频率、极性符合预期。这是最常见的问题根源。检查环回模式先配置为内部环回用DMA自发自收验证TDM和DMA基础配置是否正确。检查GPIO配置确认PxCTL、PxDDR、DEVCFG寄存器配置正确引脚确实被切换到了TDM功能。检查DMA启动确认在配置完TCD后向相应通道的DMA_CSR寄存器写入了启动命令。数据错位或混乱检查帧同步延迟TDMxTIR/RIR中的TFSD/RFSD位控制帧同步信号相对于数据的延迟0-3位。如果外部设备时序特殊可能需要调整这个值。检查数据边沿确认TDE和RDE数据驱动/采样边沿与外部设备匹配。通常上升沿采样但有些设备可能相反。检查字节序TDMxTIR/RIR中的TBO/RBO位控制MSB/LSB先行。确保与通信对方一致。DMA传输不连续或丢失数据检查FIFO水位如果TFWM/RFWM设置得太“深”比如FIFO快满/快空才触发而DMA响应延迟较大可能导致FIFO上溢或下溢。尝试调低水位值。检查DMA优先级确保TDM DMA通道优先级足够高不会被其他DMA操作长时间阻塞。检查CITER和BITER确保它们被正确赋值且不为0。BITER是初始值CITER是当前值每次主循环完成后硬件会将CITER重新加载为BITER。如果BITER为0通道会在完成一次后就停止。检查DLAST_SGA和SLAST在循环缓冲模式下这两个值必须正确设置以保证地址能正确回绕。计算错误会导致DMA写到非预期的内存区域造成数据覆盖或系统崩溃。中断无法产生检查中断使能除了在DMA TCD中设置INT_MAJ还需要在DMA控制器全局中断使能寄存器以及内核的中断控制器INTC中使能对应的DMA通道中断。检查链接配置如果使用通道链接产生中断务必确认源通道的MAJOR.E_LINK和MAJOR.LINKCH设置正确并且目标通道已正确配置并启用。调试这类问题善用芯片的仿真器和内存观察窗口至关重要。你可以单步执行初始化代码查看每个寄存器的值是否与预期一致。在DMA运行后观察目的缓冲区的数据是否按预期更新。同时结合示波器观察硬件信号能快速定位是软件配置问题还是硬件连接问题。

相关新闻