STM32F3/F4系列芯片拥有全双工I2S接口可以与Codec通信,但是目前F1系列芯片或有些国产芯片没有全双工的I2S,要想使用Codec传输音频只能使用两个半双工合为一个全双工I2S,这不仅硬件上需要额外引脚,软件配置上也会少一个可使用的SPI接口。针对这一问题,我们可以使用SPI接口与Codec的“左对齐”接口模式进行通信(不是用SPI模拟I2S接口),单片机作为从器件,Codec作为主器件。接下来介绍使用DMA+乒乓buffer双缓存形式来进行语音回环处理。

/************WM8978配置**********/
uint8_t WM8978_Write_Reg(uint16_t nRegAddr,uint16_t nRegValue)
{IIC_Start();IIC_Send_Byte(0x34);if(IIC_Wait_Ack())return 1;IIC_Send_Byte((nRegAddr<<1)|((nRegValue>>8)&0x01));if(IIC_Wait_Ack())return 2;IIC_Send_Byte(nRegValue&0xFF);if(IIC_Wait_Ack())return 3;IIC_Stop();return 0;
}void WM8978_Init(void)
{IIC_Init();WM8978_Write_Reg(0,0x0000);WM8978_Write_Reg(1,0x013F);WM8978_Write_Reg(2,0x01BF);WM8978_Write_Reg(3,0x006F);WM8978_Write_Reg(4,0x0008);                     //左对齐模式WM8978_Write_Reg(6,0x01AD);                      //MCLK=12MHzWM8978_Write_Reg(7,0x000A);                        //8KWM8978_Write_Reg(10,0x0008);                    //ADC高通滤波器打开WM8978_Write_Reg(14,0x0108);                    //DAC高通滤波器打开WM8978_Write_Reg(36,0x0018);WM8978_Write_Reg(43,0x0010);WM8978_Write_Reg(44,0x0177);WM8978_Write_Reg(45,0x0139);WM8978_Write_Reg(46,0x0139);WM8978_Write_Reg(47,0x0050);WM8978_Write_Reg(48,0x0050);WM8978_Write_Reg(49,0x0002);WM8978_Write_Reg(52,0x012F);WM8978_Write_Reg(53,0x012F);WM8978_Write_Reg(54,0x0129);WM8978_Write_Reg(55,0x0129);
}

SPI2_CS ---> WM8978_LRC

SPI2_SCK ---> WM8978_BCLK

SPI2_MISO ---> WM8978_ADC

SPI2_MOSI ---> WM8978_DAC

PA8--->WM8978_MCLK

