1. I2S接口核心原理与嵌入式音频系统设计在嵌入式音频开发领域I2SInter-IC Sound接口是连接数字音频处理器、编解码器和微控制器的基石。我第一次接触I2S是在一个车载娱乐系统的项目上当时需要将MCU处理后的音频数据实时传输给外部的DAC芯片。尝试过PCM接口但时钟抖动导致的音质劣化问题让我头疼不已直到切换到I2S架构问题才迎刃而解。I2S的精妙之处在于它将数据、时钟和帧同步信号彻底分离这种设计让它在处理16位、24位甚至32位高保真音频时能够保持极低的时基误差。简单来说你可以把I2S想象成一条精心组织的音频流水线。BCLK位时钟就像流水线的传送带节拍每一个节拍移动一位数据LRCK左右声道时钟即帧同步则像是一个分拣员告诉系统当前传送的是左声道还是右声道的数据而SDATA串行数据就是在这条传送带上流动的音频样本本身。这种物理分离的架构使得接收端无需从数据流中提取时钟从根本上避免了因时钟恢复带来的抖动问题。在实际的嵌入式系统中这意味着更纯净的声音输出和更稳定的系统性能。为什么在CC32xx这类资源受限的微控制器上I2S依然如此重要答案在于它的高效与灵活。对于需要连接多个音频外设如麦克风阵列、音频解码芯片、数字功放的物联网设备或便携式音频产品I2S支持主从模式和多声道TDM时分复用的能力让单一MCU可以轻松管理复杂的音频路由。例如你可以配置CC32xx作为主设备为从属的音频编解码器提供统一的时钟源确保整个音频链路的同步性这对于实现唇音同步或多房间音频系统至关重要。注意在设计I2S音频系统时首要考虑的是时钟精度。即使是最优秀的音频算法如果时钟源存在漂移或抖动最终输出的音质也会大打折扣。对于CC32xx其I2S主时钟由PRCM模块提供初始默认为24MHz但可以通过分频器进行精细调整这是保证音频质量的第一步。1.1 I2S数据格式与帧结构深度解析I2S标准定义了多种数据格式但最常用的是Philips标准格式。在这种格式下当LRCK线为低电平时表示正在传输左声道数据高电平时则传输右声道数据。数据在BCLK的下降沿变化并在上升沿被采样具体极性可配置。每个音频样本的数据位从最高有效位MSB开始传输并在传输完成后根据槽位大小进行填充或截断。这里有一个关键概念叫“槽位大小”Slot Size。它定义了每个音频样本在帧中所占的位数。例如对于16位音频数据你可以将槽位大小设置为16位这样数据位与槽位完美对齐。但有时为了兼容24位精度的音频编解码器即使MCU只处理16位数据也需要将槽位大小设置为24位或32位。此时多出来的低位需要用0填充Padding或者数据在槽位内进行左对齐或右对齐。CC32xx的I2S模块通过I2SConfigSetExpClk函数中的配置参数如I2S_SLOT_SIZE_16或I2S_SLOT_SIZE_24来灵活处理这种情况。帧同步信号的宽度和极性是另一个配置要点。标准I2S中LRCK信号在一个音频样本周期内变化一次。但有些设备可能需要更宽或更窄的帧同步脉冲。CC32xx的帧同步生成器允许你独立配置脉冲宽度。极性配置则决定了数据在帧同步信号的哪个边沿有效。例如设置I2S_INACT_LOW_LEVEL意味着在帧同步信号为低电平期间传输数据。这些细节必须与连接的从设备数据手册要求严格匹配否则会导致数据错位产生刺耳的噪音。1.2 CC32xx I2S模块架构与数据流剖析CC32xx的I2S模块是一个高度集成的多通道音频串行端口其内部结构远比简单的三线接口复杂。从系统层面看它位于设备互联矩阵上拥有独立的时钟域和电源域这为低功耗音频播放提供了可能。模块的核心是发送和接收状态机它们协同TDM序列器管理着多个串行器Serializer的数据收发时序。数据流入流出模块主要有两条路径CPU端口和DMA端口。CPU端口就像一条小路数据需要CPU亲自“搬运”。当使用I2SDataPut或I2SDataGet这类API时CPU会阻塞等待直到发送缓冲区有空位或接收缓冲区有数据。这种方式简单直接适合低数据率或非实时的音频处理任务。然而对于44.1kHz或48kHz的连续音频流CPU频繁被中断来搬运数据会导致系统负载过高影响其他任务执行。此时DMA端口就是一条高速公路。DMA控制器可以不经过CPU直接在I2S缓冲区和系统内存之间搬运数据。在CC32xx中发送和接收各有一个DMA端口地址I2S_TX_DMA_PORT和I2S_RX_DMA_PORT。当配置为DMA模式时I2S模块会根据FIFO的水位自动触发DMA请求。例如你可以设置当发送FIFO的空闲空间大于等于4个数据字对应两个立体声样本时触发DMA传输。这样CPU只需在初始化时设置好DMA描述符源地址、目标地址、数据量就可以解放出来处理音频编解码、网络通信等更复杂的任务从而实现高效的实时音频流处理。2. CC32xx I2S驱动配置实战从时钟树到数据收发理论清晰之后我们进入实战环节。配置CC32xx的I2S驱动就像组装一台精密的仪器必须按照正确的顺序和参数进行。整个流程可以概括为时钟配置 - 模块初始化与基础配置 - 串行器与工作模式配置 - 数据收发机制中断/DMA启用。下面我将以实现一个44.1kHz、16位立体声、主模式音频播放器为例拆解每一个步骤。2.1 时钟配置计算与PRCM模块设置一切始于时钟。CC32xx的I2S模块主时钟由PRCM电源、复位和时钟管理模块提供其源是一个240MHz的系统时钟。默认情况下一个分频器将其设置为24MHz输出给I2S模块。但我们的目标比特率是44.1kHz * 2声道 * 16位 1.4112 Mbps。模块内部还有两级分频器用于生成最终的位时钟BCLK。计算模块输入时钟频率是关键第一步。TI推荐将模块输入时钟ulI2SClk设置为所需比特率ulBitClk的整数倍通常为8倍、16倍或32倍以留出足够的余量供内部分频。这里我们选择10倍关系即模块时钟 1.4112 Mbps * 10 14.112 MHz。接下来我们需要通过PRCM模块的API来设置这个频率。// 步骤1计算所需比特率与模块时钟 #define SAMPLE_RATE_HZ 44100 #define BITS_PER_SAMPLE 16 #define NUM_CHANNELS 2 unsigned long ulBitClk SAMPLE_RATE_HZ * BITS_PER_SAMPLE * NUM_CHANNELS; // 1,411,200 Hz unsigned long ulI2SClk ulBitClk * 10; // 14,112,000 Hz // 步骤2使能I2S模块时钟并复位 PRCMPeripheralClkEnable(PRCM_I2S, PRCM_RUN_MODE_CLK); PRCMPeripheralReset(PRCM_I2S); // 步骤3设置I2S模块的输入时钟频率 PRCMI2SClockFreqSet(ulI2SClk);这里有一个极易忽略的坑PRCMI2SClockFreqSet函数设置的是分频器其输入是固定的240MHz。函数内部会根据你传入的目标频率ulI2SClk计算分频系数。CC32xx的分频器是小数分频器精度很高但并非所有频率都能完美实现。如果计算出的分频系数超出范围实际设置的频率可能会与目标有细微偏差。虽然对于音频来说微小的绝对频率偏差人耳难以察觉但若偏差过大可能导致从设备无法正确锁存数据。因此在关键应用中建议使用示波器或频率计实际测量输出的BCLK频率进行验证。2.2 模块初始化与串行器配置详解设置好时钟后接下来对I2S模块本身进行初始化。这包括设置数据格式、选择数据端口以及配置具体的串行器数据线。// 步骤4配置I2S模块基础参数 I2SConfigSetExpClk(I2S_BASE, // I2S模块基地址 ulI2SClk, // 模块输入时钟频率 (14.112 MHz) ulBitClk, // 所需比特率 (1.4112 Mbps) I2S_SLOT_SIZE_16 | // 槽位大小16位与我们的音频数据匹配 I2S_PORT_CPU); // 初始先使用CPU端口进行数据交互I2SConfigSetExpClk这个函数完成了多项重任它根据传入的模块时钟和比特率计算出内部两级分频器的值同时它通过ulConfig参数设置了数据格式。这里我们选择了16位槽位和CPU端口。如果你计划使用DMA后期需要重新配置为I2S_PORT_DMA。接下来是配置串行器。CC32xx的I2S模块通常提供至少两个串行器数据线可以独立配置为发送或接收。在我们的立体声播放例子中我们需要一个串行器来发送数据。但请注意在I2S标准中即使立体声数据左、右声道也是通过同一根数据线SDATA分时传输的。因此配置一个串行器为发送模式就足以传输立体声信号。// 步骤5配置串行器0为发送模式 I2SSerializerConfig(I2S_BASE, I2S_DATA_LINE_0, // 使用数据线0对应某个具体的AXR引脚 I2S_SER_MODE_TX, // 模式发送 I2S_INACT_LOW_LEVEL); // 非活动状态时数据线保持低电平I2S_INACT_LOW_LEVEL这个参数决定了在非传输时段例如帧同步间隔或槽位内未使用的位数据引脚的电平状态。保持低电平是一种常见的做法可以减少不必要的功耗和噪声。有些外设可能要求高电平或高阻态务必查阅你的音频编解码器数据手册。2.3 中断驱动数据收发实现对于实时音频使用中断来搬运数据是比轮询更高效的方式。我们需要注册中断服务程序ISR并在其中及时填充发送缓冲区或读取接收缓冲区。// 步骤6注册中断处理函数并使能发送数据中断 I2SIntRegister(I2S_BASE, I2SIntHandler); // 注册中断处理函数 I2SIntEnable(I2S_BASE, I2S_INT_XDATA); // 使能发送数据就绪中断 // 步骤7使能I2S模块为仅发送模式 I2SEnable(I2S_BASE, I2S_MODE_TX_ONLY);一旦模块使能时钟和帧同步信号就会开始输出。当发送缓冲区为空需要新的数据时就会触发I2S_INT_XDATA中断。中断服务程序ISR必须快速响应void I2SIntHandler(void) { unsigned long ulStatus I2SIntStatus(I2S_BASE); // 读取中断状态 if (ulStatus I2S_STS_XDATA) { // 发送缓冲区空中断 // 从你的音频数据缓冲区中获取下一个样本例如一个16位的左声道数据 int16_t nextSample get_next_audio_sample(); // 将数据写入I2S发送缓冲区。注意数据需要根据格式处理。 // 对于16位左对齐数据可能需要左移8位放入32位寄存器。 I2SDataPutNonBlocking(I2S_BASE, I2S_DATA_LINE_0, (unsigned long)nextSample 8); // 清除中断标志位非常重要 I2SIntClear(I2S_BASE, I2S_STS_XDATA); } // 可以添加接收中断处理等其他逻辑 }实操心得在中断服务程序里一定要用I2SDataPutNonBlocking而非I2SDataPut。NonBlocking版本会立即返回如果缓冲区满则返回错误你可以选择丢弃一帧数据或做其他处理。而阻塞版本会在缓冲区满时死等这很可能导致中断响应超时引发系统不稳定甚至死锁。音频流处理中偶尔丢帧产生的“咔嗒”声远比系统崩溃更容易被接受。3. 高级应用DMA传输与FIFO缓冲区管理当音频流数据量增大或系统有其他高优先级任务时中断驱动的CPU搬运方式会显得力不从心。此时直接内存访问DMA是提升系统效率和稳定性的不二之选。CC32xx的I2S模块与DMA控制器紧密集成可以自动管理数据流极大减轻CPU负担。3.1 DMA传输配置与链路建立配置DMA传输的核心思想是让DMA控制器在I2S模块和内存中的音频缓冲区之间建立一条自动化的数据通道。你需要先配置I2S模块使用DMA端口然后设置DMA控制器的传输描述符。首先修改之前的配置告诉I2S模块我们将使用DMA端口来提供数据// 重新配置I2S模块选择DMA端口注意此操作应在模块Disable状态下进行 I2SDisable(I2S_BASE); // 假设我们已有一个存放音频数据的数组 pAudioBuffer I2SConfigSetExpClk(I2S_BASE, ulI2SClk, ulBitClk, I2S_SLOT_SIZE_16 | I2S_PORT_DMA); I2SEnable(I2S_BASE, I2S_MODE_TX_ONLY);接下来是DMA控制器的配置。CC32xx的DMA控制器功能强大但配置稍显复杂。你需要定义一个DMA控制表其中包含传输的源地址、目的地址、数据量等信息。// 定义一个DMA控制表项通常需要对齐到特定边界 #pragma DATA_ALIGN(g_sDMAControlTable, 1024) tDMAControlTable g_sDMAControlTable; // 配置DMA通道以UDMA通道0为例 uDMAChannelAssign(UDMA_CHANNEL_I2S_TX); // 将DMA通道分配给I2S发送事件 uDMAChannelAttributeEnable(UDMA_CHANNEL_I2S_TX, UDMA_ATTR_USEBURST | UDMA_ATTR_HIGH_PRIORITY); // 设置DMA控制表项从内存到I2S发送端口 g_sDMAControlTable.pvSrcAddr pAudioBuffer; // 源地址音频数据数组 g_sDMAControlTable.pvDstAddr (void *)I2S_TX_DMA_PORT; // 目的地址I2S发送DMA端口 g_sDMAControlTable.ulControl (sizeof(pAudioBuffer) / sizeof(uint32_t)) 4 | // 传输数据量以字为单位 UDMA_SIZE_32 | // 数据大小32位 UDMA_SRC_INC_32 | // 源地址递增 UDMA_DST_INC_NONE | // 目的地址固定外设端口 UDMA_ARB_4 | // 仲裁大小影响传输块大小 UDMA_MODE_PINGPONG; // 使用乒乓模式实现连续传输 uDMAChannelTransferSet(UDMA_CHANNEL_I2S_TX, UDMA_MODE_PINGPONG, g_sDMAControlTable, 0); uDMAChannelEnable(UDMA_CHANNEL_I2S_TX); // 使能DMA通道乒乓模式是实现无缝音频流传输的关键。它需要两个DMA描述符通常称为Ping和Pong。当DMA正在从Ping缓冲区向I2S传输数据时CPU可以同时向Pong缓冲区填充下一段音频数据。当Ping缓冲区传输完毕DMA会自动切换到Pong缓冲区并触发一个中断通知CPU去填充刚刚传输完的Ping缓冲区。如此循环实现了数据传输和数据处理的重叠避免了音频流的中断。3.2 FIFO缓冲区配置与水位控制I2S模块内部的FIFO先入先出缓冲区是连接串行移位寄存器和DMA/CPU端口的关键枢纽。合理配置FIFO可以平滑数据流防止上溢Overflow或下溢Underrun。对于发送TXFIFO作用临时存储从DMA或CPU送来的数据再按位时钟节奏送给串行器发送。水位控制通过I2STxFIFOEnable函数的ulTxLevel参数设置。当FIFO中剩余的数据量低于此水位时会触发DMA请求如果使能了DMA或中断如果使能了中断请求主机填充新数据。关键配置ulWordsPerTransfer必须设置为使能为发送器的串行器数量。在我们的单发送器例子中此值应为1。// 配置并使能发送FIFO // ulTxLevel 2: 当FIFO中数据少于2个字时触发DMA请求。 // ulWordsPerTransfer 1: 每次DMA传输传输1个字对应一个串行器的一个数据。 I2STxFIFOEnable(I2S_BASE, 2, 1);对于接收RXFIFO逻辑类似但方向相反。它从串行器接收数据攒够一定量后通知DMA或CPU取走。水位设置的权衡水位设置得太低例如1DMA请求会非常频繁增加了总线仲裁开销可能影响其他外设。水位设置得太高例如接近FIFO深度则缓冲能力增强但引入了更大的音频延迟Latency。对于实时交互应用如语音通话延迟需要控制在几十毫秒内因此水位不宜过高。对于音乐播放可以适当提高水位以增强抗抖动能力。CC32xx的I2S FIFO深度通常为8个字或16个字你需要查阅具体型号的数据手册。一个实用的调试技巧是使用I2STxFIFOStatusGet和I2SRxFIFOStatusGet函数。你可以在中断或主循环中定期读取FIFO状态监控其数据量变化。如果发现发送FIFO经常被读空下溢说明数据供给速度跟不上消耗速度需要检查DMA配置或提高CPU填充数据的优先级。如果接收FIFO经常满上溢说明数据消费太慢需要优化数据读取逻辑。4. 同步收发模式与多声道TDM配置在某些应用场景如主动降噪耳机或音频会议系统需要同时进行音频的采集和播放并且两者必须严格同步以避免回声或音画不同步。CC32xx的I2S模块支持同步发送-接收模式I2S_MODE_TX_RX_SYNC。在此模式下发送和接收共享同一个位时钟BCLK和帧同步LRCK由I2S模块作为主设备产生确保采播时序完全对齐。配置同步模式与单发送模式类似但需要配置两个串行器并启用相应的中断。// 1. 基础初始化与时钟配置同上 PRCMPeripheralClkEnable(PRCM_I2S, PRCM_RUN_MODE_CLK); PRCMPeripheralReset(PRCM_I2S); PRCMI2SClockFreqSet(ulI2SClk); I2SConfigSetExpClk(I2S_BASE, ulI2SClk, ulBitClk, I2S_SLOT_SIZE_16 | I2S_PORT_CPU); // 2. 注册中断并使能发送和接收中断 I2SIntRegister(I2S_BASE, I2SIntHandler); I2SIntEnable(I2S_BASE, I2S_INT_XDATA | I2S_INT_RDATA); // 同时使能发送和接收中断 // 3. 配置串行器0为发送串行器1为接收 I2SSerializerConfig(I2S_BASE, I2S_DATA_LINE_0, I2S_SER_MODE_TX, I2S_INACT_LOW_LEVEL); I2SSerializerConfig(I2S_BASE, I2S_DATA_LINE_1, I2S_SER_MODE_RX, I2S_INACT_LOW_LEVEL); // 4. 使能I2S模块为同步收发模式 I2SEnable(I2S_BASE, I2S_MODE_TX_RX_SYNC);在对应的中断处理函数中你需要同时处理发送和接收中断void I2SIntHandler(void) { unsigned long ulStatus I2SIntStatus(I2S_BASE); static unsigned long ulRxData; if(ulStatus I2S_STS_XDATA) { // 发送缓冲区空填充下一个要播放的样本 I2SDataPutNonBlocking(I2S_BASE, I2S_DATA_LINE_0, get_next_tx_sample()); I2SIntClear(I2S_BASE, I2S_STS_XDATA); } if(ulStatus I2S_STS_RDATA) { // 接收缓冲区有数据读取采集到的样本 I2SDataGetNonBlocking(I2S_BASE, I2S_DATA_LINE_1, ulRxData); process_rx_sample(ulRxData); // 处理接收到的数据如写入缓冲区 I2SIntClear(I2S_BASE, I2S_STS_RDATA); } }4.1 TDM多声道扩展应用标准的I2S一帧只传输两个声道左、右。而TDM时分复用模式则允许在一根数据线上分时传输多个声道的数据非常适合连接多麦克风阵列或多路DAC。CC32xx的I2S模块内置了强大的TDM序列器可以支持多达32个时隙Slot。配置TDM模式的关键在于RTDM接收TDM时隙和XTDM发送TDM时隙寄存器。每个寄存器有32位每一位对应一个时隙。将某位置1表示在该时隙期间对应的串行器是活跃的进行收发。例如要配置一个8声道TDM接收使用串行器1并激活前8个时隙// 假设已完成基础I2S配置... // 配置接收格式可能需要调整帧长度和时隙大小 // 激活TDM模式并设置哪些时隙用于接收 HWREG(I2S_BASE I2S_O_RTDM) 0x000000FF; // 低8位置1表示时隙0-7用于接收 // 配置串行器1为接收模式 I2SSerializerConfig(I2S_BASE, I2S_DATA_LINE_1, I2S_SER_MODE_RX, I2S_INACT_LOW_LEVEL);在TDM模式下帧同步信号的频率不再是采样率而是采样率乘以每帧的时隙数。例如对于48kHz采样率、8时隙TDM帧同步频率为48kHz * 8 384kHz。位时钟频率则为帧同步频率 * 时隙大小位数。这些计算需要在配置时钟时格外注意。5. 调试技巧与常见问题排查实录即便按照手册一步步配置在实际硬件调试中I2S问题依然层出不穷。下面是我在多个项目中总结出的问题排查清单和实战技巧。5.1 无声问题排查流程这是最常见的问题。请按照以下步骤系统性地排查检查物理连接用万用表或示波器确认BCLK、LRCK、SDATA三条线是否连通有无对地短路或与电源短路。检查上拉/下拉电阻配置是否符合从设备要求。验证时钟信号使用示波器测量BCLK和LRCK引脚。有无信号如果没有回到代码检查I2SEnable函数是否被调用PRCM时钟是否使能。频率是否正确测量BCLK频率是否等于采样率 * 位数 * 声道数如果偏差很大检查PRCMI2SClockFreqSet和I2SConfigSetExpClk的参数计算。波形是否干净观察时钟信号是否有过冲、振铃或严重毛刺。这可能导致数据采样错误需要在PCB布局上检查时钟走线是否远离高频噪声源并考虑串联小电阻如22欧姆进行阻抗匹配。验证数据信号在BCLK和LRCK都正常的前提下测量SDATA线。是否有数据变化如果是一条静止的直线说明MCU没有成功写入发送缓冲区。检查中断或DMA是否正常触发。可以在中断服务程序里设置一个GPIO翻转用示波器看是否有脉冲以确认中断是否进入。数据是否对齐对照LRCK帧同步边沿检查SDATA数据的变化是否发生在正确的BCLK边沿根据配置是上升沿还是下降沿。数据错位是导致噪音的常见原因。检查从设备配置许多音频编解码器需要通过I2C或SPI进行初始化设置其工作模式、采样率、增益等。确认你的编解码器初始化代码已执行并且模式与MCU的I2S设置主/从、数据格式、时钟极性匹配。利用芯片诊断功能CC32xx的I2S模块状态寄存器XSTAT,RSTAT是强大的调试工具。在出现问题时读取这些寄存器可以快速定位。unsigned long xstat HWREG(I2S_BASE I2S_O_XSTAT); if (xstat I2S_STS_XUNDRN) { // 发送下溢数据供给太慢。 // 解决方案优化数据供给代码使用DMA或提高中断优先级。 } if (xstat I2S_STS_XSYNCERR) { // 意外的发送帧同步错误。检查从设备是否在异常时刻发出了帧同步信号在主机模式下不应发生。 }5.2 噪音与爆音问题分析如果能听到声音但伴有噪音、爆音或失真问题可能出在数据链路或处理环节。数据格式不匹配这是头号嫌疑犯。确认MCU和音频编解码器在以下方面完全一致数据对齐是左对齐MSB first、右对齐LSB first还是I2S格式数据在LRCK变化后第二个BCLK边沿有效位序是MSB先传还是LSB先传槽位大小MCU配置的槽位是16位但编解码器期望24位会导致数据错位。解决方法仔细比对双方数据手册的时序图调整I2SConfigSetExpClk中的格式配置或编解码器的寄存器配置。电源噪声模拟音频电路对电源噪声极其敏感。确保给音频编解码器的模拟电源AVDD是干净的最好使用独立的LDO供电并搭配π型滤波电路。数字电源DVDD和模拟电源之间使用磁珠隔离。将MCU的I2S信号线远离模拟音频走线。缓冲区管理错误在中断或DMA处理中如果音频缓冲区读写指针管理不当发生重叠Overrun或欠载Underrun就会引入“咔嗒”声。确保你的环形缓冲区Ring Buffer操作是线程安全的如果涉及RTOS任务或中断安全的。时钟抖动Jitter虽然I2S分离了时钟但时钟源本身的抖动仍会影响DAC的输出质量。如果追求高保真可以考虑使用外部低抖动的晶振作为时钟源并通过CC32xx的时钟输入引脚引入。5.3 性能优化与资源管理在资源紧张的嵌入式系统中优化I2S驱动的性能和内存占用至关重要。中断频率与CPU负载对于44.1kHz立体声16位音频中断频率为44.1kHz。每个中断服务程序执行时间必须远小于22.7us1/44.1kHz否则系统会崩溃。使用I2SDataPutNonBlocking并确保ISR内只做最必要的数据搬运。复杂的处理如音量调节、滤波应放在主循环或低优先级任务中。DMA缓冲区大小DMA的乒乓缓冲区大小需要权衡。缓冲区越大CPU被中断的频率越低但音频延迟也越大。对于语音通话缓冲区通常设置为5-20ms的音频数据量例如44.1kHz下10ms约为882个样本。对于音乐播放可以设置到100-500ms以减少中断。低功耗考虑在电池供电设备中当没有音频播放时应及时关闭I2S模块和时钟以省电。void stop_audio_playback(void) { I2SDisable(I2S_BASE); // 禁用I2S模块 // 如果需要可以关闭串行器 I2SSerializerConfig(I2S_BASE, I2S_DATA_LINE_0, I2S_SER_MODE_DISABLE, 0); // 最后可以关闭I2S模块时钟谨慎使用确保其他外设不依赖此时钟 // PRCMPeripheralClkDisable(PRCM_I2S); }引脚复用冲突CC32xx的引脚通常有多种功能。确保你使用的AXR、ACLKX、AFSX等引脚已通过PinTypeI2S等函数正确配置为I2S功能而不是被误配置为GPIO或其他外设功能。