当前位置:网站首页>STM32 SPI+WM8978 voice loopback
STM32 SPI+WM8978 voice loopback
2022-07-30 03:44:00 【Younique741】
STM32F3/F4Series chips have full duplexI2S接口可以与Codec通信,但是目前F1Serial chips or some domestic chips do not have full duplexI2S,要想使用CodecAudio can only be transmitted using two half duplexes combined into one full duplexI2S,Not only does this require extra pins on the hardware,There will also be one less available in the software configurationSPI接口.针对这一问题,我们可以使用SPI接口与Codec的“左对齐”interface mode for communication,The microcontroller acts as a slave device,Codec作为主器件.
/************WM8978配置**********/
uint8_t WM8978_Write_Reg(uint16_t nRegAddr,uint16_t nRegValue)
{
IIC_Start();
IIC_Send_Byte(WM8978_ADDR|0);
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,0x0010); //左对齐模式
WM8978_Write_Reg(6,0x01AD); //MCLK=12MHz
WM8978_Write_Reg(7,0x000A); //8K
WM8978_Write_Reg(10,0x0008); //ADCThe high-pass filter is on
WM8978_Write_Reg(14,0x0108); //DACThe high-pass filter is on
WM8978_Write_Reg(15,0x01ED);
WM8978_Write_Reg(36,0x0018);
WM8978_Write_Reg(16,0x01ED);
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);
}SPI3_CS ---> WM8978_LRC
SPI3_SCK ---> WM8978_BCLK
SPI3_MISO ---> WM8978_ADC
SPI3_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); //使能定时器2时钟
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); //使能GPIO外设时钟
GPIO_PinAFConfig(GPIOA,GPIO_PinSource8,GPIO_AF_6);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_DOWN;
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_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
//初始化PWM模式
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1
TIM_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 SPI3_RxBuf[320],SPI3_TxBuf[320];
__IO uint32_t SPI3_Flag=0;
void SPI3_Init(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
pADC=&SPI3_RxBuf[160];
pDAC=&SPI3_TxBuf[160];
NVIC_InitStructure.NVIC_IRQChannel=DMA2_Channel1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2,ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3,ENABLE);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource15,GPIO_AF_6);
GPIO_PinAFConfig(GPIOB,GPIO_PinSource3,GPIO_AF_6);
GPIO_PinAFConfig(GPIOB,GPIO_PinSource4,GPIO_AF_6);
GPIO_PinAFConfig(GPIOB,GPIO_PinSource5,GPIO_AF_6);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5;
GPIO_Init(GPIOB,&GPIO_InitStructure);
DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)&SPI3->DR; //外设地址
DMA_InitStructure.DMA_MemoryBaseAddr=(uint32_t)SPI3_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; //DMA1Working cycle mode
DMA_InitStructure.DMA_Priority=DMA_Priority_Low; //DMA1通道4Medium priority is low
DMA_InitStructure.DMA_M2M=DMA_M2M_Disable; //DMA1非内存到内存传输
DMA_Init(DMA2_Channel1,&DMA_InitStructure);
DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)&SPI3->DR; //外设地址
DMA_InitStructure.DMA_MemoryBaseAddr=(uint32_t)SPI3_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; //DMA1Working cycle mode
DMA_InitStructure.DMA_Priority=DMA_Priority_Low; //DMA1通道5Medium priority is low
DMA_InitStructure.DMA_M2M=DMA_M2M_Disable; //DMA1非内存到内存传输
DMA_Init(DMA2_Channel2,&DMA_InitStructure);
DMA_ITConfig(DMA2_Channel1,DMA2_IT_HT1,ENABLE);
DMA_ITConfig(DMA2_Channel1,DMA2_IT_TC1,ENABLE);
DMA_Cmd(DMA2_Channel1,ENABLE);
DMA_Cmd(DMA2_Channel2,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; //定义波特率预分频的值:波特率预分频值为32
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //数据传输从MSB位开始
SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值计算的多项式
SPI_Init(SPI3, &SPI_InitStructure); //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
SPI_RxFIFOThresholdConfig(SPI3, SPI_RxFIFOThreshold_HF);
SPI_I2S_DMACmd(SPI3,SPI_I2S_DMAReq_Tx,ENABLE);
SPI_I2S_DMACmd(SPI3,SPI_I2S_DMAReq_Rx,ENABLE);
SPI_Cmd(SPI3,ENABLE);
}
void DMA2_Channel1_IRQHandler(void)
{
if(DMA_GetITStatus(DMA2_IT_HT1) == SET)
{
DMA_ClearITPendingBit(DMA2_IT_HT1);
pADC=&SPI3_RxBuf[0];
pDAC=&SPI3_TxBuf[0];
SPI3_Flag=1;
}
if(DMA_GetITStatus(DMA2_IT_TC1) == SET)
{
DMA_ClearITPendingBit(DMA2_IT_TC1);
pADC=&SPI3_RxBuf[160];
pDAC=&SPI3_TxBuf[160];
SPI3_Flag=1;
}
}int main()
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
delay_init(SYSCLK_FREQ_72MHz);
WM8978_Init();
PWM_Init(3,2); //PA08 PWM产生12MHz频率给Codec
SPI3_Init();
Led_Init();
while(1)
{
if(SPI3_Flag == 1) //sound loop
{
SPI3_Flag=0;
for(uint32_t i=0;i<160;i++)
{
pDAC[i]=pADC[i];
}
GPIO_ToggleBits(GPIOC,GPIO_Pin_13);
}
}
}边栏推荐
猜你喜欢
随机推荐
写给技术人的管理入门知识1:什么是管理
LoadBalancer 负载均衡
使命、愿景、价值观到底有什么区别
精品:淘宝/天猫获取购买到的商品订单详情 API
监控页面部署
Testers, what else do you need to know besides testing?
CDH/CDP 是什么?
spicy (1) basic definition
Summary of Rpc and gRpc Introduction
Nacos installation and deployment
小程序毕设作品之微信积分商城小程序毕业设计成品(3)后台功能
Mini Program Graduation Works WeChat Second-hand Trading Mini Program Graduation Design Finished Works (6) Question Opening Reply PPT
List获取差集产生的问题
[C Supplement] Conversion of Integer to String
微服务CAP原则
基于全志D1-H和XR806的名贵植物监控装置
传统项目转型
Nacos namespace
智能答题功能,CRMEB知识付费系统必须有!
Organizations Going Online: A New Trend in Organizational Digital Transformation









