录音放音实验。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进行双声道录音吗,找了网络上也没有可以借鉴的例子。不知道是不是我掉坑里了。
请有经验的朋友指点下,谢谢。
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
我看例程好像没有双声道LINE IN录音。
我的组合结构为STM32+SDRAM+WM8731
目前可以直接旁路line in到line out,听声音是正常的。就是WM8731 LINE IN ADC总有一个声道录到的音有放鞭炮一样的背景噪音,而另一个声道是正常的。而将现成的WAV文件直接通过DAC LINE OUT播放都是正常的。我严重怀疑STM32的ADC这块用不起来。
有图有真相。
这个是STM32的I2S
下图是WM8731的的I2S,当然我看了其他codec芯片的I2S都是这样子的。我严重怀疑STM32的是有问题的。少了一个BCLK,从而导致总有一个声道声音有噪音。
本身我的代码也特别简单直接。并没有使用DMA,代码结构也很简单。
但是硬是调了好久ADC始终搞不定。如果哪位有兴趣我可以把代码整理发上来。
******************************************************************************
* @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>© 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]
一周热门 更多>