有道网站提交入口,商城网站开发商,宿迁房产网最新房价,深圳福永网站建设前言#xff1a; 从零开始学习I2s外设#xff0c;配置Es8288寄存器实现录音播放。本文章使用主控芯片是APM32F411系类。音频相关的概念比较多#xff0c;就不再次做过多的介绍#xff0c;本文章只是简单实现边录边播功能。APM系类兼容st的芯片#xff0c;所以用st的hal库来…前言 从零开始学习I2s外设配置Es8288寄存器实现录音播放。本文章使用主控芯片是APM32F411系类。音频相关的概念比较多就不再次做过多的介绍本文章只是简单实现边录边播功能。APM系类兼容st的芯片所以用st的hal库来实现。本文的介绍顺序从es8388这款芯片开始再到I2s协议再到最后代码讲解。
一、Es8388芯片介绍
1、Es8388介绍 Es8388有 2 个 ADC 通道和 2 个 DAC 通道麦克风放大器耳机放大器数字音效以及模拟混合和增益功能组成。 主要特点 I2S 接口支持最高 192K,24bit 音频播放。 DAC 信噪比 96dBADC 信噪比 95dB。 支持主机和从机模式。 支持立体声差分输入/麦克风输入。 支持左右声道音量独立调节。 支持 40mW 耳机输出无爆音。
2、通路
设计通入从es8388的RIN1 进行数据采集编码解码数据从ROUT 发送至喇叭。主时钟又外部12.288M的晶振电路提供。 3、采样率相关寄存器 本文设置的采样率是8K作为正常通话K的采样已足够清晰。依据主时钟与采样的关系后续如做更改需要依照下表同步更新。 4、寄存器介绍 寄存器介绍采用正点原子提供的手册做参考并对其他可能影响的进行另外介绍。 更新补充其他可能影响录音功能的寄存器以下寄存器只针对实现我上述所说的单右声道录音右声道播放
4.1问题介绍
首先说一下我遇到的问题我通过移植正点原子的历程实现边录边播功能在探索者上完全没有问题可以实现但是在自己打的板子上却存在在录音上电时发出 “哒哒哒哒哒哒” 的声音其中有一个难以理解的点时因为寄存器高通滤波开启了导致的依据笔者的理解高通滤波时需要开的但是他会带来“哒哒哒”的噪音不太理解找了好久一个一个尝试才解决的但是至今不太理解可能是硬件设计问题硬件抄的成熟的方案。
默认开启设置关闭就解决“哒哒哒”的声音 第二个问题就是在说话的时候也会伴随的杂音“哒哒哒”的杂音声音比较大后续通过一下寄存器减小了杂音之前上电就出现后者是持续存在至今没完全找到原因如果有知道的可以在评论区交流学习。
说一下以下寄存器 左DAC清零静音关闭无关寄存器防止干扰因为采用的是单声道所以无关的寄存器需要全部关闭禁止立体声也需要设置这里不做赘述相信各位英语应该都可以直接拿出相关截图给各位。 麦克风相关寄存器硬件原理图设置那边其他的就需要断电也符合他的特点“低功耗” 总结 Es8388 中的ALC调节MIC增益调节喇叭声音等一些列寄存器设置都会影响到声音播放时的杂音和啸叫提醒各位调试时可以先去掉喇叭通过示波器区测试输入输出声波保护耳朵要经。
二、I2S介绍
1、I2S简介 做一下另外补充
1WS字选择映射到spi的nss引脚及帧时钟用于切换左右声道数据对应设置的采样率可以通过示波器查看是否配置正确。
2SD串行数据映射到mosi引脚用于发送或接收两个时分复用的数据通道上的 数据。 3CK 串行时钟映射到 SCK 引脚即位时钟是主模式下的串行时钟输出以及从模 式下的串行时钟输入。CK 频率 WS 频率 fs *2*16 16 位宽如果是 32 位宽则是 CK 频率WS 频率 fs *2*32 32 位宽 主时钟的2568*16*2
4I2S2ext_SD 和 I2S3ext_SD用于控制 I2S 全双工模式的附加引脚映射到 MISO 引脚。 5MCK 即主时钟输出当 I2S 配置为主模式并且 SPI_I2SPR 寄存器中的 MCKOE 位 置 1 时使用此时钟该时钟输出频率 256 × fs fs 即音频信号采样频率 fs 。 提示大家可以将MCK引脚接入MCU通过MCU提供主时钟可能会有一点点小误差如果想要省下材料可以直接查询手册
APMF411的I2S2_MCK引脚为PA6.大家可以作为参考不过追求准确的话可以直接将MCK引脚连接至晶振电路后续通过寄存器去合理设计。本文采用的是外部12.288M晶振解决的。 I2S的时钟发生器如下介绍摘抄自正点原子手册作为学习记录 2、I2s 相关寄存器介绍
2.1 RCC_PLLI2SCFGR 2.2 SPI_I2SCFGR 2.3 SPI_I2SPR 三、Es8388配置I2S代码讲解
1、Es8388初始化
/*****************************************************************************函 数 名 : Es8388Init功能描述 : Es8388初始化输入参数 : void返 回 值 : void作 者 : GCC
*****************************************************************************/
void Es8388Init(void)
{AudioI2cInit(); /* 初始化IIC接口 */ es8388I2cWriteReg(0, 0x80); /* 软复位ES8388 */es8388I2cWriteReg(0, 0x00);DelayMs(100); /* 等待复位 */es8388I2cWriteReg(0x01, 0x58); /*默认0x5c设置0x58复位模拟软件部分*/es8388I2cWriteReg(0x01, 0x50); /*PdnAna 为0模拟部分可工作*/// es8388I2cWriteReg(0x01, 0x53);//模拟部分不工作es8388I2cWriteReg(0x02, 0xF3); /*断电ADCDAC*/es8388I2cWriteReg(0x02, 0xF0); /*0xf3 重新设置adc,dac,重新设置状态机复位开启ADC DAC*/// es8388I2cWriteReg(0x03, 0x00);//ADCL power down,left analog input power downes8388I2cWriteReg(0x03, 0x09); /* 麦克风偏置电源关闭 */es8388I2cWriteReg(0x00, 0x06); /* 使能参考 500K驱动使能,默认500K */es8388I2cWriteReg(0x04, 0x00); /* DAC电源管理不打开任何通道 */es8388I2cWriteReg(0x05,0x88); //LPDACL low powrer, LPLOUT2 low power
// es8388I2cWriteReg(0x04, 0x90);
// es8388I2cWriteReg(0x0A,0xF0);es8388I2cWriteReg(0x08, 0x05); /* MCLK 6分频产生2.048M时钟 */es8388I2cWriteReg(0x2B, 0x80); /* DAC控制 DACLRC与ADCLRC相同 */es8388I2cWriteReg(0x09, 0x00); // 0x66 ADC L/R PGA增益配置为24dB//es8388I2cWriteReg(0x09, 0x88); /* ADC L/R PGA增益配置为24dB */
// es8388I2cWriteReg(0x0C, 0x8C); //都来源源于右通道es8388I2cWriteReg(0x0C, 0x0C); //左右声道数据分开es8388I2cWriteReg(0x0D, 0x0A); /* ADC配置 MCLK/采样率15368K采样率 外部晶振12.288M*/
// es8388I2cWriteReg(0x0D, 0x02); /* ADC配置 MCLK/采样率256 */es8388I2cWriteReg(0x10, 0x00); /* ADC数字音量控制将信号衰减 L 设置为最小 */es8388I2cWriteReg(0x11, 0x00); /* ADC数字音量控制将信号衰减 R 设置为最小 */
// es8388I2cWriteReg(0x13,0xD5); //lxlvl -1.5dB 1.36ses8388I2cWriteReg(0x16,0xF3);//Noise gate threshold -30dB, PGA gain held constant Noise gate function enable es8388I2cWriteReg(0x17, 0x18); /* DAC 音频数据为16bit */es8388I2cWriteReg(0x18, 0x0A); /* DAC 配置 MCLK/采样率256 */ es8388I2cWriteReg(0x1A, 0x00); /* DAC数字音量控制将信号衰减 L 设置为最小 */es8388I2cWriteReg(0x1B, 0x00); /* DAC数字音量控制将信号衰减 R 设置为最小 */
// es8388I2cWriteReg(0x1C,0xC0);//除重音模式es8388I2cWriteReg(0x27, 0xB8); /* L混频器 */es8388I2cWriteReg(0x2A, 0xB8); /* R混频器-15 */es8388I2cWriteReg(0x0A,0);//选择输入通道es8388I2cWriteReg(0x0B,0x10);//es8388I2cWriteReg(0x0E,0x00); /*关闭高通滤波防止哒哒哒声如果存在可选择*/es8388I2cWriteReg(0x03, 0xA9); /* 麦克风偏置电源关闭 */es8388I2cWriteReg(0x06,0x02);es8388I2cWriteReg(0x04,0x90);DelayMs(100);
}
/*****************************************************************************函 数 名 : Es8388I2sCfg功能描述 : 设置ES8388工作模式输入参数 : fmt : 工作模式* arg 0, 飞利浦标准I2S;* arg 1, MSB(左对齐);* arg 2, LSB(右对齐);* arg 3, PCM/DSPlen : 数据长度 * arg 0, 24bit* arg 1, 20bit * arg 2, 18bit * arg 3, 16bit * arg 4, 32bit 返 回 值 : void作 者 : GCC
*****************************************************************************/
void Es8388I2sCfg(uint8_t fmt, uint8_t len)
{fmt 0x03;len 0x07; /* 限定范围 */es8388I2cWriteReg(23, (fmt 1) | (len 3)); /* R23,ES8388工作模式设置 */
}
/*****************************************************************************函 数 名 : Es8388Rout1Set功能描述 : 右声道声音输出大小设置输入参数 : voluem : 音量大小(0 ~ 33)返 回 值 : void作 者 : GCC
*****************************************************************************/
void Es8388Rout1Set(uint8_t volume)
{if (volume 33){volume 33;}es8388I2cWriteReg(0x2F, volume);//ROUT1VOl右声道1
}
/*****************************************************************************函 数 名 : Es8388Rout2Set功能描述 : MIC_P 声音设置输入参数 : voluem : 音量大小(0 ~ 33)返 回 值 : void作 者 : GCC
*****************************************************************************/
void Es8388Rout2Set(uint8_t volume)
{if (volume 33){volume 33;}es8388I2cWriteReg(0x31, volume);
}
/*** brief 设置3D环绕声* param 修改设置单声道* retval 无*/
/*****************************************************************************函 数 名 : Es8388Channel_3d_set功能描述 : 通道设置3d立体音设置输入参数 : Channel 0 表示立体音 1表示单左声道2表示设置右声道depth : 0 ~ 7(3D强度,0关闭,7最强)返 回 值 : void作 者 : GCC
*****************************************************************************/
void Es8388Channel_3d_set(uint8_t depth,u8 Channel)
{ switch(Channel){case 0:depth 0x7; /* 限定范围 */es8388I2cWriteReg(0x1D, depth 2); /* R7,3D环绕设置 */break;case 1:depth(35);es8388I2cWriteReg(0x1D,depth);break;case 2:depth0xA0;//单声道关闭立体音es8388I2cWriteReg(0x1D,0xA0);break;}
}/*** brief ES8388 DAC/ADC配置* param dacen : dac使能(1)/关闭(0)* param adcen : adc使能(1)/关闭(0)* retval 无*/
void Es8388AddaCfg(uint8_t dacen, uint8_t adcen)
{uint8_t tempreg 0;tempreg | ((!dacen) 0);tempreg | ((!adcen) 1);tempreg | ((!dacen) 2);tempreg | ((!adcen) 3);es8388I2cWriteReg(0x02, tempreg);
}
/*** brief ES8388 DAC输出通道配置* param o1en : 通道1使能(1)/禁止(0)* param o2en : 通道2使能(1)/禁止(0)* retval 无*/
void Es8388OutputCfg(uint8_t o1en, uint8_t o2en)
{uint8_t tempreg 0;tempreg | o1en * (3 4);tempreg | o2en * (3 2);es8388I2cWriteReg(0x04, tempreg);
}
/*** brief ES8388 MIC左右通道增益设置(MIC PGA增益)* param gain : 0~8, 对应0~24dB 3dB/Step* retval 无*/
void Es8388MicGain(uint8_t gain)
{gain 0x0F; //设置低4位gain | gain 4;//设置高位4位es8388I2cWriteReg(0x09, gain); /* R9,左右通道PGA增益设置 */
}
/*** brief ES8388 ALC设置* param sel* arg 0,关闭ALC* arg 1,右通道ALC* arg 2,左通道ALC* arg 3,立体声ALC* param maxgain : 0~7,对应-6.5~35.5dB* param mingain : 0~7,对应-12~30dB 6dB/STEP* retval 无*/
void Es8388AlcCtrl(uint8_t sel, uint8_t maxgain, uint8_t mingain)
{uint8_t tempreg 0;tempreg sel 6;tempreg | (maxgain 0x07) 3;//set maximum gain of PGA 17.5dbtempreg | mingain 0x07; //12dbes8388I2cWriteReg(0x12, tempreg); /* R18,ALC设置 */
}
/*** brief ES8388 ADC输出通道配置* param in : 输入通道* arg 0, 通道1输入* arg 1, 通道2输入* retval 无*/
void Es8388InputCfg(uint8_t in)
{es8388I2cWriteReg(0x0A, (5 * in) 4); /* ADC1 输入通道选择L/R INPUT1 */
}2、I2S 代码 /***************************************************************************************/
I2S_HandleTypeDef gAudioI2s; /* I2S句柄 */
I2S_HandleTypeDef gAudioI2sSext; /* I2S句柄 */
DMA_HandleTypeDef gI2sTxDma; /* I2S发送DMA句柄 */
DMA_HandleTypeDef gI2sRxDma; /* I2S接收DMA句柄 */
/************************************************************************************/
/*** brief I2S初始化* param i2s_standard : I2S标准* note 可以设置 : I2S_STANDARD_PHILIPS/I2S_STANDARD_MSB/* I2S_STANDARD_LSB/I2S_STANDARD_PCM_SHORT/I2S_STANDARD_PCM_LONG* param i2s_mode : I2S工作模式* note 可以设置 : I2S_MODE_SLAVE_TX/I2S_MODE_SLAVE_RX/I2S_MODE_MASTER_TX/I2S_MODE_MASTER_RX* param i2s_clock_polarity : 空闲状态时钟电平* param i2s_dataformat : 数据长度* note 可以设置 : I2S_DATAFORMAT_16B/I2S_DATAFORMAT_16B_EXTENDED/I2S_DATAFORMAT_24B/I2S_DATAFORMAT_32B* retval 无*/
void AudioI2sInit(void)
{gAudioI2s.Instance I2S_SPI;gAudioI2s.Init.Mode I2S_MODE_MASTER_TX; /* IIS模式 */gAudioI2s.Init.Standard I2S_STANDARD_PHILIPS; /* IIS标准 */gAudioI2s.Init.DataFormat I2S_DATAFORMAT_16B; /* IIS数据长度 */gAudioI2s.Init.MCLKOutput I2S_MCLKOUTPUT_ENABLE; /* 主时钟输出使能 */gAudioI2s.Init.AudioFreq I2S_AUDIOFREQ_8K; /* IIS频率设置 */gAudioI2s.Init.CPOL I2S_CPOL_LOW; /* 空闲状态时钟电平 */gAudioI2s.Init.ClockSource I2S_CLOCK_PLL; /* IIS时钟源为PLL */HAL_I2S_Init(gAudioI2s);I2S_SPI-CR2 | 11; /* SPI2/I2S2 TX DMA请求使能. */__HAL_I2S_ENABLE(gAudioI2s); /* 使能I2S2 */
}
/*** brief I2SEXT初始化* param i2s_standard : I2S标准* note 可以设置 : I2S_STANDARD_PHILIPS/I2S_STANDARD_MSB/* I2S_STANDARD_LSB/I2S_STANDARD_PCM_SHORT/I2S_STANDARD_PCM_LONG* param i2s_mode : I2S工作模式* note 可以设置 : I2S_MODE_SLAVE_TX/I2S_MODE_SLAVE_RX/I2S_MODE_MASTER_TX/I2S_MODE_MASTER_RX* param i2s_clock_polarity : 显示数字的位数* param i2s_dataformat : 数据长度* note 可以设置 : I2S_DATAFORMAT_16B/I2S_DATAFORMAT_16B_EXTENDED/I2S_DATAFORMAT_24B/I2S_DATAFORMAT_32B* retval 无*/
void AudioI2sSextInit(void)
{gAudioI2sSext.Instance I2SEXT_SPI;gAudioI2sSext.Init.Mode I2S_MODE_SLAVE_RX; /* IIS模式 */gAudioI2sSext.Init.Standard I2S_STANDARD_PHILIPS; /* IIS标准 */gAudioI2sSext.Init.DataFormat I2S_DATAFORMAT_16B; /* IIS数据长度 */gAudioI2sSext.Init.MCLKOutput I2S_MCLKOUTPUT_DISABLE; /* 主时钟输出使能 */gAudioI2sSext.Init.AudioFreq I2S_AUDIOFREQ_8K; /* IIS频率设置 */gAudioI2sSext.Init.CPOL I2S_CPOL_LOW; /* 空闲状态时钟电平 */gAudioI2sSext.Init.ClockSource I2S_CLOCK_PLL; /* IIS时钟源为PLL */HAL_I2S_Init(gAudioI2sSext); I2SEXT_SPI-CR2 | 10; /* SPI2/I2S2 TX DMA请求使能. */__HAL_I2S_ENABLE(gAudioI2sSext); /* 使能I2S2 */
}/*** brief I2S底层驱动时钟使能引脚配置DMA配置* note 此函数会被HAL_I2S_Init()调用* param hi2s:I2S句柄* retval 无*/
void HAL_I2S_MspInit(I2S_HandleTypeDef *hi2s)
{GPIO_InitTypeDef gpio_init_struct;I2S_SPI_CLK_ENABLE(); /* 使能SPI2/I2S2时钟 */I2S_WS_GPIO_CLK_ENABLE(); /* 使能I2S_WS时钟左右声道 */I2S_SCLK_GPIO_CLK_ENABLE(); /* 使能I2S_SCLK时钟 */I2S_SDOUT_GPIO_CLK_ENABLE(); /* 使能I2S_SDOUT时钟 */I2S_SDIN_GPIO_CLK_ENABLE(); /* 使能I2S_SDIN时钟 */
// I2S_MCLK_GPIO_CLK_ENABLE(); /* 使能I2S_MCLK时钟当MCLK有内部提供 */gpio_init_struct.Pin I2S_WS_GPIO_PIN;gpio_init_struct.Mode GPIO_MODE_AF_PP; /* 推挽复用 */gpio_init_struct.Pull GPIO_PULLUP; /* 上拉 */gpio_init_struct.Speed GPIO_SPEED_HIGH; /* 高速 */gpio_init_struct.Alternate GPIO_AF_I2S_SPI; /* 复用为SPI/I2S */HAL_GPIO_Init(I2S_WS_GPIO_PORT, gpio_init_struct); /* 初始化I2S_LRCK引脚 */gpio_init_struct.Pin I2S_SCLK_GPIO_PIN;HAL_GPIO_Init(I2S_SCLK_GPIO_PORT, gpio_init_struct); /* 初始化I2S_SCLK引脚 */// gpio_init_struct.Pin I2S_MCLK_GPIO_PIN;
// HAL_GPIO_Init(I2S_MCLK_GPIO_PORT, gpio_init_struct); /* 初始化I2S_MCLK引脚 */gpio_init_struct.Pin I2S_SDIN_GPIO_PIN;HAL_GPIO_Init(I2S_SDIN_GPIO_PORT, gpio_init_struct); /* 初始化I2S_SDIN引脚 */gpio_init_struct.Pin I2S_SDOUT_GPIO_PIN;HAL_GPIO_Init(I2S_SDOUT_GPIO_PORT, gpio_init_struct); /* 初始化I2S_SDOUT引脚 */gpio_init_struct.Pin I2S_SDOUT_GPIO_PIN;gpio_init_struct.Alternate GPIO_AF_I2S_EXT_SPI; /* 复用为I2Sext */HAL_GPIO_Init(I2S_SDOUT_GPIO_PORT, gpio_init_struct); /* 初始化I2S_SDOUT引脚 */RCC-CR | 1 26; /* 开启I2S时钟 */while((RCC-CR 1 27) 0); /* 等待I2S时钟开启成功. */
}/*** brief I2S TX DMA配置* note 设置为双缓冲模式,并开启DMA传输完成中断* param buf0 : M0AR地址.* param buf1 : M1AR地址.* param num : 每次传输数据量* retval 无*/
void I2sTxDmaInit(uint8_t* buf0, uint16_t num)
{ I2S_TX_DMA_CLK_ENABLE(); /* 使能I2S TX DMA时钟 */__HAL_LINKDMA(gAudioI2s, hdmatx, gI2sTxDma); /* 将DMA与I2S联系起来 */gI2sTxDma.Instance I2S_TX_DMASx; /* 设置I2S TX DMA数据流 */gI2sTxDma.Init.Channel I2S_TX_DMASx_Channel; /* 设置I2S TX DMA通道 */gI2sTxDma.Init.Direction DMA_MEMORY_TO_PERIPH; /* 存储器到外设模式 */gI2sTxDma.Init.PeriphInc DMA_PINC_DISABLE; /* 外设非增量模式 */gI2sTxDma.Init.MemInc DMA_MINC_ENABLE; /* 存储器增量模式 */gI2sTxDma.Init.PeriphDataAlignment DMA_PDATAALIGN_HALFWORD; /* 外设数据长度:16位 */gI2sTxDma.Init.MemDataAlignment DMA_MDATAALIGN_HALFWORD; /* 存储器数据长度:16位 */gI2sTxDma.Init.Mode DMA_CIRCULAR; /* 使用循环模式 */gI2sTxDma.Init.Priority DMA_PRIORITY_MEDIUM; /* 高优先级 */gI2sTxDma.Init.FIFOMode DMA_FIFOMODE_DISABLE; /* 不使用FIFO */gI2sTxDma.Init.MemBurst DMA_MBURST_SINGLE; /* 存储器单次突发传输 */gI2sTxDma.Init.PeriphBurst DMA_PBURST_SINGLE; /* 外设突发单次传输 */HAL_DMA_DeInit(gI2sTxDma); /* 先清除以前的设置 */HAL_DMA_Init(gI2sTxDma); /* 初始化DMA */HAL_DMA_Start(gI2sTxDma,(uint32_t)buf0,(uint32_t)I2S_SPI-DR,num);//单缓存 /* 10us延时防止-O2优化出问题 */DelayUs(10); __HAL_DMA_ENABLE_IT(gI2sTxDma, DMA_IT_TC); /* 开启传输完成中断 */__HAL_DMA_CLEAR_FLAG(gI2sTxDma, I2S_TX_DMASx_FLAG); /* 清除DMA传输完成中断标志位 */HAL_NVIC_SetPriority(I2S_TX_DMASx_IRQn,I2sTxPrePriority,I2sTxSubPriority); /* DMA中断优先级 */HAL_NVIC_EnableIRQ(I2S_TX_DMASx_IRQn);__HAL_DMA_DISABLE(gI2sTxDma); /* 先关闭DMA */
}
/*** brief I2Sext RX DMA配置* note 设置为双缓冲模式,并开启DMA传输完成中断* param buf0 : M0AR地址.* param buf1 : M1AR地址.* param num : 每次传输数据量* retval 无*/
void I2sSextRxDmaInit(uint8_t* buf0, uint32_t num)
{ I2SEXT_RX_DMA_CLK_ENABLE(); /* 使能I2S RX DMA时钟 */__HAL_LINKDMA(gAudioI2sSext, hdmarx, gI2sRxDma); /* 将DMA与I2S联系起来 */gI2sRxDma.Instance I2SEXT_RX_DMASx; /* 设置I2S RX DMA数据流 */gI2sRxDma.Init.Channel I2SEXT_RX_DMASx_Channel; /* 设置I2S RX DMA通道 */gI2sRxDma.Init.Direction DMA_PERIPH_TO_MEMORY; /* 外设到存储器模式 */gI2sRxDma.Init.PeriphInc DMA_PINC_DISABLE; /* 外设非增量模式 */gI2sRxDma.Init.MemInc DMA_MINC_ENABLE; /* 存储器增量模式 */gI2sRxDma.Init.PeriphDataAlignment DMA_PDATAALIGN_HALFWORD; /* 外设数据长度:16位 */gI2sRxDma.Init.MemDataAlignment DMA_MDATAALIGN_HALFWORD; /* 存储器数据长度:16位 */gI2sRxDma.Init.Mode DMA_CIRCULAR; /* 使用循环模式 */gI2sRxDma.Init.Priority DMA_PRIORITY_HIGH; /* 中等优先级 */gI2sRxDma.Init.FIFOMode DMA_FIFOMODE_DISABLE; /* 不使用FIFO */gI2sRxDma.Init.MemBurst DMA_MBURST_SINGLE; /* 存储器单次突发传输 */gI2sRxDma.Init.PeriphBurst DMA_PBURST_SINGLE; /* 外设突发单次传输 */HAL_DMA_DeInit(gI2sRxDma); /* 先清除以前的设置 */HAL_DMA_Init(gI2sRxDma); /* 初始化DMA */HAL_DMA_Start(gI2sRxDma,(uint32_t)I2S3ext-DR,(uint32_t)buf0,num);/* 10us延时防止-O2优化出问题 */DelayUs(10); __HAL_DMA_ENABLE_IT(gI2sRxDma, DMA_IT_TC); /* 开启传输完成中断 */__HAL_DMA_CLEAR_FLAG(gI2sRxDma, I2SEXT_RX_DMASx_FLAG); /* 清除DMA传输完成中断标志位 */HAL_NVIC_SetPriority(I2SEXT_RX_DMASx_IRQn,I2sRxPrePriority,I2sRxSubPriority); /* DMA中断优先级 */HAL_NVIC_EnableIRQ(I2SEXT_RX_DMASx_IRQn);__HAL_DMA_DISABLE(gI2sRxDma); /* 先关闭DMA */
}void (*i2s_tx_callback)(void); /* I2S DMA TX 回调函数指针 */
void (*i2s_rx_callback)(void); /* I2S DMA RX 回调函数指针 */
/*** brief I2S TX DMA 中断服务函数* param 无* retval 无*/
void I2S_TX_DMASx_Handle(void)
{ if (__HAL_DMA_GET_FLAG(gI2sTxDma, I2S_TX_DMASx_FLAG) ! RESET) /* DMA传输完成 */{__HAL_DMA_CLEAR_FLAG(gI2sTxDma, I2S_TX_DMASx_FLAG); /* 清除DMA传输完成中断标志位 */if (i2s_tx_callback ! NULL){i2s_tx_callback(); /* 执行回调函数,读取数据等操作在这里面处理 */}}
}/*** brief I2S RX DMA 中断服务函数* param 无* retval 无*/
void I2SEXT_RX_DMASx_Handle(void)
{ if(__HAL_DMA_GET_FLAG(gI2sRxDma,I2SEXT_RX_DMASx_FLAG) ! RESET) /* DMA传输完成 */{__HAL_DMA_CLEAR_FLAG(gI2sRxDma, I2SEXT_RX_DMASx_FLAG); /* 清除DMA传输完成中断标志位 */if (i2s_rx_callback ! NULL){i2s_rx_callback(); /* 执行回调函数,读取数据等操作在这里面处理 */}}
}
/*** brief I2S开始播放* param 无* retval 无*/
void AudioI2sStart(void)
{__HAL_DMA_ENABLE(gI2sTxDma); /* 开启DMA TX传输 */
}
/*** brief I2S停止播放* param 无* retval 无*/
void AudioI2sStop(void)
{__HAL_DMA_DISABLE(gI2sTxDma); /* 关闭DMA TX传输 */
}
/*** brief I2S开始录音* param 无* retval 无*/
void AudioI2sSextStart(void)
{__HAL_DMA_ENABLE(gI2sRxDma); /* 开启DMA RX传输 */
}
/*** brief I2S停止录音* param 无* retval 无*/
void AudioI2sSextStop(void)
{__HAL_DMA_DISABLE(gI2sRxDma); /* 关闭DMA RX传输 */
}3、I2S 头文件
#ifndef __AUDIOIIS__H
#define __AUDIOIIS__H
#include sys/sys.h
/**********************************宏定义**********************************************/
#define GPIO_AF_I2S_SPI GPIO_AF6_SPI3
#define GPIO_AF_I2S_EXT_SPI GPIO_AF7_I2S3ext#define I2S_WS_GPIO_PORT GPIOA
#define I2S_WS_GPIO_PIN GPIO_PIN_15
#define I2S_WS_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0) /* PA口时钟使能 */#define I2S_SCLK_GPIO_PORT GPIOB
#define I2S_SCLK_GPIO_PIN GPIO_PIN_3
#define I2S_SCLK_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0) /* PB口时钟使能 */#define I2S_SDOUT_GPIO_PORT GPIOB
#define I2S_SDOUT_GPIO_PIN GPIO_PIN_4
#define I2S_SDOUT_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0) /* PB口时钟使能 */#define I2S_SDIN_GPIO_PORT GPIOB
#define I2S_SDIN_GPIO_PIN GPIO_PIN_5
#define I2S_SDIN_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0) /* PB口时钟使能 */#define I2S_SPI SPI3
#define I2SEXT_SPI I2S3ext
#define I2S_SPI_CLK_ENABLE() do{ __HAL_RCC_SPI3_CLK_ENABLE(); }while(0) /* I2S3时钟使能*/#define I2S_TX_DMASx DMA1_Stream5
#define I2S_TX_DMASx_Channel DMA_CHANNEL_0
#define I2S_TX_DMASx_Handle DMA1_Stream5_IRQHandler
#define I2S_TX_DMASx_IRQn DMA1_Stream5_IRQn
#define I2S_TX_DMASx_FLAG DMA_FLAG_TCIF1_5
#define I2S_TX_DMA_CLK_ENABLE() do{ __HAL_RCC_DMA1_CLK_ENABLE(); }while(0) /* I2S3 TX DMA时钟使能 */#define I2SEXT_RX_DMASx DMA1_Stream0
#define I2SEXT_RX_DMASx_Channel DMA_CHANNEL_3
#define I2SEXT_RX_DMASx_Handle DMA1_Stream0_IRQHandler
#define I2SEXT_RX_DMASx_IRQn DMA1_Stream0_IRQn
#define I2SEXT_RX_DMASx_FLAG DMA_FLAG_TCIF0_4
#define I2SEXT_RX_DMA_CLK_ENABLE() do{ __HAL_RCC_DMA1_CLK_ENABLE(); }while(0) /* I2S3 RX DMA时钟使能 */#define REC_SAMPLERATE 8000 /* 采样率,8Khz *//*****************************************全局函数***********************************/extern void AudioI2sInit(void);
extern void AudioI2sSextInit(void);
extern void I2sTxDmaInit(uint8_t* buf0, uint16_t num);
// void I2sSextRxDmaInit(uint8_t* buf0, uint8_t *buf1, uint16_t num);
extern void (*i2s_tx_callback)(void);
extern void (*i2s_rx_callback)(void);
extern void AudioI2sStart(void);
extern void AudioI2sStop(void);
extern void AudioI2sSextStart(void);
extern void AudioI2sSextStop(void);
extern void I2sSextRxDmaInit(uint8_t* buf0, uint32_t num);
//extern void I2sTxDmaInit(uint8_t* buf0,uint8_t *buf1, uint16_t num);
//extern void I2sSextRxDmaInit(uint8_t* buf0, uint8_t *buf1, uint16_t num);
extern void i2s_init(uint32_t i2s_standard, uint32_t i2s_mode, uint32_t i2s_clock_polarity, uint32_t i2s_dataformat);
extern void i2sext_init(uint32_t i2sext_standard, uint32_t i2sext_mode, uint32_t i2sext_clock_polarity, uint32_t i2sext_dataformat);
#endif
4、main函数
#include config.h
/****************************全局变量*************************************************/
uint8_t DmrUartTxbufData[REC_I2S_RX_DMA_BUF_SIZE]; /*DMR发送到MCU的PCM数据发送至I2S发声*/
uint8_t DmrUartRxbufData[REC_I2S_RX_DMA_BUF_SIZE];
/*****************************************************************************函 数 名 : 功能描述 : 录音功能初始化输入参数 : void注 意 :设置发发送数据初始化返 回 值 : void作 者 : GCC
*****************************************************************************/
void I2sTxCallback(void)
{
// printf(I2sTxCallback\r\n);
}
void rec_i2s_dma_rx_callback(void)
{}
void recoder_enter_rec_mode(void)
{Es8388AddaCfg(1, 1); /* 开启ADCDAC */Es8388InputCfg(0); /* 开启输入通道(通道1,MIC所在通道) */Es8388MicGain(4); /* MIC增益设置为最大 */Es8388AlcCtrl(1, 5,6); /* 开启立体声ALC控制,以提高录音音量 523.5dB最大最小24dB*/
// Es8388OutputCfg(1,0); /* 关闭通道1和2的输出 */Es8388Rout1Set(15); /* 关闭喇叭. */Es8388I2sCfg(0, 3); /* 飞利浦标准,16位数据长度 */Es8388Channel_3d_set(0,2); //输出右声道DelayMs(100);//主传发送AudioI2sInit();AudioI2sSextInit();I2sSextRxDmaInit(DmrUartRxbufData, REC_I2S_RX_DMA_BUF_SIZE);i2s_rx_callback rec_i2s_dma_rx_callback;I2sTxDmaInit(DmrUartRxbufData,REC_I2S_RX_DMA_BUF_SIZE);//i2s_tx_callback I2sTxCallback;AudioI2sStart(); /* 开始I2S数据发送(主机) */AudioI2sSextStart(); /* 开始I2S数据接收(从机) */}
void RecorderStart(void)
{recoder_enter_rec_mode(); /*进入录音模式 */while(1);
}
总结 总体上比较算是比较容易就是看手册的时候得耐着性子看还有比较多的概念啥的慢慢理解吧看的久了自然不懂得慢慢百度看的多了自然就知道了。