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

打印 上一主题 下一主题

主题 767|帖子 767|积分 2301

媒介:

        从零开始学习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初始化

  1. /*****************************************************************************
  2. 函 数 名  : Es8388Init
  3. 功能描述  : Es8388初始化
  4. 输入参数  : void
  5. 返 回 值  : void
  6. 作  者    : GCC
  7. *****************************************************************************/
  8. void Es8388Init(void)
  9. {
  10.         AudioI2cInit();                                        /* 初始化IIC接口 */       
  11.         es8388I2cWriteReg(0, 0x80);     /* 软复位ES8388 */
  12.         es8388I2cWriteReg(0, 0x00);
  13.         DelayMs(100);                  /* 等待复位 */
  14.     es8388I2cWriteReg(0x01, 0x58);        /*默认0x5c,设置0x58复位模拟软件部分*/
  15.     es8388I2cWriteReg(0x01, 0x50);        /*PdnAna 为0,模拟部分可工作,*/
  16.        
  17. //        es8388I2cWriteReg(0x01, 0x53);//模拟部分不工作
  18.        
  19.     es8388I2cWriteReg(0x02, 0xF3);        /*断电ADC,DAC*/
  20.     es8388I2cWriteReg(0x02, 0xF0);        /*0xf3 重新设置adc,dac,重新设置状态机复位,开启ADC DAC*/
  21.        
  22. //        es8388I2cWriteReg(0x03, 0x00);//ADCL power down,left analog input power down
  23.     es8388I2cWriteReg(0x03, 0x09);   /* 麦克风偏置电源关闭 */
  24.     es8388I2cWriteReg(0x00, 0x06);   /* 使能参考 500K驱动使能,默认500K */
  25.     es8388I2cWriteReg(0x04, 0x00);   /* DAC电源管理,不打开任何通道 */
  26.        
  27.         es8388I2cWriteReg(0x05,0x88);        //LPDACL low powrer, LPLOUT2 low power
  28. //        es8388I2cWriteReg(0x04, 0x90);
  29. //        es8388I2cWriteReg(0x0A,0xF0);
  30.        
  31.         es8388I2cWriteReg(0x08, 0x05);   /* MCLK 6分频产生2.048M时钟 */
  32.     es8388I2cWriteReg(0x2B, 0x80);   /* DAC控制        DACLRC与ADCLRC相同 */
  33.          es8388I2cWriteReg(0x09, 0x00);   // 0x66 ADC L/R PGA增益配置为+24dB
  34.     //es8388I2cWriteReg(0x09, 0x88);   /* ADC L/R PGA增益配置为+24dB */
  35. //        es8388I2cWriteReg(0x0C, 0x8C);         //都来源源于右通道
  36.         es8388I2cWriteReg(0x0C, 0x0C);  //左右声道数据分开
  37.        
  38.         es8388I2cWriteReg(0x0D, 0x0A);   /* ADC配置 MCLK/采样率=1536,8K采样率 外部晶振12.288M*/
  39. //    es8388I2cWriteReg(0x0D, 0x02);   /* ADC配置 MCLK/采样率=256 */
  40.         es8388I2cWriteReg(0x10, 0x00);   /* ADC数字音量控制将信号衰减 L  设置为最小!!! */
  41.     es8388I2cWriteReg(0x11, 0x00);   /* ADC数字音量控制将信号衰减 R  设置为最小!!! */
  42. //        es8388I2cWriteReg(0x13,0xD5);        //lxlvl -1.5dB 1.36s
  43.        
  44.         es8388I2cWriteReg(0x16,0xF3);//Noise gate threshold -30dB, PGA gain held constant Noise gate function enable
  45.     es8388I2cWriteReg(0x17, 0x18);   /* DAC 音频数据为16bit */
  46.     es8388I2cWriteReg(0x18, 0x0A);   /* DAC 配置 MCLK/采样率=256 */
  47.     es8388I2cWriteReg(0x1A, 0x00);   /* DAC数字音量控制将信号衰减 L  设置为最小!!! */
  48.     es8388I2cWriteReg(0x1B, 0x00);   /* DAC数字音量控制将信号衰减 R  设置为最小!!! */
  49. //        es8388I2cWriteReg(0x1C,0xC0);//除重音模式
  50.     es8388I2cWriteReg(0x27, 0xB8);   /* L混频器 */
  51.         es8388I2cWriteReg(0x2A, 0xB8);   /* R混频器,-15 */
  52.         es8388I2cWriteReg(0x0A,0);//选择输入通道
  53.         es8388I2cWriteReg(0x0B,0x10);//
  54.        
  55.         es8388I2cWriteReg(0x0E,0x00);    /*关闭高通滤波防止哒哒哒声(如果存在可选择)*/
  56.         es8388I2cWriteReg(0x03, 0xA9);   /* 麦克风偏置电源关闭 */
  57.     es8388I2cWriteReg(0x06,0x02);
  58.         es8388I2cWriteReg(0x04,0x90);
  59.    DelayMs(100);
  60. }
  61. /*****************************************************************************
  62. 函 数 名  : Es8388I2sCfg
  63. 功能描述  : 设置ES8388工作模式
  64. 输入参数  : fmt : 工作模式
  65.                                 *    @arg      0, 飞利浦标准I2S;
  66.                                 *    @arg      1, MSB(左对齐);
  67.                                 *    @arg      2, LSB(右对齐);
  68.                                 *    @arg      3, PCM/DSP
  69.                          len : 数据长度       
  70.                                 *    @arg      0, 24bit
  71.                                 *    @arg      1, 20bit
  72.                                 *    @arg      2, 18bit
  73.                                 *    @arg      3, 16bit
  74.                                 *    @arg      4, 32bit
  75. 返 回 值  : void
  76. 作  者    : GCC
  77. *****************************************************************************/
  78. void Es8388I2sCfg(uint8_t fmt, uint8_t len)
  79. {
  80.     fmt &= 0x03;
  81.     len &= 0x07;    /* 限定范围 */
  82.     es8388I2cWriteReg(23, (fmt << 1) | (len << 3));  /* R23,ES8388工作模式设置 */
  83. }
  84. /*****************************************************************************
  85. 函 数 名  : Es8388Rout1Set
  86. 功能描述  : 右声道声音输出大小设置
  87. 输入参数  : voluem : 音量大小(0 ~ 33)
  88. 返 回 值  : void
  89. 作  者    : GCC
  90. *****************************************************************************/
  91. void Es8388Rout1Set(uint8_t volume)
  92. {
  93.     if (volume > 33)
  94.     {
  95.         volume = 33;
  96.     }
  97.     es8388I2cWriteReg(0x2F, volume);//ROUT1VOl右声道1
  98. }
  99. /*****************************************************************************
  100. 函 数 名  : Es8388Rout2Set
  101. 功能描述  : MIC_P 声音设置
  102. 输入参数  : voluem : 音量大小(0 ~ 33)
  103. 返 回 值  : void
  104. 作  者    : GCC
  105. *****************************************************************************/
  106. void Es8388Rout2Set(uint8_t volume)
  107. {
  108.     if (volume > 33)
  109.     {
  110.         volume = 33;
  111.     }
  112.     es8388I2cWriteReg(0x31, volume);
  113. }
  114. /**
  115. * @brief       设置3D环绕声
  116. * @param      
  117.                                 修改设置单声道
  118. * @retval      无
  119. */
  120. /*****************************************************************************
  121. 函 数 名  : Es8388Channel_3d_set
  122. 功能描述  : 通道设置,3d立体音设置
  123. 输入参数  : Channel 0 表示立体音 1表示单左声道,2表示设置右声道
  124.                          depth : 0 ~ 7(3D强度,0关闭,7最强)
  125. 返 回 值  : void
  126. 作  者    : GCC
  127. *****************************************************************************/
  128. void Es8388Channel_3d_set(uint8_t depth,u8 Channel)
  129. {
  130.         switch(Channel)
  131.         {
  132.                 case 0:
  133.                         depth &= 0x7;       /* 限定范围 */
  134.                         es8388I2cWriteReg(0x1D, depth << 2);    /* R7,3D环绕设置 */
  135.                 break;
  136.                 case 1:
  137.                         depth=(3<<5);
  138.                         es8388I2cWriteReg(0x1D,depth);
  139.                         break;
  140.                 case 2:
  141.                         depth=0xA0;//单声道关闭立体音
  142.                         es8388I2cWriteReg(0x1D,0xA0);
  143.                         break;
  144.         }
  145. }
  146. /**
  147. * @brief       ES8388 DAC/ADC配置
  148. * @param       dacen : dac使能(1)/关闭(0)
  149. * @param       adcen : adc使能(1)/关闭(0)
  150. * @retval      无
  151. */
  152. void Es8388AddaCfg(uint8_t dacen, uint8_t adcen)
  153. {
  154.     uint8_t tempreg = 0;
  155.    
  156.     tempreg |= ((!dacen) << 0);
  157.     tempreg |= ((!adcen) << 1);
  158.     tempreg |= ((!dacen) << 2);
  159.     tempreg |= ((!adcen) << 3);
  160.     es8388I2cWriteReg(0x02, tempreg);
  161. }
  162. /**
  163. * @brief       ES8388 DAC输出通道配置
  164. * @param       o1en : 通道1使能(1)/禁止(0)
  165. * @param       o2en : 通道2使能(1)/禁止(0)
  166. * @retval      无
  167. */
  168. void Es8388OutputCfg(uint8_t o1en, uint8_t o2en)
  169. {
  170.     uint8_t tempreg = 0;
  171.     tempreg |= o1en * (3 << 4);
  172.     tempreg |= o2en * (3 << 2);
  173.     es8388I2cWriteReg(0x04, tempreg);
  174. }
  175. /**
  176. * @brief       ES8388 MIC左右通道增益设置(MIC PGA增益)
  177. * @param       gain : 0~8, 对应0~24dB  3dB/Step
  178. * @retval      无
  179. */
  180. void Es8388MicGain(uint8_t gain)
  181. {
  182.     gain &= 0x0F;          //设置低4位
  183.     gain |= gain << 4;//设置高位4位
  184.     es8388I2cWriteReg(0x09, gain);       /* R9,左右通道PGA增益设置 */
  185. }
  186. /**
  187. * @brief       ES8388 ALC设置
  188. * @param       sel
  189. *   @arg       0,关闭ALC
  190. *   @arg       1,右通道ALC
  191. *   @arg       2,左通道ALC
  192. *   @arg       3,立体声ALC
  193. * @param       maxgain : 0~7,对应-6.5~+35.5dB
  194. * @param       mingain : 0~7,对应-12~+30dB 6dB/STEP
  195. * @retval      无
  196. */
  197. void Es8388AlcCtrl(uint8_t sel, uint8_t maxgain, uint8_t mingain)
  198. {
  199.     uint8_t tempreg = 0;
  200.    
  201.     tempreg = sel << 6;
  202.     tempreg |= (maxgain & 0x07) << 3;//set maximum gain of PGA        17.5db
  203.     tempreg |= mingain & 0x07;                 //12db
  204.     es8388I2cWriteReg(0x12, tempreg);     /* R18,ALC设置 */
  205. }
  206. /**
  207. * @brief       ES8388 ADC输出通道配置
  208. * @param       in : 输入通道
  209. *    @arg      0, 通道1输入
  210. *    @arg      1, 通道2输入
  211. * @retval      无
  212. */
  213. void Es8388InputCfg(uint8_t in)
  214. {
  215.         es8388I2cWriteReg(0x0A, (5 * in) << 4);   /* ADC1 输入通道选择L/R  INPUT1 */
  216. }
