野火电子论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 4178|回复: 1

悬赏!STM32F4x双缓冲DMA问题

[复制链接]
发表于 2022-10-16 09:30:17 | 显示全部楼层 |阅读模式
22火花
本帖最后由 fengge0832 于 2022-10-16 19:05 编辑

     STM32F407+WM8909硬件组合,音频采样是8K 16bit立体声,采集和播放侧都采用I2S DMA双缓冲机制目的减少CPU的处理消耗codec接收和写入数据后会产生DMA中断。播放侧设置half-buffer DMA中断,中断后通过freeRTOS信号通知任务线程进行下一个buffer数据拷贝从实际测试情况利用DMA双缓冲在STM32中会出现每一秒会多产生4~5个包(每个包32*2字节)总数据量是320字节的数据。是否有遇到该问题?排查方向是什么?


/* I2S2 init function */
void MX_I2S2_Init(void)
{

  hi2s2.Instance = SPI2;
  hi2s2.Init.Mode = I2S_MODE_MASTER_TX;
  hi2s2.Init.Standard = I2S_STANDARD_PHILIPS;
  hi2s2.Init.DataFormat = I2S_DATAFORMAT_16B;
  hi2s2.Init.MCLKOutput = I2S_MCLKOUTPUT_ENABLE;
  hi2s2.Init.AudioFreq = I2S_AUDIOFREQ_8K;
  hi2s2.Init.CPOL = I2S_CPOL_LOW;
  hi2s2.Init.ClockSource = I2S_CLOCK_PLL;
  hi2s2.Init.FullDuplexMode = I2S_FULLDUPLEXMODE_DISABLE;
  if (HAL_I2S_Init(&hi2s2) != HAL_OK)
  {
    Error_Handler();
  }

}

void HAL_I2S_MspInit(I2S_HandleTypeDef* i2sHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(i2sHandle->Instance==SPI2)
  {
  /* USER CODE BEGIN SPI2_MspInit 0 */

  /* USER CODE END SPI2_MspInit 0 */
    /* I2S2 clock enable */
    __HAL_RCC_SPI2_CLK_ENABLE();

    __HAL_RCC_GPIOB_CLK_ENABLE();
    __HAL_RCC_GPIOC_CLK_ENABLE();
    /**I2S2 GPIO Configuration   
    PB12     ------> I2S2_WS
    PB13     ------> I2S2_CK
    PB15     ------> I2S2_SD
    PC6     ------> I2S2_MCK
    */
    GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_15;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_6;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

    /* I2S2 DMA Init */
    /* SPI2_TX Init */
    hdma_spi2_tx.Instance = DMA1_Stream4;
    hdma_spi2_tx.Init.Channel = DMA_CHANNEL_0;
    hdma_spi2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_spi2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_spi2_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_spi2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
    hdma_spi2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
    hdma_spi2_tx.Init.Priority = DMA_PRIORITY_HIGH;

    hdma_spi2_tx.Init.Mode = DMA_CIRCULAR;
    hdma_spi2_tx.Init.FIFOMode = DMA_FIFOMODE_ENABLE;   
    hdma_spi2_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL;
    hdma_spi2_tx.Init.MemBurst = DMA_MBURST_SINGLE;
    hdma_spi2_tx.Init.PeriphBurst = DMA_PBURST_SINGLE;

    if (HAL_DMA_Init(&hdma_spi2_tx) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(i2sHandle,hdmatx,hdma_spi2_tx);

  /* USER CODE BEGIN SPI2_MspInit 1 */
  /* USER CODE END SPI2_MspInit 1 */
  }
}





static void mx_audio_play_task(void const* args)
{
    struct mx_audio_context* ctx = (struct mx_audio_context*)args;
    char pcm_buf[MX_PCM_STERO_SIZE] = { 0 };
    uint32_t tmout = MX_AUDIO_STREAM_NONE_TIMEOUT;
    uint32_t ts = 0;
    int len = 0;
    osEvent evt;
    error_t err;

    /*Make sure buffer is not empty*/
    LOGI("start play task %u\r\n", ring_buffer_len(ctx->rbc));

    for (;;) {
        // 1. blocking wait and the first time tmout = 1 to trigger timeout
        evt = osSignalWait(MX_AUDIO_EV_BIT2, tmout);
        if (evt.status == osEventTimeout) {
            ts = get_micro_seconds();

            // 2. obtain buffer data from wireless
            len = ring_buffer_get(ctx->rbc, pcm_buf, &ts, MX_PCM_STERO_SIZE);
            if (len != MX_PCM_STERO_SIZE) {
                len = mx_audio_virtual_stero_data(pcm_buf, MX_PCM_STERO_SIZE);
                stats.pcm_in_err_cnt++;
            } else {
                stats.pcm_in_cnt++;
            }

            err = mx_pcm_dma_data((uint16_t*)pcm_buf, RSHIFT(MX_PCM_STERO_SIZE, 1));
            if (err == -MX_ERROR_IO) {
                stats.pcm_out_err_cnt++;
            } else {
                stats.pcm_out_cnt++;
            }
        }

        if (evt.status == osEventSignal) {
            ts = get_micro_seconds();
            if (evt.value.signals & MX_AUDIO_EV_BIT2) {
                LOGI("DMA I2S Error");
            }
        }
    }
}



void HAL_I2S_M1TxHalfCpltCallback(I2S_HandleTypeDef* hi2s)
{
    /*Notify fill data*/
    osSignalSet(g_evt_handle, MX_AUDIO_EV_BIT1);
}





回复

使用道具 举报

 楼主| 发表于 2022-10-18 11:47:16 | 显示全部楼层
顶!!!!!!!!!!!!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

联系站长|手机版|野火电子官网|野火淘宝店铺|野火电子论坛 ( 粤ICP备14069197号 ) 大学生ARM嵌入式2群

GMT+8, 2024-5-3 03:08 , Processed in 0.027391 second(s), 22 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表