void PWM_Init(uint16_t psc,uint16_t arr)
{GPIO_InitTypeDef GPIO_InitStructure;TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;TIM_OCInitTypeDef TIM_OCInitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);       //使能定时器1时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);     //使能GPIOA外设时钟GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);TIM_TimeBaseStructure.TIM_Period = arr-1; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值TIM_TimeBaseStructure.TIM_Prescaler =psc-1; //设置用来作为TIMx时钟频率除数的预分频值 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_timTIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);//初始化PWM模式TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高TIM_OCInitStructure.TIM_Pulse=arr>>1;TIM_OC1Init(TIM1, &TIM_OCInitStructure);TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);TIM_ARRPreloadConfig(TIM1,ENABLE);TIM_CtrlPWMOutputs(TIM1, ENABLE);TIM_Cmd(TIM1, ENABLE);
}
int16_t *pADC,*pDAC;
int16_t SPI2_RxBuf[320],SPI2_TxBuf[320];
__IO uint32_t SPI2_Flag=0;void SPI2_Init(void)
{NVIC_InitTypeDef NVIC_InitStructure;DMA_InitTypeDef DMA_InitStructure;GPIO_InitTypeDef GPIO_InitStructure;SPI_InitTypeDef SPI_InitStructure;pADC=&SPI2_RxBuf[160];pDAC=&SPI2_TxBuf[160];NVIC_InitStructure.NVIC_IRQChannel=DMA1_Channel4_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;          NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;  NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;NVIC_Init(&NVIC_InitStructure);RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOB,&GPIO_InitStructure);GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_InitStructure.GPIO_Pin=GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_15;GPIO_Init(GPIOB,&GPIO_InitStructure);DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)&SPI2->DR;         //外设地址DMA_InitStructure.DMA_MemoryBaseAddr=(uint32_t)SPI2_RxBuf;                   //DMA1内存地址DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC;                                         //数据传输方向:外设到内存DMA_InitStructure.DMA_BufferSize=320;                                //DMA1缓存大小DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;               //外设地址不变DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;                              //内存地址递增DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord; //数据宽度16位DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord;      //数据宽度16位DMA_InitStructure.DMA_Mode=DMA_Mode_Circular;                                                     //DMA1工作循环模式DMA_InitStructure.DMA_Priority=DMA_Priority_Low;                                           //DMA1通道4中优先级低DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;                                                       //DMA1非内存到内存传输DMA_Init(DMA1_Channel4,&DMA_InitStructure);DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)&SPI2->DR;          //外设地址DMA_InitStructure.DMA_MemoryBaseAddr=(uint32_t)SPI2_TxBuf;                   //DMA1内存地址DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralDST;                                         //数据传输方向:内存到外设DMA_InitStructure.DMA_BufferSize=320;                                //DMA1缓存大小DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;               //外设地址不变DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;                              //内存地址递增DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord; //数据宽度16位DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord;      //数据宽度16位DMA_InitStructure.DMA_Mode=DMA_Mode_Circular;                                                     //DMA1工作循环模式DMA_InitStructure.DMA_Priority=DMA_Priority_Low;                                           //DMA1通道5中优先级低DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;                                                       //DMA1非内存到内存传输DMA_Init(DMA1_Channel5,&DMA_InitStructure);DMA_ITConfig(DMA1_Channel4,DMA_IT_HT,ENABLE);DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE);DMA_Cmd(DMA1_Channel4,ENABLE);DMA_Cmd(DMA1_Channel5,ENABLE);SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //SPI设置为双线双向全双工SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;        //SPI从机SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;      //发送接收16位帧结构SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;     //时钟悬空低SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;    //数据捕获于第1个时钟沿SPI_InitStructure.SPI_NSS = SPI_NSS_Hard;       //CS引脚硬件配置SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;        //定义波特率预分频的值:波特率预分频值为16SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;  //数据传输从MSB位开始SPI_Init(SPI2, &SPI_InitStructure);  //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器SPI_I2S_DMACmd(SPI2,SPI_I2S_DMAReq_Tx,ENABLE);SPI_I2S_DMACmd(SPI2,SPI_I2S_DMAReq_Rx,ENABLE);SPI_Cmd(SPI2,ENABLE);
}void DMA1_Channel4_IRQHandler(void)
{if(DMA_GetITStatus(DMA1_IT_HT4) == SET){DMA_ClearITPendingBit(DMA1_IT_HT4);pADC=&SPI2RxBuf[0];pDAC=&SPI2_TxBuf[0];SPI2_Flag=1;}if(DMA_GetITStatus(DMA1_IT_TC4) == SET){DMA_ClearITPendingBit(DMA1_IT_TC4);pADC=&SPI2_RxBuf[160];pDAC=&SPI2_TxBuf[160];SPI2_Flag=1;}
}
int main()
{NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);delay_init(SYSCLK_FREQ_72MHz);WM8978_Init();PWM_Init(3,2);      //PA08 PWM产生12MHz频率给CodecSPI2_Init();Led_Init();while(1){if(SPI2_Flag == 1){SPI2_Flag=0;for(uint32_t i=0;i<160;i++)        //声音回环{pDAC[i]=pADC[i];}GPIOC->ODR^=GPIO_Pin_13;}}
}

https://download.csdn.net/download/qq_44065318/86245927

