CC13x2/CC26x2 I2S音频开发:从寄存器配置到无线同步实战
1. 项目概述与I2S核心原理
在嵌入式音频开发领域,I2S(Inter-IC Sound)总线是连接数字音频处理器、编解码器(CODEC)、ADC/DAC等器件的“标准语言”。它不像I2C或SPI那样承载复杂的控制指令,而是专注于一件事:高效、精准地传输数字化的音频采样数据流。对于TI的CC13x2/CC26x2这类集成了强大射频和低功耗特性的无线MCU而言,其内置的I2S模块不仅仅是提供一个通信接口,更是一个配备了专用DMA(直接内存访问)控制器和精密采样时间戳生成器的音频子系统。这意味着开发者可以在MCU内核几乎不干预的情况下,实现音频数据的自动搬运,将宝贵的CPU算力留给音频处理算法(如滤波、均衡、编码)或无线协议栈,这对于实现高音质、低延迟的无线音频产品至关重要。
理解I2S,首先要抓住它的三个核心时钟信号和两条数据线。位时钟(BCLK)是数据同步的“节拍器”,每个上升沿或下降沿锁存一位数据。字时钟(WCLK,或LRCLK)则扮演着“指挥家”的角色,其电平高低指示当前传输的是左声道还是右声道数据,它的一个周期对应一个完整的音频帧(包含左、右两个声道)。主时钟(MCLK)通常为采样频率的256或384倍,为外部音频器件提供高稳定度的系统时钟参考。数据线则分为数据输出(ADx_OUT)和数据输入(ADx_IN),在CC13x2/CC26x2上,它们被复用到AD0和AD1这两个GPIO引脚上。
CC13x2/CC26x2的I2S模块强大之处在于其灵活性。它支持四种主流的串行数据格式:标准的I2S格式、左对齐格式(LJF)、右对齐格式(RJF)以及DSP模式。这些格式的区别主要在于数据相对于WCLK边沿的位置、以及WCLK的占空比。例如,标准I2S格式下,数据在WCLK边沿变化后的第二个BCLK上升沿开始传输,并且WCLK在左声道期间为低电平;而左对齐格式下,数据的最高有效位(MSB)则直接对齐WCLK的边沿。模块的DMA控制器能够自动管理输入和输出缓冲区,当一块内存区域的数据被搬空或填满时,会通过中断通知CPU准备下一块缓冲区,从而实现音频流的“乒乓操作”,保证数据传输的连续性。而采样时间戳生成器则是实现多设备间无线音频同步的“秘密武器”,它通过精确计数WCLK周期和内部高频时钟周期,为每一个音频采样帧打上时间标签,使得在复杂的无线环境中也能维持恒定的音频延迟。
2. 核心寄存器配置详解
要让CC13x2/CC26x2的I2S模块正常工作,我们需要像搭积木一样,正确配置一系列功能寄存器。这个过程必须遵循严格的顺序,手册中给出的启动序列(Start-Up Sequence)是黄金法则,乱序配置很可能导致模块无法工作或产生不可预料的错误。
2.1 引脚与时钟源配置
一切始于引脚。通过配置I2S:AIFDIRCFG寄存器,我们决定AD0和AD1引脚的角色。每个引脚可以独立配置为输入(0x1)、输出(0x2)或禁用(0x0)。例如,连接一个立体声ADC进行录音,可能需要将AD0和AD1都配置为输入;而驱动一个立体声DAC播放,则需要将它们都配置为输出。一个常见的误区是忽略了引脚复用功能,AD0/AD1是与其他外设(如GPIO、SPI)复用的,因此必须在芯片的IO控制器(IOC)中先将相应引脚的功能映射到AIF(音频接口)上,这一步通常通过TI的驱动库函数PIN_setMux来完成。
接下来是时钟的“源头”选择,由I2S:AIFWCLKSRC寄存器控制。这里有两个关键位:WCLK_SRC和WCLK_INV。WCLK_SRC选择WCLK(以及隐含的BCLK)的来源:0表示无时钟(禁用),1表示来自外部引脚(由外部主设备提供),2表示由芯片内部的PRCM模块生成。WCLK_INV位则决定是否对输入的WCLK信号进行反相,这在需要对齐不同设备间相位时非常有用。一个至关重要的原则是:WCLK_SRC的选择必须与PRCM模块中BCLK源的选择(PRCM:I2SBCLKSEL.SRC)保持一致。如果选择内部时钟源(WCLK_SRC=2),那么PRCM:I2SBCLKSEL.SRC必须设为1;如果选择外部时钟源(WCLK_SRC=1),则PRCM中必须设为0。不一致的配置是导致无声或杂音的常见原因。
2.2 串行格式与数据参数设定
这是配置的核心,决定了数据流如何被组织和解析。所有相关参数都集中在I2S:AIFFMTCFG寄存器中。
DUAL_PHASE(位5):这是格式选择的总开关。设为1时,启用双相位格式,即标准的I2S、LJF、RJF格式,WCLK是一个占空比为50%的方波,高电平和低电平各代表一个声道。设为0时,启用单相位格式,即DSP格式,WCLK是一个短暂的高脉冲,标志着一个帧的开始,多个声道的数据连续传输。WORD_LEN(位[4:0]):定义每个采样字的位数,范围是8到24位。这里有一个关键细节:在双相位格式下,此字段应设置为每个采样字的最大位数;而在单相位(DSP)格式下,它应设置为每个采样字的精确位数。例如,传输24位精度的音频,在I2S格式下应设为24,在DSP格式下也应设为24。SMPL_EDGE(位6):定义数据在BCLK的哪个边沿被采样(锁存),在相反的边沿被更新(输出)。1表示在BCLK的上升沿采样,下降沿更新;0则相反。这个设置必须与相连的音频从设备(如CODEC)的时序要求严格匹配。DATA_DELAY(位[15:8]):这是数据延迟参数,单位是BCLK周期数。它定义了WCLK边沿与第一个采样字的MSB开始传输之间的间隔。这是区分I2S、LJF、RJF格式的关键:- I2S格式:
DATA_DELAY = 1。MSB在WCLK边沿后的第2个BCLK上升沿出现。 - LJF格式:
DATA_DELAY = 0。MSB直接对齐WCLK边沿。 - RJF格式:
DATA_DELAY = (每相位的BCLK周期数) - WORD_LEN。LSB对齐WCLK边沿。 - DSP格式:通常设为
0或1,表示WCLK脉冲与第一个数据字开始之间的BCLK延迟。
- I2S格式:
MEM_LEN_24(位7):这个位决定了采样字在内存中的存储格式。0表示每个采样字在内存中以16位形式存储(占用2字节),此时DMA指针必须半字(2字节)对齐。1表示以24位形式存储(占用4字节,但实际有效数据是3字节,采用一次16位加一次8位的锁定总线传输),DMA指针无需对齐。这个设置与串行线上的WORD_LEN是独立的。例如,你可以从线上接收24位数据(WORD_LEN=24),但选择在内存中只存储高16位(MEM_LEN_24=0),这相当于自动进行了截断处理。
2.3 通道映射与数据屏蔽
I2S:AIFWMASK0和I2S:AIFWMASK1寄存器分别控制AD0和AD1引脚上的通道映射。这是一个非常灵活的功能,允许你选择性地接收或发送多通道音频流中的特定通道。
- 在双相位模式(
DUAL_PHASE=1)下:只有寄存器的低两位(MASK[1:0])有效。0x01表示单声道(Mono)模式,只处理左声道(通道0);0x03表示立体声(Stereo)模式,处理左(通道0)和右(通道1)两个声道。在单声道输入时,只有左声道数据会被存入内存;在单声道输出时,左声道数据会被重复输出到右声道上。 - 在单相位模式(
DUAL_PHASE=0,DSP格式)下:MASK寄存器的8个位(MASK[7:0])可以分别对应一个帧内的最多8个通道。例如,MASK = 0x0F表示使能前4个通道。这对于多通道音频应用(如环绕声)非常有用。被屏蔽的通道在输入时不会被存储,在输出时则输出恒定低电平。
2.4 DMA缓冲区与指针管理
DMA是I2S模块高效运转的引擎,其核心是两组指针寄存器:AIFINPTRNEXT/AIFINPTR(输入)和AIFOUTPTRNEXT/AIFOUTPTR(输出)。
AIFDMACFG.END_FRAME_IDX:这个寄存器定义了每个DMA缓冲区包含多少帧音频数据。设置的值是“帧数减一”。例如,如果你想设置一个包含256帧音频的缓冲区,就写入255 (0xFF)。向此寄存器写入非零值,是最终启动DMA和整个I2S接口的动作。在此之前,所有其他配置必须已完成。AIFINPTRNEXT/AIFOUTPTRNEXT:这是“下一个”缓冲区指针。软件需要提前把下一块内存缓冲区的起始地址写入这里。当当前缓冲区用完时,DMA控制器会自动将NEXT指针的值加载到当前指针,并将NEXT寄存器清零,同时触发中断(如果使能)。软件必须在中断处理程序或轮询中,检测到NEXT指针为零后,及时写入下一个缓冲区的地址,否则会导致PTR_ERR错误,DMA停止。AIFINPTR/AIFOUTPTR:这是只读寄存器,显示DMA控制器当前正在访问的内存地址。用于调试和监控DMA进度。
启动DMA有一个特定的“预加载”流程:1) 写入第一个缓冲区地址到NEXT寄存器;2) 配置END_FRAME_IDX(启动DMA,此时NEXT指针值被加载到当前指针PTR);3)立即写入第二个缓冲区地址到NEXT寄存器。对于输出DMA,在步骤2之后,它会立即预取前两个音频采样字。
2.5 采样时间戳生成器配置
采样时间戳生成器是用于精确控制DMA启动时机和实现无线同步的高级功能。其核心是两个计数器:STMPWCNT(WCLK帧计数器)和STMPXCNT(48MHz XOSC时钟周期计数器)。
STMPWPER:设置WCLK计数器的模值。它通常应设置为DMA缓冲区大小的整数倍(N * (END_FRAME_IDX + 1))。这个值也定义了音频延迟的帧数。STMPWCNT会从0递增到此值后归零,循环计数。STMPINTRIG和STMPOUTTRIG:这是输入和输出DMA的启动触发器。当STMPWCNT的值等于这两个寄存器中设置的值时,对应的DMA通道将在下一个WCLK周期开始工作。为了避免上电时的误触发,初始时应将它们设置为一个大于STMPWPER的值。在不需要无线同步的简单应用中,可以在启动前将它们设置为(STMPWCNT + 2) % STMPWPER,让DMA在不久后开始。STMPCTL.EN:时间戳生成器的总开关。必须在所有相关配置完成后才能置1。
通过捕获无线事件(如射频同步字收发)瞬间的STMPWCNTCAPT0和STMPXCNTCAPT0值,可以计算出精确的采样时间戳,用于对齐两个无线节点间的音频播放,实现唇音同步。
3. 四种串行格式的实战配置与对比
理论需要结合实践。下面我们以常见的48kHz采样率、24位深度、立体声音频为例,分别详解四种格式的配置,并对比其异同。假设我们使用内部时钟,BCLK频率设为64 * Fs = 3.072 MHz。
3.1 标准I2S格式配置
标准I2S格式是最常见的格式。其特点是WCLK在左声道期间为低电平,右声道期间为高电平;数据的MSB在WCLK边沿(左声道到右声道切换或反之)后的第二个BCLK上升沿开始传输。
寄存器配置:
AIFFMTCFG.DUAL_PHASE = 1(双相位)AIFFMTCFG.WORD_LEN = 24(24位字长)AIFFMTCFG.SMPL_EDGE = 1(在BCLK上升沿采样数据)AIFFMTCFG.DATA_DELAY = 1(关键:I2S格式延迟1个BCLK)AIFFMTCFG.MEM_LEN_24 = 1(内存中按24位存储)AIFWCLKSRC.WCLK_INV = 1(关键:因为I2S标准中左声道对应WCLK低电平,而模块默认左声道对应WCLK高?这里需要根据具体CODEC调整。通常,如果CODEC规定左声道对应WCLK低,而模块在WCLK高时传输左声道,则需要反相。手册示例中I2S格式设为了1。)AIFWMASK0.MASK = 0x03(立体声)
计算与解释:对于48kHz,双相位,WCLK频率就是48kHz。若BCLK = 64 * Fs = 3.072 MHz,则每相位(左或右声道)有3.072MHz / (48kHz * 2) = 32个BCLK周期。DATA_DELAY=1意味着在WCLK边沿后,有1个BCLK的“空白”期,然后才开始传输24位数据。传输完成后,剩余的32 - 1 - 24 = 7个BCLK周期为空闲期。这完全符合I2S标准时序。
3.2 左对齐格式(LJF)配置
左对齐格式下,数据的MSB直接对齐WCLK的边沿,没有I2S格式的那个BCLK延迟。WCLK占空比仍为50%。
寄存器配置:
AIFFMTCFG.DUAL_PHASE = 1AIFFMTCFG.WORD_LEN = 24AIFFMTCFG.SMPL_EDGE = 1AIFFMTCFG.DATA_DELAY = 0(关键:左对齐无延迟)AIFFMTCFG.MEM_LEN_24 = 1AIFWCLKSRC.WCLK_INV = 0(通常不需要反相,左声道对应WCLK高)AIFWMASK0.MASK = 0x03
对比与注意事项:LJF格式的时序更紧凑,在WCLK边沿变化后立即开始传输数据。这要求接收端必须能在第一个BCLK周期就准备好锁存数据。与I2S格式相比,它节省了1个BCLK周期的开销,在高速或高位数传输时更有优势。配置时务必确认你的音频从设备支持LJF格式。
3.3 右对齐格式(RJF)配置
右对齐格式下,数据的LSB对齐WCLK的边沿。这意味着在WCLK边沿变化时,整个24位数据已经传输完毕。
寄存器配置:
AIFFMTCFG.DUAL_PHASE = 1AIFFMTCFG.WORD_LEN = 24(这里填精确位数24)AIFFMTCFG.SMPL_EDGE = 1AIFFMTCFG.DATA_DELAY = BCLKs_per_phase - WORD_LEN(关键:计算延迟)AIFFMTCFG.MEM_LEN_24 = 1AIFWCLKSRC.WCLK_INV = 0AIFWMASK0.MASK = 0x03
计算示例:同样每相位32个BCLK周期。DATA_DELAY = 32 - 24 = 8。这意味着WCLK边沿变化后,先有8个BCLK周期的空闲,然后开始传输24位数据,并且当最后一位(LSB)移出时,恰好对齐下一个WCLK边沿。必须确保DATA_DELAY + WORD_LEN <= BCLKs_per_phase,本例中8+24=32,刚好等于。
3.4 DSP格式配置
DSP格式是一种单相位格式,常用于TI的DSP处理器。WCLK是一个单周期的高脉冲,标志帧开始,之后多个声道的数据连续传输,中间没有WCLK变化。
寄存器配置:
AIFFMTCFG.DUAL_PHASE = 0(关键:单相位)AIFFMTCFG.WORD_LEN = 24(精确位数)AIFFMTCFG.SMPL_EDGE = 0(注意:DSP格式通常在BCLK下降沿采样)AIFFMTCFG.DATA_DELAY = 0或1(定义WCLK脉冲后到第一个数据开始的延迟)AIFFMTCFG.MEM_LEN_24 = 1AIFWCLKSRC.WCLK_INV = 0AIFWMASK0.MASK = 0x03(使能通道0和1,对应左和右)
特殊计算:在DSP模式下,一个WCLK周期内要传输所有声道的数据。假设立体声(2声道),每声道24位。那么需要的最小BCLK周期数为:DATA_DELAY + (WORD_LEN * channel_count)。channel_count由AIFWMASKx.MASK中置位的位数决定。例如,DATA_DELAY=1,WORD_LEN=24,MASK=0x03(2通道),则所需BCLK周期为1 + (24 * 2) = 49。你需要配置PRCM的WDIV参数,确保BCLK频率 / WCLK频率大于等于49。如果配置的BCLK周期数少于所需,会导致数据被截断,产生严重错误。
格式选择小结:选择哪种格式,首要取决于你的外部音频器件(CODEC、ADC、DAC)支持哪种格式。绝大多数消费级音频编解码器都支持I2S和LJF。RJF较少见。DSP格式则多在与特定DSP芯片对接时使用。在寄存器配置时,务必反复检查DUAL_PHASE、DATA_DELAY、WCLK_INV这几个关键字段。
4. 时钟配置与DMA深度实战
4.1 内部时钟生成与计算
使用内部时钟时,MCLK、BCLK、WCLK均由PRCM模块从48MHz系统时钟分频得到。配置集中在PRCM的相关寄存器中。
- MCLK频率:
MCLK = 48 MHz / PRCM:I2SMCLKDIV.MDIV。MCLK通常为采样频率Fs的256倍(12.288MHz)或384倍(18.432MHz),用于为外部高性能音频器件提供低抖动的系统时钟。设置MDIV = 48MHz / 12.288MHz = 4。 - BCLK频率:
BCLK = 48 MHz / PRCM:I2SBCLKDIV.BDIV。BCLK = 每采样位 * 声道数 * Fs。对于24位立体声I2S,每相位32个BCLK,一帧(左右声道)64个BCLK。所以BCLK = 64 * Fs = 3.072 MHz。计算BDIV = 48MHz / 3.072MHz = 15.625,但分频器必须是整数,所以取BDIV = 16,此时实际BCLK = 3.0 MHz,会产生轻微误差。更精确的做法是选择Fs使得分频为整数,例如32kHz或48kHz。 - WCLK频率(双相位):
WCLK = BCLK / (2 * PRCM:I2SWCLKDIV.WDIV[9:0])。WCLK就是Fs。由公式反推:WDIV = BCLK / (2 * Fs) / 2? 不对,应该是WDIV = BCLK / (2 * Fs)。代入BCLK=3.072MHz,Fs=48kHz,得WDIV = 3.072M / (2*48k) = 32。这意味着WCLK高电平和低电平各持续32个BCLK周期,总共64个BCLK一帧,与之前计算吻合。关键步骤:需要设置PRCM:I2SCLKCTL.WCLK_PHASE = 1来选择双相位模式。
配置流程示例(使用TI DriverLib):
// 假设使用48kHz, 24bit, 立体声,I2S格式,内部时钟 // 1. 配置PRCM时钟源 PRCMI2SClockFreqSet(PRCM_I2S_48MHZ, PRCM_I2S_SAMPLING_48KHZ); // 这是一个高阶API,内部会计算分频 // 或者手动配置: PRCMI2SClockConfigure(PRCM_I2S_CLK_SRC_XOSC_HF, // 必须使用XOSC_HF作为48MHz源以降低抖动 PRCM_I2S_SAMPLING_48KHZ, PRCM_I2S_WCLK_PHASE_DUAL); // 双相位 // 2. 计算并设置分频器 (以下为示意,实际参数需根据公式计算) PRCM->I2SMCLKDIV = 4 - 1; // MDIV寄存器是分频值-1 PRCM->I2SBCLKDIV = 16 - 1; // BDIV寄存器是分频值-1 PRCM->I2SWCLKDIV = 32; // WDIV直接写入值 PRCM->I2SCLKCTL |= PRCM_I2SCLKCTL_EN; // 使能I2S时钟生成4.2 DMA缓冲区与指针管理实战
DMA缓冲区的设计直接影响系统的实时性和稳定性。缓冲区太小,会导致CPU频繁被中断处理,增加系统负载,甚至可能因处理不及时导致缓冲区溢出/下溢。缓冲区太大,则会增加音频延迟。
缓冲区大小计算:假设我们想要一个10ms的音频缓冲区。
- 单声道,16位内存存储:
缓冲区大小(字节) = 采样率 * (位深/8) * 通道数 * 时间(s) = 48000 * 2 * 1 * 0.01 = 960 字节。 - 立体声,24位内存存储(
MEM_LEN_24=1):每个采样占4字节(但有效数据24位)。缓冲区大小(字节) = 48000 * 4 * 2 * 0.01 = 3840 字节。 - 帧数计算:
帧数 = 采样率 * 时间(s) = 48000 * 0.01 = 480 帧。 - 因此,
END_FRAME_IDX = 480 - 1 = 479。
双缓冲(乒乓缓冲)实现:这是最常用的策略。需要两个大小相等的缓冲区(BufA, BufB)。
- 初始化:
uint8_t audioBufA[3840], audioBufB[3840]; // 假设立体声24位存储 I2S->AIFINPTRNEXT = (uint32_t)audioBufA; // 预加载第一个输入缓冲区地址 I2S->AIFDMACFG = 479; // 设置缓冲区帧数,启动DMA I2S->AIFINPTRNEXT = (uint32_t)audioBufB; // 立即预加载第二个缓冲区地址 // 类似配置输出DMA的 AIFOUTPTRNEXT - 中断服务程序(ISR)处理:
关键点:必须在当前缓冲区被DMA使用完之前,将下一个缓冲区的地址写入void I2S_IRQHandler(void) { uint32_t irqFlags = I2S->IRQFLAGS; if (irqFlags & I2S_IRQFLAGS_AIF_DMA_IN) { // 输入缓冲区已满(例如audioBufA) processAudioData((uint32_t*)audioBufA); // 处理数据 I2S->AIFINPTRNEXT = (uint32_t)audioBufA; // 重新提交该缓冲区地址 I2S->IRQCLR = I2S_IRQCLR_AIF_DMA_IN; // 清除中断标志(写入1清除) } if (irqFlags & I2S_IRQFLAGS_AIF_DMA_OUT) { // 输出缓冲区已空(例如audioBufB) fillAudioData((uint32_t*)audioBufB); // 填充新的音频数据 I2S->AIFOUTPTRNEXT = (uint32_t)audioBufB; // 重新提交该缓冲区地址 I2S->IRQCLR = I2S_IRQCLR_AIF_DMA_OUT; } // ... 处理其他错误中断 (PTR_ERR, BUS_ERR等) }NEXT寄存器。中断方式是最可靠的。轮询方式风险较高,因为如果CPU被其他高优先级任务阻塞,可能错过时机。
4.3 采样时间戳生成器在无线音频同步中的应用
对于无线音频传输(如真正的无线立体声耳机TWS),保持主从设备间极低的延迟和完美的同步是巨大挑战。CC13x2/CC26x2的采样时间戳生成器为此提供了硬件支持。
实现恒定延迟的基本思路:
- 定义主从:一个设备作为音频时钟主设备(Master),使用内部时钟或高精度晶振。另一个作为从设备(Slave),使用外部时钟输入(来自主设备的MCLK或BCLK),并且其时钟频率可以通过某些方式微调(例如,使用可编程的时钟发生器或通过软件调整从设备I2S模块的预期WCLK周期数)。
- 设置公共的缓冲区周期:主从设备设置相同的
STMPWPER值,例如N * 缓冲区帧数。STMPWPER定义了时间戳计数器的模,也代表了音频流水线的总延迟周期数。 - 时间戳捕获与交换:
- 主设备在通过射频发送音频数据包的同步字(preamble)时,触发一个事件(通过
EVENT:I2SSTMPSEL0配置),捕获此时的STMPWCNTCAPT0和STMPXCNTCAPT0,将这个“采样时间戳”嵌入到无线数据包中。 - 从设备在射频接收到该数据包的同步字时,同样触发事件捕获自己的时间戳。
- 主设备在通过射频发送音频数据包的同步字(preamble)时,触发一个事件(通过
- 从设备对齐:
- 从设备比较接收到的主设备时间戳和自己的时间戳,计算出一个偏差。
- 初始偏移:通过写入
STMPWSET或STMPWADD寄存器,调整从设备的STMPWCNT计数器,使其与主设备对齐。 - 动态调整:在运行中,从设备持续监测偏差。如果从设备“跑得快了”(时间戳领先),就轻微调低其外部音频时钟源的频率(或增加其预期的WCLK周期数),使其“慢下来”;反之亦然。这个调整过程是一个闭环控制,目标是使主从时间戳差趋于零。
- DMA触发点设置:通过合理设置
STMPINTRIG和STMPOUTTRIG,可以确保音频数据的采集和播放与这个全局的时间戳计数器精确对应,从而保证从设备播放的音频数据帧与主设备在时间上是严格对齐的。
这个过程实现了网络级的音频同步,延迟恒定且可预测,是开发高性能无线音频产品的关键技术。
5. 常见问题排查与调试技巧
即使按照手册配置,也难免会遇到问题。以下是一些常见坑点及排查方法。
5.1 无声或杂音问题排查
- 检查时钟:这是最常见的问题。首先用示波器或逻辑分析仪测量BCLK和WCLK引脚是否有信号,频率是否正确。如果没有时钟,检查:
- PRCM模块的I2S时钟是否使能(
PRCM:I2SCLKCTL.EN)。 - 时钟源选择(
PRCM:I2SBCLKSEL.SRC和I2S:AIFWCLKSRC.WCLK_SRC)是否一致且正确。 - 如果使用外部时钟,检查外部主设备是否已输出时钟。
- PRCM模块的I2S时钟是否使能(
- 检查数据线:确认ADx引脚是否有数据波形。如果没有,检查:
- 引脚复用配置(IOC)是否正确映射到AIF。
AIFDIRCFG寄存器中引脚方向(输入/输出)设置是否正确。- 对于输出,DMA是否已启动并正确加载了数据?检查
AIFOUTPTR是否在递增。
- 检查格式匹配:用逻辑分析仪解码I2S信号,确认时序是否符合预期。重点检查:
WCLK_INV设置是否正确?左/右声道与WCLK电平关系是否与CODEC匹配?DATA_DELAY是否正确?MSB/LSB是否对齐WCLK边沿?SMPL_EDGE(采样边沿)是否与从设备匹配?通常是在BCLK的上升沿采样,但有些设备可能相反。
- 检查DMA和缓冲区:
- 确认
END_FRAME_IDX已写入非零值。 - 确认输入/输出的
AIFxPTRNEXT指针已正确加载了两个缓冲区的地址(启动序列)。 - 检查是否有
PTR_ERR或BUS_ERR中断标志被置位。这表示指针未及时更新或DMA传输超时。 - 检查内存缓冲区是否在DMA可访问的区域(如SRAM),并且地址是否对齐(16位存储时需半字对齐)。
- 确认
5.2 数据错位或失真
WORD_LEN与MEM_LEN_24不匹配:如果你从线上接收24位数据(WORD_LEN=24),但在内存中按16位存储(MEM_LEN_24=0),那么低8位数据会被丢弃。反之,如果线上是16位,内存是24位,则高8位会补零。确保这两个参数与你的音频数据流真实位深一致。AIFWMASK配置错误:在立体声应用中,如果误设为0x01(单声道),则只会存储或播放一个声道的数据,导致声音异常。在DSP多通道模式下,错误的掩码会导致通道错乱。- 缓冲区大小与中断处理不匹配:如果CPU处理音频数据(如编码、滤波)的时间超过了一个DMA缓冲区的持续时间,就会导致缓冲区溢出(输入)或下溢(输出),表现为声音卡顿、爆音。解决方法是增大缓冲区(增加
END_FRAME_IDX)或优化音频处理算法降低耗时。 - 时钟抖动(Jitter):如果使用内部时钟且系统负载变化大,可能导致BCLK抖动,影响音质。确保系统高频时钟(SCLK_HF)源始终为外部晶体(XOSC_HF),而不是内部RC振荡器(RCOSC_HF),因为后者精度和稳定性较差。
5.3 调试工具与技巧
- 利用PWM调试输出:
AIFPWMVALUE寄存器可以生成一个与DMA缓冲区开始同步的PWM脉冲。将其连接到GPIO并用示波器观察,可以精确测量DMA的启动时间、缓冲区周期,是调试采样时间戳和同步功能的利器。 - 监控寄存器状态:在调试时,定期读取以下寄存器非常有帮助:
STMPWCNT/STMPXCNT:了解时间戳计数器的运行状态。AIFINPTR/AIFOUTPTR:确认DMA是否在持续搬运数据。IRQFLAGS:第一时间发现错误。
- 分步启动:严格按照手册的启动序列操作。一个稳妥的调试方法是:先只配置时钟和最简单的输出(如固定输出静音数据),用逻辑分析仪验证时序。然后再逐步加入DMA、输入、复杂格式等功能。
- 参考TI官方软件:TI的SimpleLink SDK中通常提供I2S的驱动示例(例如在
ti/drivers/i2s目录下)。这些示例代码展示了正确的配置流程和DMA处理框架,是极好的学习起点。但要注意,SDK的API可能封装了部分底层细节,当需要实现特定高级功能(如精确同步)时,仍需直接操作寄存器。
通过系统地理解寄存器功能、严格遵循配置顺序、并善用硬件提供的调试手段,你就能驾驭CC13x2/CC26x2上这个强大的I2S音频子系统,为你的嵌入式音频应用打下坚实的基础。