APM32F411使用IIS外设驱动es8388实现自录自播

news/2024/12/27 10:51:06/

前言:

        从零开始学习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 进行数据采集编码,解码数据从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 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/采样率=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.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=(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.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 |= 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);
}
总结:

        总体上比较算是比较容易,就是看手册的时候得耐着性子看,还有比较多的概念啥的,慢慢理解吧,看的久了自然,不懂得慢慢百度,看的多了自然就知道了。


http://www.ppmy.cn/news/1558065.html

相关文章

相机雷达外参标定综述“Automatic targetless LiDAR–camera calibration: a survey“

相机雷达外参标定综述--Automatic targetless LiDAR–camera calibration: a survey 前言1 Introduction2 Background3 Automatic targetless LiDAR–camera calibration3.1 Information theory based method(信息论方法)3.1.1 Pairs of point cloud and image attributes(属性…

vue3标签中的ref属性如何使用$refs获取元素

用在普通DOM标签上&#xff0c;获取的是DOM节点。用在组件标签上&#xff0c;获取的是组件实例对象。 用在普通DOM标签中 获取dom元素方法一&#xff1a; 在需要获取的元素标签上添加ref属性 创建ref对象&#xff0c;存储ref属性标记的内容 通过ref上的value属性即可获取当…

eNSP安装教程(内含安装包)

通过网盘分享的文件&#xff1a;eNSP模拟器.zip 链接: https://pan.baidu.com/s/1wPmAr4MV8YBq3U5i3hbhzQ 提取码: tefj --来自百度网盘超级会员v1的分享 &#xff01;&#xff01;&#xff01;&#xff01;解压后有四个文件&#xff0c;先安装Box&#xff0c;第二个安装cap&a…

最新版本 - 二进制安装k8s1.29.2 集群

一、环境初始化 角色IPmaster01192.168.174.143master02192.168.174.144master03192.168.174.145node01192.168.174.146node02192.168.174.147 角色组件masternginx、APIServer、Schedule、Controllermanager、kubelet、kube-proxy、ETCDnodenginx、kubelet、kube-proxy 作者…

【Chrome Extension】二、导航栏快速查询

【Chrome Extension】二、导航栏快速查询 介绍插件内容1、目录2、manifest.json3、service-worker.js4、sw-omnibox.js5、sw-tips.js6、content.js 介绍 导航栏&#xff0c;输入fei&#xff0c;然后tab可进入当前扩展&#xff1a;Quick Query FeiFeiYeChuan CSDN Blogs&#x…

批量生成二维码,助力数字化管理-Excel易用宝

今天老板给我一份表格&#xff0c;说是要提高企业数字化管理效率&#xff0c;让我把这张表格中的商品编号、材料名称、规格的信息合并到一列&#xff0c;然后将这些商品信息制作生成二维码。 这活可真不好办啊&#xff0c;&#xff0c;我先想想哈&#xff01; 先使用公式将商品…

探索 ES6 基础:开启 JavaScript 新篇章

文章目录 一、ES6 简介与重要性二、变量声明新方式&#xff08;一&#xff09;let 关键字&#xff08;二&#xff09;const 关键字 三、模板字符串四、箭头函数五、函数参数默认值六、Spread / Rest 操作符&#xff08;一&#xff09;Spread 操作符&#xff08;二&#xff09;R…

Wux weapp 组件库的 bug—— wux-picker选择器组件无法正确初始化到选定的value

options的value为Number&#xff0c;组件无法正常使用 解决方案&#xff0c;修改picker-view/utils.js中的getIndexFromValue函数&#xff0c;如下&#xff1a; export function getIndexFromValue(value, col [], fieldNames DEFAULT_FIELD_NAMES) {//return getRealIndex(…