OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 3360|回复: 4

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

[复制链接]

8

主题

92

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
311
金钱
311
注册时间
2016-10-1
在线时间
117 小时
发表于 2019-2-20 22:53:03 | 显示全部楼层 |阅读模式
1金钱
录音放音实验。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进行双声道录音吗,找了网络上也没有可以借鉴的例子。不知道是不是我掉坑里了。

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







正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165536
金钱
165536
注册时间
2010-12-1
在线时间
2117 小时
发表于 2019-2-21 02:11:07 | 显示全部楼层
回复

使用道具 举报

8

主题

92

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
311
金钱
311
注册时间
2016-10-1
在线时间
117 小时
 楼主| 发表于 2019-2-21 12:37:42 | 显示全部楼层

我看例程好像没有双声道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始终搞不定。如果哪位有兴趣我可以把代码整理发上来。





回复

使用道具 举报

8

主题

92

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
311
金钱
311
注册时间
2016-10-1
在线时间
117 小时
 楼主| 发表于 2019-2-21 12:39:01 | 显示全部楼层
[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\r\n", 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]
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165536
金钱
165536
注册时间
2010-12-1
在线时间
2117 小时
发表于 2019-2-22 02:30:29 | 显示全部楼层
20161001 发表于 2019-2-21 12:37
我看例程好像没有双声道LINE IN录音。

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

按理说不应该是stm32的问题,不过我也没做过立体声录音,所以,你再找找问题吧
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-9 19:15

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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