WM8731 LINE IN录音总有一个声道有噪音

2019-07-20 03:43发布

录音放音实验。16bits 双声道,44.1K录音(录音数据实时写入外部sdram),然后读取sdram放音。



I2S设置核心代码如下。

[mw_shl_code=c,true]      I2SHandle.Instance = SPI2;
      I2SHandle.Init.AudioFreq = I2S_AUDIOFREQ_44K;
      I2SHandle.Init.ClockSource = I2S_CLOCK_SYSCLK;
      I2SHandle.Init.CPOL = I2S_CPOL_LOW;
      I2SHandle.Init.DataFormat = I2S_DATAFORMAT_16B;
      I2SHandle.Init.MCLKOutput = I2S_MCLKOUTPUT_DISABLE;
      I2SHandle.Init.Standard = I2S_STANDARD_PHILIPS;
      
      I2SHandle.Init.Mode = I2S_MODE_MASTER_RX;[/mw_shl_code]


[mw_shl_code=c,true]      /* 录音数据实时写入SDRAM关键代码 */
      for (uwIndex = 0; uwIndex < 10000000; )
      {
            while((SPI2->SR&I2S_FLAG_RXNE) != I2S_FLAG_RXNE)
            {
            
            }
        *(__IO uint16_t*) (SDRAM_BANK_ADDR+ uwIndex) = SPI2->DR;
        uwIndex+=2;
      }[/mw_shl_code]


录音一段时间后回放有时候左声道会伴随有噪音,有时候录音回放右声道会伴有噪音。总之左右声道总会有一个声道有噪音,而另一个声道声音干净正常。每次重新启动录音噪音通道可能会不一样,并且没有规律。
给我的感觉好像启动录音那一刻哪里错位了?

琢磨了好久想不明白到底哪里问题。

另外放音没有问题,我直接将一个wav文件从SD卡里写到SDRAM然后再播放是没有问题的。现在问题就出现在录音的时候好像WM8731 ADC采集到的数据单片机读取到的总有一个声道原始数据是不干净的感觉。



简单来说我只是想通过WM8731 ADC采集两声道数据,可是好像总得不到干净的数据?
有人成功用WM8731的ADC进行双声道录音吗,找了网络上也没有可以借鉴的例子。不知道是不是我掉坑里了。

请有经验的朋友指点下,谢谢。







友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
4条回答
正点原子
1楼-- · 2019-07-20 08:30
 精彩回答 2  元偷偷看……
20161001
2楼-- · 2019-07-20 11:34
正点原子 发表于 2019-2-21 02:11
参考下我们例程吧

我看例程好像没有双声道LINE IN录音。

我的组合结构为STM32+SDRAM+WM8731   

目前可以直接旁路line in到line out,听声音是正常的。就是WM8731 LINE IN ADC总有一个声道录到的音有放鞭炮一样的背景噪音,而另一个声道是正常的。而将现成的WAV文件直接通过DAC LINE OUT播放都是正常的。我严重怀疑STM32的ADC这块用不起来。

有图有真相。
这个是STM32的I2S

11.jpg

下图是WM8731的的I2S,当然我看了其他codec芯片的I2S都是这样子的。我严重怀疑STM32的是有问题的。少了一个BCLK,从而导致总有一个声道声音有噪音。

222.jpg


本身我的代码也特别简单直接。并没有使用DMA,代码结构也很简单。

但是硬是调了好久ADC始终搞不定。如果哪位有兴趣我可以把代码整理发上来。





20161001
3楼-- · 2019-07-20 15:25
[mw_shl_code=c,true]/**
******************************************************************************
* @file    FMC/FMC_SDRAM/Src/main.c
* @Author  MCD Application Team
* @brief   This example describes how to configure and use GPIOs through
*          the STM32F7xx HAL API.
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT(c) 2016 STMicroelectronics</center></h2>
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*   1. Redistributions of source code must retain the above copyright notice,
*      this list of conditions and the following disclaimer.
*   2. Redistributions in binary form must reproduce the above copyright notice,
*      this list of conditions and the following disclaimer in the documentation
*      and/or other materials provided with the distribution.
*   3. Neither the name of STMicroelectronics nor the names of its contributors
*      may be used to endorse or promote products derived from this software
*      without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/*FMC SDRAM测试通过*/
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "WM8731.h"
/** @addtogroup STM32F7xx_HAL_Examples
* @{
*/