STM32F103 硬件SPI+WM8978单声道语音回环相关推荐

  1. CC2652RB硬件SPI驱动W5100S网卡进行回环测试

    1. W5100S 1.1 简介 W5100S 是一款多功能的单芯片网络接口芯片,内部集成全硬件的TCP/IP协议栈,以太网MAC和 10Base-T/100Base-TX以太网控制器.主要应用于高集 ...

  2. STM32F103 硬件SPI驱动外部FLASH W25X16

    之前学习过使用,汇顶和盛源达的蓝牙芯片驱动外部FLASH,从外部FLASH中读出图片原始数据,并刷新到OLED上,最开始入门的芯片也是STM321但是在学校的时候基本没有使用STM32来驱动外部FLA ...

  3. ad5764的回读,硬件spi接口

    之前写过了mcu通过硬件spi接口向dac芯片ad5764的数据寄存器写值输出电压,ad5764的offset与gain寄存器的值也是可以通过硬件spi读出来的. 第一步:将待读取的芯片设置为读模式 ...

  4. pcm 8k单声道和双声道采样_音频接口PCM

    1 简介 PCM (Pulse Code Modulation) 是通过等时间隔(即采样率时钟周期)采样将模拟信号数字化的方法.图 1为 4 bit 采样深度的PCM 数据量化示意图.PCM 数字音频 ...

  5. 关于声音的前后左右上下的控制以及单声道立体声的区别

    一. 声像 在立体声重放技术中,用摆声像的方法把各个乐器的位置还原出来,这就是声像.一个乐器就是一个声像点. 我们知道声音是一种波,点击下面链接以flash形式演示波的振动. http://huang ...

  6. STM32硬件SPI通过fm17550读取身份证UID,识别银行卡,识别TYPEA与TYPEB

    上面是我的微信和QQ群,欢迎新朋友的加入. 目录 1.硬件平台 2.驱动实现 3.循环扫卡测试程序 4.TYPEB射频卡扫描 5.TYPEA射频卡扫描 6.身份证UID读取 1.硬件平台 1.STM3 ...

  7. STM32硬件SPI控制TM1638 按键数码管LED显示模块

    STM32硬件SPI控制TM1638按键数码管LED显示模块   从淘宝买来的,TM1638专门是控制LED的,LED组合起来就可以变成数码管,还有按键,这个我就没管了,不想管了,发这个帖子只是为了记 ...

  8. STM32CubeMX | 基于STM32使用HAL库硬件SPI驱动WK2124一拖四SPI转四路串口芯片

    STM32CubeMX | 基于STM32使用HAL库硬件SPI驱动WK2124一拖四SPI转四路串口芯片 STM32基础工程生成 首先使用STM32CUBEMX生成STM32的基础工程,配置时钟到7 ...

  9. STM32音频I2S单声道处理方法

    STM32的M4系列芯片支持全双工的I2S,而一般做语音信号处理的场景一般都采用单声道的处理方法,因为通常情况下左右声道采集的语音都是一样的.然而DMA方式下,STM32的芯片不像DSP那样支持DMA ...

  10. 硬件SPI+LCD增强屏幕刷新率

    1.前言 近日在研究如何提高LCD的刷新率,修改程序发现LCD屏幕用的是模拟通信,所以刷新特别慢,在设置硬件SPI,并使用通过HAL库HAL_SPI_Transmit()函数发送数据后刷新率并没有提升 ...

最新文章

  1. 你不知道的CSS单位
  2. git 连接到远程的其它分支问题
  3. C#路径/文件/目录/I/O常见操作汇总(一)
  4. 王健林:中国房地产不会崩盘 进入十年平稳发展期
  5. 3种关闭linux系统端口方法
  6. python将一行作为字段_关于python:Django admin在同一行显示多个字段
  7. [SpringSecurity]框架概述
  8. P3834 【模板】可持久化线段树 2(整体二分做法)
  9. gin 生成api文档_gin-swagger 生成RESTful风格OpenAPI文档
  10. lwip协议栈在linux运行,LwIP协议栈在uCOS II下的实现
  11. 文档安全管理系统服务器地址是什么,一种文档安全管理系统登录方法及装置
  12. Python GUI界面编程初步 04 - Tkinter设计框架和概念
  13. Android高级-Android操作SQL数据管理,增删改查
  14. NPOI导出 The maximum column width for an individual cell is 255 characters
  15. 一些Gym三星单刷的比赛总结
  16. nodejs下载集成到idea
  17. 第24期、宠物医院管理系统
  18. 解读WPF中的Binding
  19. 上号神器扫码教程,常见问题解答
  20. picturebox绑定datagridview

热门文章

  1. Centos 7环境MySql8.0.28源码安装
  2. mysql当前时间的本月_mysql 获得当前月1号的日期 和 0点日期方法
  3. 番外4:自动进行功放输出阻抗匹配设计(匹配至4次谐波)
  4. 人工智能 —— 归结演绎推理
  5. Microsoft Office LTSC ProPlus 2021 Volume(含:Project + Visio)离线命令方式安装说明(原创)
  6. ROS智能车定位导航仿真(原赛道自主导航,构建地图再导航)
  7. 解决在onedrive里无法打开onenote笔记本的问题
  8. M1芯片的Mac在开发iOS项目时遇到的问题汇总(模拟器无法运行,Cocoapods错误等)
  9. SVO 论文与代码分析总结
  10. pycharm双击无反应