复制代码
2、I2S 代码

  1. /***************************************************************************************/
  2. I2S_HandleTypeDef gAudioI2s;        /* I2S句柄 */
  3. I2S_HandleTypeDef gAudioI2sSext;     /* I2S句柄 */
  4. DMA_HandleTypeDef gI2sTxDma;  /* I2S发送DMA句柄 */
  5. DMA_HandleTypeDef gI2sRxDma;  /* I2S接收DMA句柄 */
  6. /************************************************************************************/
  7. /**
  8. * @brief       I2S初始化
  9. * @param       i2s_standard        : I2S标准
  10. *   @note      可以设置            : I2S_STANDARD_PHILIPS/I2S_STANDARD_MSB/
  11. *                                    I2S_STANDARD_LSB/I2S_STANDARD_PCM_SHORT/I2S_STANDARD_PCM_LONG
  12. * @param       i2s_mode            : I2S工作模式
  13. *   @note      可以设置            : I2S_MODE_SLAVE_TX/I2S_MODE_SLAVE_RX/I2S_MODE_MASTER_TX/I2S_MODE_MASTER_RX
  14. * @param       i2s_clock_polarity  : 空闲状态时钟电平
  15. * @param       i2s_dataformat      : 数据长度
  16. *   @note      可以设置            : I2S_DATAFORMAT_16B/I2S_DATAFORMAT_16B_EXTENDED/I2S_DATAFORMAT_24B/I2S_DATAFORMAT_32B
  17. * @retval      无
  18. */
  19. void AudioI2sInit(void)
  20. {
  21.     gAudioI2s.Instance = I2S_SPI;
  22.     gAudioI2s.Init.Mode = I2S_MODE_MASTER_TX;           /* IIS模式 */
  23.     gAudioI2s.Init.Standard = I2S_STANDARD_PHILIPS;     /* IIS标准 */
  24.     gAudioI2s.Init.DataFormat = I2S_DATAFORMAT_16B;      /* IIS数据长度 */
  25.     gAudioI2s.Init.MCLKOutput = I2S_MCLKOUTPUT_ENABLE;  /* 主时钟输出使能 */
  26.     gAudioI2s.Init.AudioFreq = I2S_AUDIOFREQ_8K;   /* IIS频率设置 */
  27.     gAudioI2s.Init.CPOL = I2S_CPOL_LOW;           /* 空闲状态时钟电平 */
  28.     gAudioI2s.Init.ClockSource = I2S_CLOCK_PLL;         /* IIS时钟源为PLL */
  29.     HAL_I2S_Init(&gAudioI2s);
  30.     I2S_SPI->CR2 |= 1<<1;               /* SPI2/I2S2 TX DMA请求使能. */
  31.     __HAL_I2S_ENABLE(&gAudioI2s);    /* 使能I2S2 */
  32. }
  33. /**
  34. * @brief       I2SEXT初始化
  35. * @param       i2s_standard        : I2S标准
  36. *   @note      可以设置            : I2S_STANDARD_PHILIPS/I2S_STANDARD_MSB/
  37. *                                    I2S_STANDARD_LSB/I2S_STANDARD_PCM_SHORT/I2S_STANDARD_PCM_LONG
  38. * @param       i2s_mode            : I2S工作模式
  39. *   @note      可以设置            : I2S_MODE_SLAVE_TX/I2S_MODE_SLAVE_RX/I2S_MODE_MASTER_TX/I2S_MODE_MASTER_RX
  40. * @param       i2s_clock_polarity  : 显示数字的位数
  41. * @param       i2s_dataformat      : 数据长度
  42. *   @note      可以设置            : I2S_DATAFORMAT_16B/I2S_DATAFORMAT_16B_EXTENDED/I2S_DATAFORMAT_24B/I2S_DATAFORMAT_32B
  43. * @retval      无
  44. */
  45. void AudioI2sSextInit(void)
  46. {
  47.     gAudioI2sSext.Instance = I2SEXT_SPI;
  48.     gAudioI2sSext.Init.Mode = I2S_MODE_SLAVE_RX;             /* IIS模式 */
  49.     gAudioI2sSext.Init.Standard = I2S_STANDARD_PHILIPS;           /* IIS标准 */
  50.     gAudioI2sSext.Init.DataFormat = I2S_DATAFORMAT_16B;       /* IIS数据长度 */
  51.     gAudioI2sSext.Init.MCLKOutput = I2S_MCLKOUTPUT_DISABLE;   /* 主时钟输出使能 */
  52.     gAudioI2sSext.Init.AudioFreq = I2S_AUDIOFREQ_8K;                    /* IIS频率设置 */
  53.     gAudioI2sSext.Init.CPOL = I2S_CPOL_LOW;         /* 空闲状态时钟电平 */
  54.     gAudioI2sSext.Init.ClockSource = I2S_CLOCK_PLL;          /* IIS时钟源为PLL */
  55.     HAL_I2S_Init(&gAudioI2sSext);
  56.     I2SEXT_SPI->CR2 |= 1<<0;                /* SPI2/I2S2 TX DMA请求使能. */
  57.     __HAL_I2S_ENABLE(&gAudioI2sSext);     /* 使能I2S2 */
  58. }
  59. /**
  60. * @brief       I2S底层驱动,时钟使能,引脚配置,DMA配置
  61. * @note        此函数会被HAL_I2S_Init()调用
  62. * @param       hi2s:I2S句柄
  63. * @retval      无
  64. */
  65. void HAL_I2S_MspInit(I2S_HandleTypeDef *hi2s)
  66. {
  67.         GPIO_InitTypeDef gpio_init_struct;
  68.     I2S_SPI_CLK_ENABLE();           /* 使能SPI2/I2S2时钟 */
  69.     I2S_WS_GPIO_CLK_ENABLE();       /* 使能I2S_WS时钟,左右声道 */
  70.     I2S_SCLK_GPIO_CLK_ENABLE();     /* 使能I2S_SCLK时钟 */
  71.     I2S_SDOUT_GPIO_CLK_ENABLE();    /* 使能I2S_SDOUT时钟 */
  72.     I2S_SDIN_GPIO_CLK_ENABLE();     /* 使能I2S_SDIN时钟 */
  73. //        I2S_MCLK_GPIO_CLK_ENABLE();     /* 使能I2S_MCLK时钟,当MCLK有内部提供 */
  74.        
  75.     gpio_init_struct.Pin = I2S_WS_GPIO_PIN;
  76.     gpio_init_struct.Mode = GPIO_MODE_AF_PP;        /* 推挽复用 */
  77.     gpio_init_struct.Pull = GPIO_PULLUP;            /* 上拉 */
  78.     gpio_init_struct.Speed = GPIO_SPEED_HIGH;       /* 高速 */
  79.     gpio_init_struct.Alternate = GPIO_AF_I2S_SPI;   /* 复用为SPI/I2S */
  80.    
  81.     HAL_GPIO_Init(I2S_WS_GPIO_PORT, &gpio_init_struct);   /* 初始化I2S_LRCK引脚 */
  82.     gpio_init_struct.Pin = I2S_SCLK_GPIO_PIN;
  83.     HAL_GPIO_Init(I2S_SCLK_GPIO_PORT, &gpio_init_struct);   /* 初始化I2S_SCLK引脚 */
  84.    
  85. //        gpio_init_struct.Pin = I2S_MCLK_GPIO_PIN;
  86. //    HAL_GPIO_Init(I2S_MCLK_GPIO_PORT, &gpio_init_struct);   /* 初始化I2S_MCLK引脚 */
  87.     gpio_init_struct.Pin = I2S_SDIN_GPIO_PIN;
  88.     HAL_GPIO_Init(I2S_SDIN_GPIO_PORT, &gpio_init_struct);   /* 初始化I2S_SDIN引脚 */
  89.    
  90.     gpio_init_struct.Pin = I2S_SDOUT_GPIO_PIN;
  91.     HAL_GPIO_Init(I2S_SDOUT_GPIO_PORT, &gpio_init_struct);  /* 初始化I2S_SDOUT引脚 */
  92.     gpio_init_struct.Pin = I2S_SDOUT_GPIO_PIN;
  93.     gpio_init_struct.Alternate = GPIO_AF_I2S_EXT_SPI;       /* 复用为I2Sext */
  94.     HAL_GPIO_Init(I2S_SDOUT_GPIO_PORT, &gpio_init_struct);  /* 初始化I2S_SDOUT引脚 */
  95.           RCC->CR |= 1 << 26;                 /* 开启I2S时钟 */
  96.     while((RCC->CR & 1 << 27) == 0);    /* 等待I2S时钟开启成功. */
  97. }
  98. /**
  99. * @brief       I2S TX DMA配置
  100. *  @note       设置为双缓冲模式,并开启DMA传输完成中断
  101. * @param       buf0 : M0AR地址.
  102. * @param       buf1 : M1AR地址.
  103. * @param       num  : 每次传输数据量
  104. * @retval      无
  105. */
  106. void I2sTxDmaInit(uint8_t* buf0, uint16_t num)
  107. {  
  108.     I2S_TX_DMA_CLK_ENABLE();                                               /* 使能I2S TX DMA时钟 */
  109.     __HAL_LINKDMA(&gAudioI2s, hdmatx, gI2sTxDma);              /* 将DMA与I2S联系起来 */
  110.     gI2sTxDma.Instance = I2S_TX_DMASx;                            /* 设置I2S TX DMA数据流 */
  111.     gI2sTxDma.Init.Channel = I2S_TX_DMASx_Channel;                /* 设置I2S TX DMA通道 */
  112.     gI2sTxDma.Init.Direction = DMA_MEMORY_TO_PERIPH;              /* 存储器到外设模式 */
  113.     gI2sTxDma.Init.PeriphInc = DMA_PINC_DISABLE;                  /* 外设非增量模式 */
  114.     gI2sTxDma.Init.MemInc = DMA_MINC_ENABLE;                      /* 存储器增量模式 */
  115.     gI2sTxDma.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; /* 外设数据长度:16位 */
  116.     gI2sTxDma.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;    /* 存储器数据长度:16位 */
  117.         gI2sTxDma.Init.Mode = DMA_CIRCULAR;                           /* 使用循环模式 */
  118.     gI2sTxDma.Init.Priority = DMA_PRIORITY_MEDIUM;                  /* 高优先级 */
  119.     gI2sTxDma.Init.FIFOMode = DMA_FIFOMODE_DISABLE;               /* 不使用FIFO */
  120.     gI2sTxDma.Init.MemBurst = DMA_MBURST_SINGLE;                  /* 存储器单次突发传输 */
  121.     gI2sTxDma.Init.PeriphBurst = DMA_PBURST_SINGLE;               /* 外设突发单次传输 */
  122.     HAL_DMA_DeInit(&gI2sTxDma);                                   /* 先清除以前的设置 */
  123.     HAL_DMA_Init(&gI2sTxDma);                                     /* 初始化DMA */
  124.         HAL_DMA_Start(&gI2sTxDma,(uint32_t)buf0,(uint32_t)&I2S_SPI->DR,num);//单缓存                                                /* 10us延时,防止-O2优化出问题 */
  125.     DelayUs(10);   
  126.         __HAL_DMA_ENABLE_IT(&gI2sTxDma, DMA_IT_TC);                   /* 开启传输完成中断 */
  127.     __HAL_DMA_CLEAR_FLAG(&gI2sTxDma, I2S_TX_DMASx_FLAG);          /* 清除DMA传输完成中断标志位 */
  128.        
  129.         HAL_NVIC_SetPriority(I2S_TX_DMASx_IRQn,I2sTxPrePriority,I2sTxSubPriority);                /* DMA中断优先级 */
  130.     HAL_NVIC_EnableIRQ(I2S_TX_DMASx_IRQn);
  131.     __HAL_DMA_DISABLE(&gI2sTxDma);                                /* 先关闭DMA */
  132. }
  133. /**
  134. * @brief       I2Sext RX DMA配置
  135. *  @note       设置为双缓冲模式,并开启DMA传输完成中断
  136. * @param       buf0 : M0AR地址.
  137. * @param       buf1 : M1AR地址.
  138. * @param       num  : 每次传输数据量
  139. * @retval      无
  140. */
  141. void I2sSextRxDmaInit(uint8_t* buf0, uint32_t num)       
  142. {  
  143.     I2SEXT_RX_DMA_CLK_ENABLE();                                            /* 使能I2S RX DMA时钟 */
  144.     __HAL_LINKDMA(&gAudioI2sSext, hdmarx, gI2sRxDma);           /* 将DMA与I2S联系起来 */
  145.        
  146.     gI2sRxDma.Instance = I2SEXT_RX_DMASx;                         /* 设置I2S RX DMA数据流 */
  147.     gI2sRxDma.Init.Channel = I2SEXT_RX_DMASx_Channel;             /* 设置I2S RX DMA通道 */
  148.     gI2sRxDma.Init.Direction = DMA_PERIPH_TO_MEMORY;              /* 外设到存储器模式 */
  149.     gI2sRxDma.Init.PeriphInc = DMA_PINC_DISABLE;                  /* 外设非增量模式 */
  150.     gI2sRxDma.Init.MemInc = DMA_MINC_ENABLE;                      /* 存储器增量模式 */
  151.     gI2sRxDma.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; /* 外设数据长度:16位 */
  152.     gI2sRxDma.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;    /* 存储器数据长度:16位 */
  153.     gI2sRxDma.Init.Mode = DMA_CIRCULAR;                           /* 使用循环模式 */
  154.     gI2sRxDma.Init.Priority = DMA_PRIORITY_HIGH;                        /* 中等优先级 */
  155.     gI2sRxDma.Init.FIFOMode = DMA_FIFOMODE_DISABLE;               /* 不使用FIFO */
  156.     gI2sRxDma.Init.MemBurst = DMA_MBURST_SINGLE;                  /* 存储器单次突发传输 */
  157.     gI2sRxDma.Init.PeriphBurst = DMA_PBURST_SINGLE;               /* 外设突发单次传输 */
  158.         HAL_DMA_DeInit(&gI2sRxDma);                                   /* 先清除以前的设置 */
  159.     HAL_DMA_Init(&gI2sRxDma);                                     /* 初始化DMA */
  160.         HAL_DMA_Start(&gI2sRxDma,(uint32_t)&I2S3ext->DR,(uint32_t)buf0,num);
  161.         /* 10us延时,防止-O2优化出问题 */
  162.         DelayUs(10);
  163.         __HAL_DMA_ENABLE_IT(&gI2sRxDma, DMA_IT_TC);                   /* 开启传输完成中断 */
  164.     __HAL_DMA_CLEAR_FLAG(&gI2sRxDma, I2SEXT_RX_DMASx_FLAG);       /* 清除DMA传输完成中断标志位 */
  165.    
  166.     HAL_NVIC_SetPriority(I2SEXT_RX_DMASx_IRQn,I2sRxPrePriority,I2sRxSubPriority);             /* DMA中断优先级 */
  167.     HAL_NVIC_EnableIRQ(I2SEXT_RX_DMASx_IRQn);
  168.         __HAL_DMA_DISABLE(&gI2sRxDma);                                /* 先关闭DMA */
  169. }
  170. void (*i2s_tx_callback)(void);  /* I2S DMA TX 回调函数指针 */
  171. void (*i2s_rx_callback)(void);  /* I2S DMA RX 回调函数指针 */
  172. /**
  173. * @brief       I2S TX DMA 中断服务函数
  174. * @param       无
  175. * @retval      无
  176. */
  177. void I2S_TX_DMASx_Handle(void)
  178. {  
  179.     if (__HAL_DMA_GET_FLAG(&gI2sTxDma, I2S_TX_DMASx_FLAG) != RESET)   /* DMA传输完成 */
  180.     {
  181.         __HAL_DMA_CLEAR_FLAG(&gI2sTxDma, I2S_TX_DMASx_FLAG);          /* 清除DMA传输完成中断标志位 */
  182.         if (i2s_tx_callback != NULL)
  183.         {
  184.             i2s_tx_callback();  /* 执行回调函数,读取数据等操作在这里面处理 */
  185.         }
  186.     }
  187. }
  188. /**
  189. * @brief       I2S RX DMA 中断服务函数
  190. * @param       无
  191. * @retval      无
  192. */
  193. void I2SEXT_RX_DMASx_Handle(void)
  194. {
  195.     if(__HAL_DMA_GET_FLAG(&gI2sRxDma,I2SEXT_RX_DMASx_FLAG) != RESET) /* DMA传输完成 */
  196.     {
  197.         __HAL_DMA_CLEAR_FLAG(&gI2sRxDma, I2SEXT_RX_DMASx_FLAG);       /* 清除DMA传输完成中断标志位 */
  198.         if (i2s_rx_callback != NULL)
  199.         {
  200.             i2s_rx_callback();  /* 执行回调函数,读取数据等操作在这里面处理 */
  201.         }
  202.     }
  203. }
  204. /**
  205. * @brief       I2S开始播放
  206. * @param       无
  207. * @retval      无
  208. */
  209. void AudioI2sStart(void)
  210. {
  211.         __HAL_DMA_ENABLE(&gI2sTxDma);     /* 开启DMA TX传输 */
  212. }
  213. /**
  214. * @brief       I2S停止播放
  215. * @param       无
  216. * @retval      无
  217. */
  218. void AudioI2sStop(void)
  219. {
  220.     __HAL_DMA_DISABLE(&gI2sTxDma);    /* 关闭DMA TX传输 */
  221. }
  222. /**
  223. * @brief       I2S开始录音
  224. * @param       无
  225. * @retval      无
  226. */
  227. void AudioI2sSextStart(void)
  228. {
  229.     __HAL_DMA_ENABLE(&gI2sRxDma);     /* 开启DMA RX传输 */
  230. }
  231. /**
  232. * @brief       I2S停止录音
  233. * @param       无
  234. * @retval      无
  235. */
  236. void AudioI2sSextStop(void)
  237. {
  238.     __HAL_DMA_DISABLE(&gI2sRxDma);   /* 关闭DMA RX传输 */
  239. }