/** @addtogroup FMC_SDRAM
* @{
*/

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define BUFFER_SIZE         ((uint32_t)0x1000)
#define WRITE_READ_ADDR     ((uint32_t)0x0000)

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
SDRAM_HandleTypeDef      hsdram;
FMC_SDRAM_TimingTypeDef  SDRAM_Timing;
FMC_SDRAM_CommandTypeDef command;

/* Read/Write Buffers */
uint32_t aTxBuffer[BUFFER_SIZE];
uint32_t aRxBuffer[BUFFER_SIZE];

/* Status variables */
__IO uint32_t uwWriteReadStatus = 0;

/* Counter index */
uint32_t uwIndex = 0;
#include "WAV.h"
#include "WavSample.c"
uint8_t yinliang=0;
void I2S_WriteByte( uint8_t * data , uint32_t size);
#include <stdio.h>
#include <string.h>
/* Private function prototypes -----------------------------------------------*/
static void SystemClock_Config(void);
static void Error_Handler(void);
static void SDRAM_Initialization_Sequence(SDRAM_HandleTypeDef *hsdram, FMC_SDRAM_CommandTypeDef *Command);
static void Fill_Buffer(uint32_t *pBuffer, uint32_t uwBufferLenght, uint32_t uwOffset);
static void CPU_CACHE_Enable(void);

/* Private functions ---------------------------------------------------------*/
uint32_t SYSCLK_frequency;
uint32_t PCLK1Freq;
uint32_t PCLK2Freq;
uint8_t play_m=2;

I2S_HandleTypeDef  I2SHandle1;

#define BFS 64000

uint16_t shuzu[BFS];
uint16_t qq=0;
/**
* @brief  Main program
* @param  None
* @retval None
*/
int main(void)
{
  /* Enable the CPU Cache */
  CPU_CACHE_Enable();
  
  /* STM32F7xx HAL library initialization:
  - Configure the Flash ART accelerator on ITCM interface
  - Systick timer is configured by default as source of time base, but user
  can eventually implement his proper time base source (a general purpose
  timer for example or other time source), keeping in mind that Time base
  duration should be kept 1ms since PPP_TIMEOUT_VALUEs are defined and
  handled in milliseconds basis.
  - Set NVIC Group Priority to 4
  - Low Level Initialization
  */
  HAL_Init();
  
  /* Configure the system clock to 200 MHz */
  SystemClock_Config();
  SystemCoreClockUpdate();
  SYSCLK_frequency=HAL_RCC_GetSysClockFreq();
  PCLK1Freq=HAL_RCC_GetPCLK1Freq();
  PCLK2Freq=HAL_RCC_GetPCLK2Freq();
  /* Configure LED1 and LED3 */
  // BSP_LED_Init(LED1);
  BSP_LED_Init(LED3);
  
  /*##-1- Configure the SDRAM device #########################################*/
  /* SDRAM device configuration */
  hsdram.Instance = FMC_SDRAM_DEVICE;
  
  SDRAM_Timing.LoadToActiveDelay    = 2;
  SDRAM_Timing.ExitSelfRefreshDelay = 8;
  SDRAM_Timing.SelfRefreshTime      = 6;
  SDRAM_Timing.RowCycleDelay        = 6;
  SDRAM_Timing.WriteRecoveryTime    = 2;
  SDRAM_Timing.RPDelay              = 2;
  SDRAM_Timing.RCDDelay             = 2;
  
  hsdram.Init.SDBank             = FMC_SDRAM_BANK2;
  hsdram.Init.ColumnBitsNumber   = FMC_SDRAM_COLUMN_BITS_NUM_9;
  hsdram.Init.RowBitsNumber      = FMC_SDRAM_ROW_BITS_NUM_13;
  hsdram.Init.MemoryDataWidth    = SDRAM_MEMORY_WIDTH;
  hsdram.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
  hsdram.Init.CASLatency         = FMC_SDRAM_CAS_LATENCY_3;
  hsdram.Init.WriteProtection    = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
  hsdram.Init.SDClockPeriod      = SDCLOCK_PERIOD;
  hsdram.Init.ReadBurst          = FMC_SDRAM_RBURST_ENABLE;
  hsdram.Init.ReadPipeDelay      = FMC_SDRAM_RPIPE_DELAY_0;
  
  /* Initialize the SDRAM controller */
  if(HAL_SDRAM_Init(&hsdram, &SDRAM_Timing) != HAL_OK)
  {
    /* Initialization Error */
    Error_Handler();
  }
  
  /* Program the SDRAM external device */
  SDRAM_Initialization_Sequence(&hsdram, &command);
  
  /*##-2- SDRAM memory read/write access #####################################*/
  
  /* Fill the buffer to write */
  // Fill_Buffer(aTxBuffer, BUFFER_SIZE, 0x12345678);
  
  /* Write data to the SDRAM memory */
  for (uwIndex = 0; uwIndex < sizeof(WAV_DATA); )
  {
  //  *(__IO uint16_t*) (SDRAM_BANK_ADDR + WRITE_READ_ADDR + uwIndex) = WAV_DATA[uwIndex]|(WAV_DATA[uwIndex+1]<<8);
    uwIndex+=2;
    //shuzu[uwIndex]=  uwIndex;
  }
  
  
  
  
  
  WM8731_Init();
  WM8731_Vol(100);
  HAL_I2S_MspInit1(&I2SHandle1,play_m);
  
  
  memcpy(&userWav,WAV_DATA,sizeof(WavHeader));

  while (1)
  {
    HAL_I2S_MspInit1(&I2SHandle1,play_m);
   
         
    if(play_m==0)
    {
      

      /* Write data to the SDRAM memory */
      for (uwIndex = 0; uwIndex < sizeof(WAV_DATA)*10; )
      {
            while((SPI2->SR&I2S_FLAG_RXNE) != I2S_FLAG_RXNE)
            {
            
            }
        *(__IO uint16_t*) (SDRAM_BANK_ADDR + WRITE_READ_ADDR + uwIndex) = SPI2->DR;
        uwIndex+=2;
        //shuzu[uwIndex]=  uwIndex;
      }
      
    }
    else if(play_m==1)
    {
      // I2S_WriteByte( (uint8_t*)WAV_DATA , sizeof(WAV_DATA) );
    }
    else if(play_m==2)
    {
       I2S_WriteByte( (uint8_t*)SDRAM_BANK_ADDR,sizeof(WAV_DATA)*10);//单位字节 14次DMA传输的结果 约10秒钟声音
    }

    BSP_LED_Toggle(LED3);
  }
}

