NXP MCU 技术论坛
直播中

张涛

8年用户 1407经验值
私信 关注
[问答]

如何使用NXP S32K142/144中的Flexio在I2S中发送连续音频数据?

对于我的应用程序,我希望将连续的音频数据传输到我的放大器以获得连续的声音。我正在使用 S32K142/144 板。我正在使用 Flexio 进行 I2S 通信。请建议我应该遵循哪种方法来传输数据,即轮询、DMA 或中断。
目前我正在使用 DMA 方法,数据正在传输,但在数据传输的每次迭代之后、时钟会再次重新初始化、因此、我的放大器需要时间来生成 PWM 信号。请建议适当的方法,以便我可以在不重新初始化的情况下传输连续数据。

回帖(1)

晴兮晴兮

2025-3-25 17:52:30

为了在NXP S32K142/144中使用FlexIO实现I2S连续音频传输,避免时钟重新初始化,请按以下步骤优化配置:


1. 配置DMA为循环模式



  • 关键点:确保DMA通道设置为循环模式(Circular Mode),而非单次传输。这将使DMA在缓冲区末尾自动跳回起点,无需重新初始化。

  • 代码调整
     // 配置DMA传输描述符为循环模式
    DmaChannel_SetLoopMode(DMA_CH0, true);
    DmaChannel_SetTransferSize(DMA_CH0, BUFFER_SIZE); // BUFFER_SIZE为音频缓冲区大小


2. 使用双缓冲(Ping-Pong)技术



  • 关键点:双缓冲允许在一个缓冲区传输时填充另一个,避免数据断流。

  • 实现步骤

    • 分配两个缓冲区(BufferA和BufferB)。

    • 当DMA传输BufferA时,CPU或另一个DMA填充BufferB,反之亦然。


  • 代码示例
     // 在DMA完成中断中切换缓冲区
    void DMA_IRQHandler() {
         if (currentBuffer == BufferA) {
             DmaChannel_ConfigDestination(DMA_CH0, BufferB);
             currentBuffer = BufferB;
         } else {
             DmaChannel_ConfigDestination(DMA_CH0, BufferA);
             currentBuffer = BufferA;
         }
         // 处理数据填充(如从音频流读取到非活动缓冲区)
    }


3. 保持FlexIO时钟持续运行



  • 关键点:确保FlexIO定时器配置为连续模式,而非单次触发。

  • 配置检查
     // 初始化FlexIO定时器为连续运行
    FLEXIO_TIMER_CFG_Type timerConfig;
    timerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(0);
    timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveHigh;
    timerConfig.triggerSource = kFLEXIO_TimerTriggerSourceInternal;
    timerConfig.mode = kFLEXIO_TimerModeDual8BitBaudBit; // I2S常用模式
    timerConfig.output = kFLEXIO_TimerOutputOneNotAffectedByReset;
    timerConfig.decrementerResetCondition = kFLEXIO_TimerDecReloadOnTimerDisable;
    timerConfig.decrementerSource = kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput;
    timerConfig.reset = kFLEXIO_TimerResetNever;
    timerConfig.disable = kFLEXIO_TimerDisableNever; // 关键:定时器永不停止
    FLEXIO_TIMER_Init(FLEXIO0, &timerConfig, TIMER_CHANNEL);


4. 避免不必要的重新初始化



  • 关键检查点:确保DMA完成中断或传输完成回调中没有重置FlexIO或定时器的代码。

  • 处理建议:仅在初始启动时初始化FlexIO和DMA,传输过程中不再调用初始化函数。


5. 验证时钟源稳定性



  • 确认点:检查FlexIO的时钟源(如内部总线时钟或外部晶振)是否稳定,未被其他模块意外修改。

  • 代码检查
     // 确保FlexIO时钟源配置正确且未被更改
    CLOCK_SetFlexio0Clock(FLEXIO0_CLK_SOURCE); // 例如,使用PLL分频后的时钟


6. 调整中断优先级



  • 优化建议:提高DMA或FlexIO中断优先级,确保数据及时处理,避免缓冲区欠载。

  • 代码调整
     NVIC_SetPriority(DMA_CH0_IRQn, 1); // 设置DMA中断为较高优先级


7. 使用足够大的缓冲区



  • 经验值:缓冲区大小应至少容纳2个I2S帧(如双通道,16位,44.1kHz采样率,每帧4字节),建议设置为256字节以上,具体根据主频和数据处理速度调整。


验证步骤



  1. 使用逻辑分析仪或示波器检查SCK和WS信号,确认传输期间时钟持续运行。

  2. 监控DMA传输完成中断频率,确认其与音频采样率匹配(如44.1kHz时中断应为每采样周期一次)。

  3. 检查放大器输出是否无间隙噪声或断音。


通过以上调整,FlexIO和DMA将协同工作,实现无中断的I2S音频流传输,避免时钟重新初始化导致的延迟问题。

举报

更多回帖

发帖
×
20
完善资料,
赚取积分