复制代码
3、I2S 头文件

  1. #ifndef __AUDIOIIS__H
  2. #define __AUDIOIIS__H
  3. #include "sys/sys.h"
  4. /**********************************宏定义**********************************************/
  5. #define GPIO_AF_I2S_SPI                 GPIO_AF6_SPI3
  6. #define GPIO_AF_I2S_EXT_SPI             GPIO_AF7_I2S3ext
  7. #define I2S_WS_GPIO_PORT              GPIOA
  8. #define I2S_WS_GPIO_PIN               GPIO_PIN_15
  9. #define I2S_WS_GPIO_CLK_ENABLE()      do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0)     /* PA口时钟使能 */
  10. #define I2S_SCLK_GPIO_PORT              GPIOB
  11. #define I2S_SCLK_GPIO_PIN               GPIO_PIN_3
  12. #define I2S_SCLK_GPIO_CLK_ENABLE()      do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0)     /* PB口时钟使能 */
  13. #define I2S_SDOUT_GPIO_PORT             GPIOB
  14. #define I2S_SDOUT_GPIO_PIN              GPIO_PIN_4
  15. #define I2S_SDOUT_GPIO_CLK_ENABLE()     do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0)     /* PB口时钟使能 */
  16. #define I2S_SDIN_GPIO_PORT              GPIOB
  17. #define I2S_SDIN_GPIO_PIN               GPIO_PIN_5
  18. #define I2S_SDIN_GPIO_CLK_ENABLE()      do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0)     /* PB口时钟使能 */
  19. #define I2S_SPI                         SPI3
  20. #define I2SEXT_SPI                      I2S3ext
  21. #define I2S_SPI_CLK_ENABLE()            do{ __HAL_RCC_SPI3_CLK_ENABLE(); }while(0)      /* I2S3时钟使能*/
  22. #define I2S_TX_DMASx                    DMA1_Stream5
  23. #define I2S_TX_DMASx_Channel            DMA_CHANNEL_0
  24. #define I2S_TX_DMASx_Handle             DMA1_Stream5_IRQHandler
  25. #define I2S_TX_DMASx_IRQn               DMA1_Stream5_IRQn
  26. #define I2S_TX_DMASx_FLAG               DMA_FLAG_TCIF1_5
  27. #define I2S_TX_DMA_CLK_ENABLE()         do{ __HAL_RCC_DMA1_CLK_ENABLE(); }while(0)   /* I2S3 TX DMA时钟使能 */
  28. #define I2SEXT_RX_DMASx                    DMA1_Stream0
  29. #define I2SEXT_RX_DMASx_Channel            DMA_CHANNEL_3
  30. #define I2SEXT_RX_DMASx_Handle             DMA1_Stream0_IRQHandler
  31. #define I2SEXT_RX_DMASx_IRQn               DMA1_Stream0_IRQn
  32. #define I2SEXT_RX_DMASx_FLAG               DMA_FLAG_TCIF0_4
  33. #define I2SEXT_RX_DMA_CLK_ENABLE()         do{ __HAL_RCC_DMA1_CLK_ENABLE(); }while(0)   /* I2S3 RX DMA时钟使能 */
  34. #define REC_SAMPLERATE              8000       /* 采样率,8Khz */
  35. /*****************************************全局函数***********************************/
  36. extern void AudioI2sInit(void);
  37. extern void AudioI2sSextInit(void);
  38. extern void I2sTxDmaInit(uint8_t* buf0, uint16_t num);
  39. // void I2sSextRxDmaInit(uint8_t* buf0, uint8_t *buf1, uint16_t num);
  40. extern void (*i2s_tx_callback)(void);
  41. extern void (*i2s_rx_callback)(void);
  42. extern void AudioI2sStart(void);
  43. extern void AudioI2sStop(void);
  44. extern void AudioI2sSextStart(void);
  45. extern void AudioI2sSextStop(void);
  46. extern void I2sSextRxDmaInit(uint8_t* buf0, uint32_t num);
  47. //extern void I2sTxDmaInit(uint8_t* buf0,uint8_t *buf1, uint16_t num);
  48. //extern void I2sSextRxDmaInit(uint8_t* buf0, uint8_t *buf1, uint16_t num);
  49. extern void i2s_init(uint32_t i2s_standard, uint32_t i2s_mode, uint32_t i2s_clock_polarity, uint32_t i2s_dataformat);
  50. extern void i2sext_init(uint32_t i2sext_standard, uint32_t i2sext_mode, uint32_t i2sext_clock_polarity, uint32_t i2sext_dataformat);
  51. #endif
复制代码
4、main函数

  1. #include "config.h"
  2. /****************************全局变量*************************************************/
  3. uint8_t DmrUartTxbufData[REC_I2S_RX_DMA_BUF_SIZE];  /*DMR发送到MCU的PCM数据发送至I2S发声*/       
  4. uint8_t DmrUartRxbufData[REC_I2S_RX_DMA_BUF_SIZE];
  5. /*****************************************************************************
  6. 函 数 名  :
  7. 功能描述  : 录音功能初始化
  8. 输入参数  : void
  9. 注           意  :设置发发送数据初始化
  10. 返 回 值  : void
  11. 作  者    : GCC
  12. *****************************************************************************/
  13. void I2sTxCallback(void)
  14. {
  15. //        printf("I2sTxCallback\r\n");
  16. }
  17. void rec_i2s_dma_rx_callback(void)
  18. {
  19.        
  20. }
  21. void recoder_enter_rec_mode(void)
  22. {
  23.         Es8388AddaCfg(1, 1);          /* 开启ADC,DAC */
  24.         Es8388InputCfg(0);            /* 开启输入通道(通道1,MIC所在通道) */
  25.     Es8388MicGain(4);             /* MIC增益设置为最大 */
  26.     Es8388AlcCtrl(1, 5,6);        /* 开启立体声ALC控制,以提高录音音量 5:23.5dB最大,最小+24dB*/
  27. //    Es8388OutputCfg(1,0);        /* 关闭通道1和2的输出 */
  28.         Es8388Rout1Set(15);           /* 关闭喇叭. */
  29.     Es8388I2sCfg(0, 3);           /* 飞利浦标准,16位数据长度 */
  30.         Es8388Channel_3d_set(0,2);                //输出右声道
  31.         DelayMs(100);
  32.         //主传发送
  33.         AudioI2sInit();
  34.         AudioI2sSextInit();
  35.         I2sSextRxDmaInit(DmrUartRxbufData, REC_I2S_RX_DMA_BUF_SIZE);
  36.         i2s_rx_callback = rec_i2s_dma_rx_callback;
  37.        
  38.         I2sTxDmaInit(DmrUartRxbufData,REC_I2S_RX_DMA_BUF_SIZE);//
  39.         i2s_tx_callback = I2sTxCallback;
  40.         AudioI2sStart();   /* 开始I2S数据发送(主机) */
  41.     AudioI2sSextStart();    /* 开始I2S数据接收(从机) */
  42. }
  43. void RecorderStart(void)
  44. {
  45.         recoder_enter_rec_mode();   /*进入录音模式 */
  46.     while(1);
  47. }
复制代码
总结:

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


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

惊雷无声

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表