/**
* @brief  System Clock Configuration
*         The system Clock is configured as follow :
*            System Clock source            = PLL (HSE)
*            SYSCLK(Hz)                     = 200000000
*            HCLK(Hz)                       = 200000000
*            AHB Prescaler                  = 1
*            APB1 Prescaler                 = 4
*            APB2 Prescaler                 = 2
*            HSE Frequency(Hz)              = 25000000
*            PLL_M                          = 25
*            PLL_N                          = 400
*            PLL_P                          = 2
*            PLL_Q                          = 9
*            PLL_R                          = 7
*            VDD(V)                         = 3.3
*            Main regulator output voltage  = Scale1 mode
*            Flash Latency(WS)              = 7
* @param  None
* @retval None
*/
static void SystemClock_Config(void)
{
  RCC_ClkInitTypeDef RCC_ClkInitStruct;
  RCC_OscInitTypeDef RCC_OscInitStruct;
  HAL_StatusTypeDef  ret = HAL_OK;
  
  /* Enable Power Control clock */
  __HAL_RCC_PWR_CLK_ENABLE();
  
  /* The voltage scaling allows optimizing the power consumption when the device is
  clocked below the maximum system frequency, to update the voltage scaling value
  regarding system frequency refer to product datasheet.  */
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  
  /* Enable HSE Oscillator and activate PLL with HSE as source */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 25;
  RCC_OscInitStruct.PLL.PLLN = 400;  
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 9;
  RCC_OscInitStruct.PLL.PLLR = 7;
  
  ret = HAL_RCC_OscConfig(&RCC_OscInitStruct);
  if(ret != HAL_OK)
  {
    while(1) { ; }
  }
  
  /* Activate the OverDrive to reach the 200 MHz Frequency */  
  ret = HAL_PWREx_EnableOverDrive();
  if(ret != HAL_OK)
  {
    while(1) { ; }
  }
  
  /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 clocks dividers */
  RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;  
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
  
  ret = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_7);
  if(ret != HAL_OK)
  {
    while(1) { ; }
  }  
}

/**
* @brief  This function is executed in case of error occurrence.
* @param  None
* @retval None
*/
static void Error_Handler(void)
{
  /* User may add here some code to deal with this error */
  /* Turn LED3 on */
  BSP_LED_On(LED3);
  while(1)
  {
  }
}

