媒介:
从零开始学习I2s外设,设置Es8288寄存器实现录音播放。本文章使用主控芯片是APM32F411系类。音频相关的概念比力多,就不再次做过多的介绍,本文章只是简质朴现边录边播功能。APM系类兼容st的芯片,所以用st的hal库来实现。本文的介绍顺序从es8388这款芯片开始,再到I2s协议,再到末了代码讲解。
一、Es8388芯片介绍
1、Es8388介绍
Es8388有 2 个 ADC 通道和 2 个 DAC 通道,麦克风放大器,耳机放大器,数字音效以及模拟混淆和增益功能组成。
主要特点:
I2S 接口,支持最高 192K,24bit 音频播放。
DAC 信噪比 96dB;ADC 信噪比 95dB。
支持主机和从机模式。
支持立体声差分输入/麦克风输入。
支持左右声道音量独立调节。
支持 40mW 耳机输出,无爆音。
2、通路
设计通入从es8388的RIN1 进行数据采集编码,解码数据从ROUT1 发送至喇叭。主时钟又外部12.288M的晶振电路提供。
3、采样率相关寄存器
本文设置的采样率是8K,作为正常通话,8K的采样已充足清晰。依据主时钟与采样的关系后续如做更改需要依照下表同步更新。
4、寄存器介绍
寄存器介绍采用正点原子提供的手册做参考,并对其他大概影响的进行另外介绍。
更新增补其他大概影响录音功能的寄存器:(以下寄存器只针对实现我上述所说的单右声道录音右声道播放)
4.1问题介绍
首先说一下我碰到的问题,我通过移植正点原子的历程实现边录边播功能,在探索者上完全没有问题,可以实现,但是在本身打的板子上却存在在录音上电时发出 “哒哒哒哒哒哒” 的声音,此中有一个难以明确的点时,由于寄存器高通滤波开启了导致的,依据笔者的明确,高通滤波时需要开的,但是他会带来“哒哒哒”的噪音不太明确,找了好久,一个一个实验才解决的,但是至今不太明确,大概是硬件设计问题,硬件抄的成熟的方案。
默认开启,设置关闭就解决“哒哒哒”的声音
第二个问题就是在语言的时间也会陪同的杂音“哒哒哒”的杂音声音比力大后续通过一下寄存器减小了杂音,之前上电就出现,后者是持续存在,至今没完全找到缘故原由,如果有知道的可以在评论区交流学习。
说一下以下寄存器:
左DAC清零静音,关闭无关寄存器,防止干扰,由于采用的是单声道,所以无关的寄存器需要全部关闭,克制立体声也需要设置,这里不做赘述,相信各位英语应该都可以,直接拿出相关截图给各位。
麦克风相关寄存器,硬件原理图设置那边,其他的就需要断电,也符合他的特点,“低功耗”
总结:
Es8388 中的ALC调节,MIC增益调节,喇叭声音等一些列寄存器设置都会影响到声音播放时的杂音和啸叫,提示各位调试时可以先去掉喇叭,通过示波器区测试输入输出声波,保护耳朵要经。
二、I2S介绍
1、I2S简介
做一下另外增补:
(1)WS:字选择,映射到spi的nss引脚,及帧时钟用于切换左右声道数据,对应设置的采样率,可以通过示波器查看是否设置精确。
(2)SD:串行数据,映射到mosi引脚,用于发送或接收两个时分复用的数据通道上的 数据。
(3)CK :串行时钟(映射到 SCK 引脚),即位时钟,是主模式下的串行时钟输出以及从模 式下的串行时钟输入。CK 频率 =WS 频率( fs ) *2*16 ( 16 位宽),如果是 32 位宽,则是: CK 频率=WS 频率( fs ) *2*32 ( 32 位宽) 主时钟的256=8*16*2
(4)I2S2ext_SD 和 I2S3ext_SD:用于控制 I2S 全双工模式的附加引脚(映射到 MISO 引脚)。
(5)MCK :即主时钟输出,当 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); /*断电ADC,DAC*/
- es8388I2cWriteReg(0x02, 0xF0); /*0xf3 重新设置adc,dac,重新设置状态机复位,开启ADC DAC*/
-
- // es8388I2cWriteReg(0x03, 0x00);//ADCL power down,left analog input power down
- es8388I2cWriteReg(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/采样率=1536,8K采样率 外部晶振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.36s
-
- es8388I2cWriteReg(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/DSP
- len : 数据长度
- * @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=(3<<5);
- es8388I2cWriteReg(0x1D,depth);
- break;
- case 2:
- depth=0xA0;//单声道关闭立体音
- 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.5db
- tempreg |= mingain & 0x07; //12db
- es8388I2cWriteReg(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 |= 1<<1; /* 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 |= 1<<0; /* 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); /* 开启ADC,DAC */
- Es8388InputCfg(0); /* 开启输入通道(通道1,MIC所在通道) */
- Es8388MicGain(4); /* MIC增益设置为最大 */
- Es8388AlcCtrl(1, 5,6); /* 开启立体声ALC控制,以提高录音音量 5:23.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);
- }
复制代码 总结:
总体上比力算是比力容易,就是看手册的时间得耐着性子看,还有比力多的概念啥的,慢慢明确吧,看的久了自然,不懂得慢慢百度,看的多了自然就知道了。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |