简体   繁体   English

STM32使用I2S(DMA)检索数据和output通过USB CDC,但结果有噪音

[英]STM32 using I2S(DMA) retrieve data and output via USB CDC, but the result has noise

I'm using the STM32F3Discovery board and codec CS5343 to implement this project, it's almost completed but the output is not smooth.我正在使用STM32F3Discovery板和编解码器CS5343来实现这个项目,它几乎完成了,但output并不顺利。 Looking like step deformation.看起来像台阶变形。

EX: 100Hz sin wave (the result of processed, 2's complement and shift 1 bit) enter image description here EX:100Hz 正弦波(处理后的结果,2 的补码和移位 1 位)在此处输入图像描述

Try to use the Logic analyzer to retrieve the I2S signal at the same time, but the result is smooth and pure.尝试同时使用逻辑分析仪检索I2S信号,但结果平滑纯净。 and different from the output of data of I2S DMA via CDC.与通过CDC的I2S DMA数据的output不同。 Why are the result different, I think the results for both should be the same.为什么结果不同,我认为两者的结果应该是相同的。

Raw data: Left (Retrieve by Logic analyzer), Right (output of USB CDC) enter image description here原始数据:左(由逻辑分析仪检索),右(USB CDC 的输出)在此处输入图像描述

I'm trying to change the configuration of STM32 I2S, but the result is not different, the output signal also has step formation.我正在尝试更改STM32 I2S的配置,但结果不一样,output信号也有阶跃形成。

main.c main.c

uint16_t SignalTmp[32] = {0x00};
uint8_t BufSize = 4;
uint32_t lSample = 0, rSample = 0;
uint8_t FLAG_half = 0, FLAG_comp = 0;

int main(void)
{
  HAL_Init();

  /* Configure the system clock */
  SystemClock_Config();

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_I2C1_Init();
  MX_SPI1_Init();    
  MX_TIM2_Init();
  MX_TIM3_Init();
  MX_TIM4_Init();
  MX_I2S2_Init();
  MX_UART4_Init();
  MX_USART2_UART_Init();
  MX_USB_DEVICE_Init();
  /* USER CODE BEGIN 2 */
  HAL_TIM_Base_Start_IT(&htim3);
  HAL_TIM_Base_Start_IT(&htim4);
  HAL_I2S_Receive_DMA(&hi2s2, (uint16_t *)&SignalTmp[0], BufSize);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    if (HAL_GPIO_ReadPin(BT_KEY_GPIO_Port, BT_KEY_Pin) == 1)
      ButtonPressed = 1;

    if (ButtonPressed)
    {
      if (!TransferFlag)
      {
        HAL_TIM_Base_Start_IT(&htim2);
        HAL_GPIO_WritePin(LD7_GPIO_Port, LD7_Pin, GPIO_PIN_SET);
      }
      else
      {
        HAL_TIM_Base_Stop_IT(&htim2);
        HAL_GPIO_WritePin(LD7_GPIO_Port, LD7_Pin, GPIO_PIN_RESET);
        HAL_GPIO_WritePin(LD4_GPIO_Port, LD4_Pin, GPIO_PIN_RESET);
        HAL_GPIO_WritePin(LD5_GPIO_Port, LD5_Pin, GPIO_PIN_RESET);
      }

      TransferFlag ^= 1;
      ButtonPressed = 0;
    }
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */

  }
  /* USER CODE END 3 */
}

/* USER CODE BEGIN 4 */
void HAL_I2S_RxHalfCpltCallback(I2S_HandleTypeDef *hi2s)
{
  memcpy(&lSample, &SignalTmp[0], 4);
  memcpy(&rSample, &SignalTmp[2], 4);
  FLAG_half = 1; // fill buffer half
}

void HAL_I2S_RxCpltCallback(I2S_HandleTypeDef *hi2s)    
{
  memcpy(&lSample, &SignalTmp[4], 4);
  memcpy(&rSample, &SignalTmp[6], 4);
  FLAG_comp = 1;
}

i2s.c i2s.c

  void MX_I2S2_Init(void)
  {
    hi2s2.Instance = SPI2;
    hi2s2.Init.Mode = I2S_MODE_MASTER_RX;
    hi2s2.Init.Standard = I2S_STANDARD_PHILIPS; 
    hi2s2.Init.DataFormat = I2S_DATAFORMAT_24B;
    hi2s2.Init.MCLKOutput = I2S_MCLKOUTPUT_ENABLE;
    hi2s2.Init.AudioFreq = I2S_AUDIOFREQ_48K;
    hi2s2.Init.CPOL = I2S_CPOL_HIGH;
    hi2s2.Init.ClockSource = I2S_CLOCK_SYSCLK;
    hi2s2.Init.FullDuplexMode = I2S_FULLDUPLEXMODE_ENABLE;
    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
      PB14     ------> I2S2_ext_SD
      PB15     ------> I2S2_SD
      PC6     ------> I2S2_MCK
      */
      GPIO_InitStruct.Pin = GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
      GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
      GPIO_InitStruct.Pull = GPIO_PULLUP;
      GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
      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_PULLUP;
      GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
      GPIO_InitStruct.Alternate = GPIO_AF6_SPI2;
      HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

      /* I2S2 DMA Init */
      /* SPI2_RX Init */
      hdma_spi2_rx.Instance = DMA1_Channel4;
      hdma_spi2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
      hdma_spi2_rx.Init.PeriphInc = DMA_PINC_DISABLE;
      hdma_spi2_rx.Init.MemInc = DMA_MINC_ENABLE;
      hdma_spi2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
      hdma_spi2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
      hdma_spi2_rx.Init.Mode = DMA_CIRCULAR;
      hdma_spi2_rx.Init.Priority = DMA_PRIORITY_HIGH;
      if (HAL_DMA_Init(&hdma_spi2_rx) != HAL_OK)
      {
        Error_Handler();
      }

      __HAL_LINKDMA(i2sHandle, hdmarx, hdma_spi2_rx);

      /* SPI2_TX Init */
      hdma_spi2_tx.Instance = DMA1_Channel5;
      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.Mode = DMA_CIRCULAR;
      hdma_spi2_tx.Init.Priority = DMA_PRIORITY_HIGH;
      if (HAL_DMA_Init(&hdma_spi2_tx) != HAL_OK)
      {
        Error_Handler();
      }

      __HAL_LINKDMA(i2sHandle, hdmatx, hdma_spi2_tx);

      /* I2S2 interrupt Init */
      HAL_NVIC_SetPriority(SPI2_IRQn, 0, 0);
      HAL_NVIC_EnableIRQ(SPI2_IRQn);
      /* USER CODE BEGIN SPI2_MspInit 1 */

      /* USER CODE END SPI2_MspInit 1 */
    }
  }