/**
* @brief  Perform the SDRAM exernal memory inialization sequence
* @param  hsdram: SDRAM handle
* @param  Command: Pointer to SDRAM command structure
* @retval None
*/
static void SDRAM_Initialization_Sequence(SDRAM_HandleTypeDef *hsdram, FMC_SDRAM_CommandTypeDef *Command)
{
  __IO uint32_t tmpmrd =0;
  /* Step 1:  Configure a clock configuration enable command */
  Command->CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;
  Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2;
  Command->AutoRefreshNumber = 1;
  Command->ModeRegisterDefinition = 0;
  
  /* Send the command */
  HAL_SDRAM_SendCommand(hsdram, Command, 0x1000);
  
  /* Step 2: Insert 100 us minimum delay */
  /* Inserted delay is equal to 1 ms due to systick time base unit (ms) */
  HAL_Delay(1);
  
  /* Step 3: Configure a PALL (precharge all) command */
  Command->CommandMode = FMC_SDRAM_CMD_PALL;
  Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2;
  Command->AutoRefreshNumber = 1;
  Command->ModeRegisterDefinition = 0;
  
  /* Send the command */
  HAL_SDRAM_SendCommand(hsdram, Command, 0x1000);
  
  /* Step 4 : Configure a Auto-Refresh command */
  Command->CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
  Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2;
  Command->AutoRefreshNumber = 8;
  Command->ModeRegisterDefinition = 0;
  
  /* Send the command */
  HAL_SDRAM_SendCommand(hsdram, Command, 0x1000);
  
  /* Step 5: Program the external memory mode register */
  tmpmrd = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1          |
    SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL   |
      SDRAM_MODEREG_CAS_LATENCY_3           |
        SDRAM_MODEREG_OPERATING_MODE_STANDARD |
          SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;
  
  Command->CommandMode = FMC_SDRAM_CMD_LOAD_MODE;
  Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2;
  Command->AutoRefreshNumber = 1;
  Command->ModeRegisterDefinition = tmpmrd;
  
  /* Send the command */
  HAL_SDRAM_SendCommand(hsdram, Command, 0x1000);
  
  /* Step 6: Set the refresh rate counter */
  /* (15.62 us x Freq) - 20 */
  /* Set the device refresh counter */
  hsdram->Instance->SDRTR |= ((uint32_t)((1292)<< 1));
  
}

/**
* @brief  Fills buffer with user predefined data.
* @param  pBuffer: pointer on the buffer to fill
* @param  uwBufferLenght: size of the buffer to fill
* @param  uwOffset: first value to fill on the buffer
* @retval None
*/
static void Fill_Buffer(uint32_t *pBuffer, uint32_t uwBufferLenght, uint32_t uwOffset)
{
  uint32_t tmpIndex = 0;
  
  /* Put in global buffer different values */
  for (tmpIndex = 0; tmpIndex < uwBufferLenght; tmpIndex++ )
  {
    pBuffer[tmpIndex] = tmpIndex + uwOffset;
  }
}



void I2S_WriteByte( uint8_t * data , uint32_t size)
{
  typedef union
  {
    uint16_t Val;
    struct
    {
      uint16_t low         :8;                               
      uint16_t high         :8;                       
    }bits;            
  }wav;
  
  uint32_t addr;
  wav temp;       
  
  
  for(addr=0; addr<size; addr+=2 )
  {
    temp.bits.low=data[addr];
    temp.bits.high=data[addr+1];
   
   
    SPI2->DR = temp.Val;
    while((SPI2->SR&I2S_FLAG_TXE) != I2S_FLAG_TXE);
   
  }
}







#ifdef  USE_FULL_ASSERT

/**
* @brief  Reports the name of the source file and the source line number
*         where the assert_param error has occurred.
* @param  file: pointer to the source file name
* @param  line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
  /* User can add his own implementation to report the file name and line number,
  ex: printf("Wrong parameters value: file %s on line %d ", file, line) */
  
  /* Infinite loop */
  while (1)
  {
  }
}
#endif

/**
* @brief  CPU L1-Cache enable.
* @param  None
* @retval None
*/
static void CPU_CACHE_Enable(void)
{
  /* Enable I-Cache */
  SCB_EnableICache();
  
  /* Enable D-Cache */
  SCB_EnableDCache();
}

/**
* @}
*/

/**
* @}
*/

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
[/mw_shl_code]
正点原子
4楼-- · 2019-07-20 17:23
 精彩回答 2  元偷偷看……

一周热门 更多>