一、硬件平台
MCU选用NXP的RT1052,SDRAM使用NT5SV16M16CS-6K,CODEC选用CS4270
二、软件实现
1、I2S配置
配置I2S为48K,立体声,24bit,MCLK = 12.2888M,BCLK = 3.0722M
void xBSP_I2S_Init(void)
{
sai_config_t config;
IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_03_SAI1_MCLK, 1U);
IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_03_SAI1_MCLK, 0x10B0u);
IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_12_SAI1_RX_DATA00, 1U);
IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_12_SAI1_RX_DATA00, 0x10B0u);
IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_13_SAI1_TX_DATA00, 1U);
IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_13_SAI1_TX_DATA00, 0x10B0u);
IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_14_SAI1_TX_BCLK, 1U);
IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_14_SAI1_TX_BCLK, 0x10B0u);
IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_15_SAI1_TX_SYNC, 1U);
IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_15_SAI1_TX_SYNC, 0x10B0u);
//时钟初始化
CLOCK_InitAudioPll(&audioPllConfig);
//使用PLL时钟
CLOCK_SetMux(kCLOCK_Sai1Mux, C052_SAI1_CLOCK_SOURCE_SELECT);
CLOCK_SetDiv(kCLOCK_Sai1PreDiv, C052_SAI1_CLOCK_SOURCE_PRE_DIVIDER);
CLOCK_SetDiv(kCLOCK_Sai1Div, C052_SAI1_CLOCK_SOURCE_DIVIDER);
edma_config_t sai_dmaConfig = {0};
/* Init DMA and create handle for DMA */
EDMA_GetDefaultConfig(&sai_dmaConfig);
EDMA_Init(C052_DMA, &sai_dmaConfig);
//RX
EDMA_CreateHandle(&dmaRxHandle, C052_DMA, C052_RX_CHANNEL);
//TX
EDMA_CreateHandle(&dmaTxHandle, C052_DMA, C052_TX_CHANNEL);
/* Init DMAMUX */
DMAMUX_Init(C052_DMAMUX);
//RX
DMAMUX_SetSource(C052_DMAMUX, C052_RX_CHANNEL, (uint8_t)C052_SAI_RX_SOURCE);
DMAMUX_EnableChannel(C052_DMAMUX, C052_RX_CHANNEL);
//TX
DMAMUX_SetSource(C052_DMAMUX, C052_TX_CHANNEL, (uint8_t)C052_SAI_TX_SOURCE);
DMAMUX_EnableChannel(C052_DMAMUX, C052_TX_CHANNEL);
/* Init SAI module */
/*
* sai_config.masterSlave = kSAI_Master;
* sai_config.mclkSource = kSAI_MclkSourceSysclk;
* sai_config.protocol = kSAI_BusLeftJustified;
* sai_config.syncMode = kSAI_ModeAsync;
* sai_config.mclkOutputEnable = true;
*/
SAI_TxGetDefaultConfig(&config);
config.masterSlave = kSAI_Master;
config.protocol = kSAI_BusI2S; //kSAI_BusI2S
SAI_TxInit(C052_SAI, &config);
SAI_RxGetDefaultConfig(&config);
config.masterSlave = kSAI_Master;
config.protocol = kSAI_BusI2S; //
SAI_RxInit(C052_SAI, &config);
/* Configure the audio format */
format.bitWidth = kSAI_WordWidth32bits; //必须是32位
format.channel = 0;
format.sampleRate_Hz = kSAI_SampleRate48KHz;
format.masterClockHz = C052_SAI_CLK_FREQ;
format.protocol = config.protocol;
format.stereo = kSAI_Stereo;
format.isFrameSyncCompact = false;
format.watermark = 16;//FSL_FEATURE_SAI_FIFO_COUNT / 2;
//RX 接收存在DMA
format.channel = 0;
format.channelMask = 0;
SAI_TransferRxCreateHandleEDMA(C052_SAI, &rxHandle, xBSP_AudioRxCallback, NULL, &dmaRxHandle);
SAI_TransferRxSetFormatEDMA(C052_SAI, &rxHandle, &format, C052_SAI_CLK_FREQ, format.masterClockHz);
sai_transfer_receive.dataSize = AUDIO_DOT_NUM*4;
sai_transfer_receive.data = (uint8_t *)&audioRecDMATempBuff[sai_receive_fifo_index * AUDIO_DOT_NUM];
//TX 接收存在DMA
format.channel = 0;
format.channelMask = 0;
SAI_TransferTxCreateHandleEDMA(C052_SAI, &txHandle, xBSP_AudioTxCallback, NULL, &dmaTxHandle);
SAI_TransferTxSetFormatEDMA(C052_SAI, &txHandle, &format, C052_SAI_CLK_FREQ, format.masterClockHz);
sai_transfer_send.dataSize = AUDIO_DOT_NUM*4;
sai_transfer_send.data = (uint8_t *)&audioSendDMATempBuff[sai_send_fifo_write * AUDIO_DOT_NUM];
}
void xBSP_I2S_Start(void)
{
__disable_irq();
NVIC_SetPriority(DMA0_DMA16_IRQn, 0);
NVIC_SetPriority(DMA1_DMA17_IRQn, 1);
SAI_TransferReceiveEDMA(C052_SAI, &rxHandle, &sai_transfer_receive);
SAI_TransferSendEDMA(C052_SAI, &txHandle, &sai_transfer_send);
xBSP_I2S_MclkOutput(true);
__enable_irq();
}
2、卷积长度设置为32768,MATLAB导出ROMM3的脉冲响应数据
3、内存划分
OCRAM = 32K,DTCM = 416KB, ITCM = 64KB,最大限度使用内部内存,加快访问速度
LDR R0,=0x400AC038
LDR R1,=0x00AA0000
STR R1,[R0]
LDR R0,=0x400AC040
LDR R1,=0x00200007
STR R1,[R0]
LDR R0,=0x400AC044
LDR R1,=0x6AAAAAAF ; OCRAM = 32K,DTCM = 416KB, ITCM = 64KB
STR R1,[R0]
4、配置SDRAM
修改DCD数组,配置SDRAM超频到200M
const uint8_t dcd_sdram[1072] = {
/*0000*/ 0xD2, 0x04, 0x30, 0x41, 0xCC, 0x03, 0xAC, 0x04, 0x40, 0x0F, 0xC0, 0x68, 0xFF, 0xFF, 0xFF, 0xFF,
/*0010*/ 0x40, 0x0F, 0xC0, 0x6C, 0xFF, 0xFF, 0xFF, 0xFF, 0x40, 0x0F, 0xC0, 0x70, 0xFF, 0xFF, 0xFF, 0xFF,
/*0020*/ 0x40, 0x0F, 0xC0, 0x74, 0xFF, 0xFF, 0xFF, 0xFF, 0x40, 0x0F, 0xC0, 0x78, 0xFF, 0xFF, 0xFF, 0xFF,
/*0030*/ 0x40, 0x0F, 0xC0, 0x7C, 0xFF, 0xFF, 0xFF, 0xFF, 0x40, 0x0F, 0xC0, 0x80, 0xFF, 0xFF, 0xFF, 0xFF,
/*0040*/ 0x40, 0x0D, 0x80, 0x30, 0x00, 0x00, 0x20, 0x01, 0x40, 0x0D, 0x81, 0x00, 0x00, 0x18, 0x00, 0x00,
/*0050*/ 0x40, 0x0F, 0xC0, 0x14, 0x00, 0x01, 0x0D, 0x40, 0x40, 0x1F, 0x80, 0x14, 0x00, 0x00, 0x00, 0x00,
/*0060*/ 0x40, 0x1F, 0x80, 0x18, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x1C, 0x00, 0x00, 0x00, 0x00,
/*0070*/ 0x40, 0x1F, 0x80, 0x20, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x24, 0x00, 0x00, 0x00, 0x00,
/*0080*/ 0x40, 0x1F, 0x80, 0x28, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x2C, 0x00, 0x00, 0x00, 0x00,
/*0090*/ 0x40, 0x1F, 0x80, 0x30, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x34, 0x00, 0x00, 0x00, 0x00,
/*00a0*/ 0x40, 0x1F, 0x80, 0x38, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x3C, 0x00, 0x00, 0x00, 0x00,
/*00b0*/ 0x40, 0x1F, 0x80, 0x40, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x44, 0x00, 0x00, 0x00, 0x00,
/*00c0*/ 0x40, 0x1F, 0x80, 0x48, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x4C, 0x00, 0x00, 0x00, 0x00,
/*00d0*/ 0x40, 0x1F, 0x80, 0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x54, 0x00, 0x00, 0x00, 0x00,
/*00e0*/ 0x40, 0x1F, 0x80, 0x58, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x5C, 0x00, 0x00, 0x00, 0x00,
/*00f0*/ 0x40, 0x1F, 0x80, 0x60, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x64, 0x00, 0x00, 0x00, 0x00,
/*0100*/ 0x40, 0x1F, 0x80, 0x68, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x6C, 0x00, 0x00, 0x00, 0x00,
/*0110*/ 0x40, 0x1F, 0x80, 0x70, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x74, 0x00, 0x00, 0x00, 0x00,
/*0120*/ 0x40, 0x1F, 0x80, 0x78, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x7C, 0x00, 0x00, 0x00, 0x00,
/*0130*/ 0x40, 0x1F, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x84, 0x00, 0x00, 0x00, 0x00,
/*0140*/ 0x40, 0x1F, 0x80, 0x88, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x8C, 0x00, 0x00, 0x00, 0x00,
/*0150*/ 0x40, 0x1F, 0x80, 0x90, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x94, 0x00, 0x00, 0x00, 0x00,
/*0160*/ 0x40, 0x1F, 0x80, 0x98, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x9C, 0x00, 0x00, 0x00, 0x00,
/*0170*/ 0x40, 0x1F, 0x80, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0xA4, 0x00, 0x00, 0x00, 0x00,
/*0180*/ 0x40, 0x1F, 0x80, 0xA8, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0xAC, 0x00, 0x00, 0x00, 0x00,
/*0190*/ 0x40, 0x1F, 0x80, 0xB0, 0x00, 0x00, 0x00, 0x10, 0x40, 0x1F, 0x80, 0xB4, 0x00, 0x00, 0x00, 0x00,
/*01a0*/ 0x40, 0x1F, 0x80, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x82, 0x04, 0x00, 0x01, 0x10, 0xF9,
/*01b0*/ 0x40, 0x1F, 0x82, 0x08, 0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x0C, 0x00, 0x01, 0x10, 0xF9,
/*01c0*/ 0x40, 0x1F, 0x82, 0x10, 0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x14, 0x00, 0x01, 0x10, 0xF9,
/*01d0*/ 0x40, 0x1F, 0x82, 0x18, 0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x1C, 0x00, 0x01, 0x10, 0xF9,
/*01e0*/ 0x40, 0x1F, 0x82, 0x20, 0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x24, 0x00, 0x01, 0x10, 0xF9,
/*01f0*/ 0x40, 0x1F, 0x82, 0x28, 0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x2C, 0x00, 0x01, 0x10, 0xF9,
/*0200*/ 0x40, 0x1F, 0x82, 0x30, 0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x34, 0x00, 0x01, 0x10, 0xF9,
/*0210*/ 0x40, 0x1F, 0x82, 0x38, 0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x3C, 0x00, 0x01, 0x10, 0xF9,
/*0220*/ 0x40, 0x1F, 0x82, 0x40, 0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x44, 0x00, 0x01, 0x10, 0xF9,
/*0230*/ 0x40, 0x1F, 0x82, 0x48, 0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x4C, 0x00, 0x01, 0x10, 0xF9,
/*0240*/ 0x40, 0x1F, 0x82, 0x50, 0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x54, 0x00, 0x01, 0x10, 0xF9,
/*0250*/ 0x40, 0x1F, 0x82, 0x58, 0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x5C, 0x00, 0x01, 0x10, 0xF9,
/*0260*/ 0x40, 0x1F, 0x82, 0x60, 0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x64, 0x00, 0x01, 0x10, 0xF9,
/*0270*/ 0x40, 0x1F, 0x82, 0x68, 0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x6C, 0x00, 0x01, 0x10, 0xF9,
/*0280*/ 0x40, 0x1F, 0x82, 0x70, 0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x74, 0x00, 0x01, 0x10, 0xF9,
/*0290*/ 0x40, 0x1F, 0x82, 0x78, 0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x7C, 0x00, 0x01, 0x10, 0xF9,
/*02a0*/ 0x40, 0x1F, 0x82, 0x80, 0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x84, 0x00, 0x01, 0x10, 0xF9,
/*02b0*/ 0x40, 0x1F, 0x82, 0x88, 0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x8C, 0x00, 0x01, 0x10, 0xF9,
/*02c0*/ 0x40, 0x1F, 0x82, 0x90, 0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x94, 0x00, 0x01, 0x10, 0xF9,
/*02d0*/ 0x40, 0x1F, 0x82, 0x98, 0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x9C, 0x00, 0x01, 0x10, 0xF9,
/*02e0*/ 0x40, 0x1F, 0x82, 0xA0, 0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0xA4, 0x00, 0x01, 0x10, 0xF9,
/*02f0*/ 0x40, 0x1F, 0x82, 0xA8, 0x00, 0x01, 0x10, 0xF9, 0x40, 0x2F, 0x00, 0x00, 0x10, 0x00, 0x00, 0x04,
/*0300*/ 0x40, 0x2F, 0x00, 0x08, 0x00, 0x03, 0x05, 0x24, 0x40, 0x2F, 0x00, 0x0C, 0x06, 0x03, 0x05, 0x24,
/*0310*/ 0x40, 0x2F, 0x00, 0x10, 0x80, 0x00, 0x00, 0x1B, 0x40, 0x2F, 0x00, 0x14, 0x82, 0x00, 0x00, 0x1B,
/*0320*/ 0x40, 0x2F, 0x00, 0x18, 0x84, 0x00, 0x00, 0x1B, 0x40, 0x2F, 0x00, 0x1C, 0x86, 0x00, 0x00, 0x1B,
/*0330*/ 0x40, 0x2F, 0x00, 0x20, 0x90, 0x00, 0x00, 0x21, 0x40, 0x2F, 0x00, 0x24, 0xA0, 0x00, 0x00, 0x19,
/*0340*/ 0x40, 0x2F, 0x00, 0x28, 0xA8, 0x00, 0x00, 0x17, 0x40, 0x2F, 0x00, 0x2C, 0xA9, 0x00, 0x00, 0x1B,
/*0350*/ 0x40, 0x2F, 0x00, 0x30, 0x00, 0x00, 0x00, 0x21, 0x40, 0x2F, 0x00, 0x04, 0x00, 0x00, 0x79, 0xA8,
/*0360*/ 0x40, 0x2F, 0x00, 0x40, 0x00, 0x00, 0x0F, 0x31, 0x40, 0x2F, 0x00, 0x44, 0x00, 0x65, 0x29, 0x22,
/*0370*/ 0x40, 0x2F, 0x00, 0x48, 0x00, 0x01, 0x09, 0x20, 0x40, 0x2F, 0x00, 0x4C, 0x50, 0x21, 0x0A, 0x08,
/*0380*/ 0x40, 0x2F, 0x00, 0x80, 0x00, 0x00, 0x00, 0x21, 0x40, 0x2F, 0x00, 0x84, 0x00, 0x88, 0x88, 0x88,
/*0390*/ 0x40, 0x2F, 0x00, 0x94, 0x00, 0x00, 0x00, 0x02, 0x40, 0x2F, 0x00, 0x98, 0x00, 0x00, 0x00, 0x00,
/*03a0*/ 0x40, 0x2F, 0x00, 0x90, 0x80, 0x00, 0x00, 0x00, 0x40, 0x2F, 0x00, 0x9C, 0xA5, 0x5A, 0x00, 0x0F,
/*03b0*/ 0xCF, 0x00, 0x0C, 0x1C, 0x40, 0x2F, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x01, 0xCC, 0x00, 0x14, 0x04,
/*03c0*/ 0x40, 0x2F, 0x00, 0x90, 0x80, 0x00, 0x00, 0x00, 0x40, 0x2F, 0x00, 0x9C, 0xA5, 0x5A, 0x00, 0x0C,
/*03d0*/ 0xCF, 0x00, 0x0C, 0x1C, 0x40, 0x2F, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x01, 0xCC, 0x00, 0x14, 0x04,
/*03e0*/ 0x40, 0x2F, 0x00, 0x90, 0x80, 0x00, 0x00, 0x00, 0x40, 0x2F, 0x00, 0x9C, 0xA5, 0x5A, 0x00, 0x0C,
/*03f0*/ 0xCF, 0x00, 0x0C, 0x1C, 0x40, 0x2F, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x01, 0xCC, 0x00, 0x1C, 0x04,
/*0400*/ 0x40, 0x2F, 0x00, 0xA0, 0x00, 0x00, 0x00, 0x33, 0x40, 0x2F, 0x00, 0x90, 0x80, 0x00, 0x00, 0x00,
/*0410*/ 0x40, 0x2F, 0x00, 0x9C, 0xA5, 0x5A, 0x00, 0x0A, 0xCF, 0x00, 0x0C, 0x1C, 0x40, 0x2F, 0x00, 0x3C,
/*0420*/ 0x00, 0x00, 0x00, 0x01, 0xCC, 0x00, 0x0C, 0x04, 0x40, 0x2F, 0x00, 0x4C, 0x50, 0x21, 0x0A, 0x09,
};
三、验证
验证原理,声音输出到声卡,声卡输出到MCU板子,MCU板子输出声音连回声卡,声卡把声音输出到电脑。通过MATLAB把脉冲响应数据计算出来。
1、声卡模块本身参数
如下所示,声音通过声卡后对低频和高频具有衰减
2、抓取MCU混响的脉冲响应数据
3、MATLAB对比原本脉冲响应数据和MCU混响脉冲响应
原本的ROOM3的脉冲响应数据
MCU的脉冲响应数据
4、音频对比
MCU_ROOM3_ir_conv1-reverb.wav 为MCU脉冲响应卷积后音频
PC_ROOM3_ir_conv1-reverb.wav 为原本脉冲响应卷积后音频
TEST MONO GUITAR 48kHZ 24bits 4S.wav 为原音频
https://github.com/BrotherSix/MATLAB_REVERB_AUDIO_WAV
四、总结
1、单声道算法执行周期为25ms,立体声算法执行周期为50ms。在立体声情况下,混响表现为Pre Delay最低为50ms,所以在使用空间比较大的混响时候,需要手动把脉冲响应数据往前50ms。
2、在RT1052平台上,较为完美地实现了混响卷积,而且实时性较为强,仅需要50ms延时。
欢迎技术交流QQ 736009573