stm32f3xx_it.c stm32f3xx_it.c

uint8_t ABuf[64] = {0x00};
uint8_t BBuf[64] = {0x00};

void TIM2_IRQHandler(void)
{
  /* USER CODE BEGIN TIM2_IRQn 0 */
  if (TX_Flag)
  {
    if (NextBuf)
      CDC_Transmit_FS(&ABuf, 64);
    else
      CDC_Transmit_FS(&BBuf, 64);

    TX_Flag = 0;
  }
  /* USER CODE END TIM2_IRQn 0 */
  HAL_TIM_IRQHandler(&htim2);
  /* USER CODE BEGIN TIM2_IRQn 1 */

  /* USER CODE END TIM2_IRQn 1 */
}

/**
 * @brief This function handles TIM3 global interrupt.
 */
void TIM3_IRQHandler(void)
{
/* USER CODE BEGIN TIM3_IRQn 0 */
#if 1
#ifdef SIMULATOR
  SignalAvg = GenerateSignal();
#else
  if (!NextBuf)
  {
    memcpy(&ABuf[txidx * 4], &lSample, 4);
    txidx++;
    memcpy(&ABuf[txidx * 4], &rSample, 4);
    txidx++;
  }
  else
  {
    memcpy(&BBuf[txidx * 4], &lSample, 4);
    txidx++;
    memcpy(&BBuf[txidx * 4], &rSample, 4);
    txidx++;
  }

  if (txidx >= 16)
  {
    NextBuf ^= 1;
    TX_Flag = 1;
    txidx = 0;
  }
#endif

#endif
  /* USER CODE END TIM3_IRQn 0 */
  HAL_TIM_IRQHandler(&htim3);
  /* USER CODE BEGIN TIM3_IRQn 1 */

  /* USER CODE END TIM3_IRQn 1 */
}





Link to completed code on GitHub链接到 GitHub 上的完整代码

result data 结果数据

The result data folder includes 3 files.结果数据文件夹包括 3 个文件。

  1. record_2022_07_19_05-32-45.txt --> the signal data of output of USB CDC, a point data use 4 bytes and the sequence is Left channel, Right channel, Left channel, Right channel... record_2022_07_19_05-32-45.txt --> USB CDC的output的信号数据,一个点数据使用4个字节,顺序为左声道,右声道,左声道,右声道...
  2. Logic_R-1kHzSin_L-GND.csv --> the retrieve signal data from the i2s interface via the Logic Analyzer. Logic_R-1kHzSin_L-GND.csv --> 通过逻辑分析仪从 i2s 接口检索信号数据。
  3. drawout7.m --> the data conversion for the output of USB CDC, transfer the data to value (2's complement and shift 1 bit) drawout7.m --> USB CDC的output的数据转换,将数据转换为值(2的补码并移位1位)

Any suggestion please, Thank in advance.请有任何建议,在此先感谢。

refer the video: [#13] FIR Filters - Audio DSP On STM32 (24 Bit / 48 kHz)参考视频: [#13] FIR 滤波器 - STM32 上的音频 DSP(24 位 / 48 kHz)

It also has source code and is very useful.它也 有源代码,非常有用。

change the process of retrieving value for signals of L/R channel.改变 L/R 通道信号的取值过程。

void HAL_I2S_RxHalfCpltCallback(I2S_HandleTypeDef *hi2s)
{
    lSample = (int)(rxBuf[0] << 16) | rxBuf[1];
    rSample = (int)(rxBuf[2] << 16) | rxBuf[3];
}

void HAL_I2S_RxCpltCallback(I2S_HandleTypeDef *hi2s)
{
   lSample = (int)(rxBuf[4] << 16) | rxBuf[5];
   rSample = (int)(rxBuf[6] << 16) | rxBuf[7];    
}

and collect data via a timer, when reached 64 bytes (best performance for CDC), and transmit it.并通过计时器收集数据,当达到 64 字节时(CDC 的最佳性能),并传输它。

and the final result.和最终的结果。
1k sine wave 1k 正弦波

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM