#include "sys.h"
#include "delay.h"
#include "sdram.h"
#include "malloc.h"
#include "wm8978.h"
#include "usbd_audio_core.h"
#include "stm324x9i_usb_audio_codec.h"
#include "usbd_usr.h"
#include "usb_conf.h"
/************************************************
ALIENTEK 阿波罗STM32F429开发板实验53
USB读卡器(Slave)实验-HAL库函数版
技术支持:
www.openedv.com
淘宝店铺:
http://eboard.taobao.com
关注微信公众平台微信号:"正点原子",免费获取STM32资料。
广州市星翼电子科技有限公司
作者:正点原子 @ALIENTEK
************************************************/
USB_OTG_CORE_HANDLE USB_OTG_dev;
/* I2S 引脚复用初始化 */
void HAL_I2S_MspInit(I2S_HandleTypeDef *hi2s)
{
__HAL_RCC_GPIOC_CLK_ENABLE() ; /* GPIO Ports Clock Enable */
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_SPI2_CLK_ENABLE();
GPIO_InitTypeDef GPIO_Initure1;
GPIO_InitTypeDef GPIO_Initure2;
GPIO_InitTypeDef GPIO_Initure3;
GPIO_Initure1.Pin = GPIO_PIN_10|GPIO_PIN_12|GPIO_PIN_15;
GPIO_Initure1.Mode = GPIO_MODE_AF_PP;
GPIO_Initure1.Pull=GPIO_PULLUP;
GPIO_Initure1.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_Initure1.Alternate = GPIO_AF5_SPI2;
GPIO_Initure2.Pin= GPIO_PIN_2;
GPIO_Initure2.Mode=GPIO_MODE_AF_PP;
GPIO_Initure2.Pull=GPIO_PULLUP;
GPIO_Initure2.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_Initure2.Alternate= GPIO_AF6_I2S2ext;
GPIO_Initure3.Pin= GPIO_PIN_6;
GPIO_Initure3.Mode=GPIO_MODE_AF_PP;
GPIO_Initure3.Pull=GPIO_PULLUP;
GPIO_Initure3.Speed=GPIO_SPEED_FREQ_HIGH;
GPIO_Initure3.Alternate= GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOB, &GPIO_Initure1); //PB10/12/15 复用功能输出
HAL_GPIO_Init(GPIOC, &GPIO_Initure2);
HAL_GPIO_Init(GPIOC, &GPIO_Initure3); //PC2/6 复用功能输出
}
//采样率计算公式:Fs=I2SxCLK/[256*(2*I2SDIV+ODD)]
//I2SxCLK=(HSE/pllm)*PLLI2SN/PLLI2SR
//一般HSE=8Mhz
//pllm:在Sys_Clock_Set设置的时候确定,一般是8
//PLLI2SN:一般是192~432
//PLLI2SR:2~7
//I2SDIV:2~255
//ODD:0/1
//I2S分频系数表@pllm=25,HSE=25Mhz,即vco输入频率为1Mhz
//表格式:采样率/10,PLLI2SN,PLLI2SR,I2SDIV,ODD
const u16 I2S_PSC_TBL[][5]=
{
{800 ,256,5,12,1}, //8Khz采样率
{1102,429,4,19,0}, //11.025Khz采样率
{1600,213,2,13,0}, //16Khz采样率 open MCLK
{2205,429,4, 9,1}, //22.05Khz采样率
{3200,213,2, 6,1}, //32Khz采样率
{4410,271,2, 6,0}, //44.1Khz采样率
{4800,258,3, 3,1}, //48Khz采样率
{8820,316,2, 3,1}, //88.2Khz采样率
{9600,344,2, 3,1}, //96Khz采样率
{17640,361,2,2,0}, //176.4Khz采样率
{19200,393,2,2,0}, //192Khz采样率
};
//设置IIS的采样率(@MCKEN)
//samplerate:采样率,单位:Hz
//返回值:0,设置成功;1,无法设置.
u8 I2S2_SampleRate_Set(u32 samplerate)
{
u8 i=0;
u32 tempreg=0;
samplerate/=10;//缩小10倍
for(i=0;i<(sizeof(I2S_PSC_TBL)/10);i++)//看看改采样率是否可以支持
{
if(samplerate==I2S_PSC_TBL
[0])break;
}
__HAL_RCC_PLLI2S_DISABLE();; //先关闭PLLI2S
if(i==(sizeof(I2S_PSC_TBL)/10))return 1;//搜遍了也找不到
tempreg|=(u32)I2S_PSC_TBL[1]<<6; //设置PLLI2SN
tempreg|=(u32)I2S_PSC_TBL[2]<<28; //设置PLLI2SR
RCC->PLLI2SCFGR=tempreg; //设置I2SxCLK的频率(x=2)
RCC->CR|=1<<26; //开启I2S时钟
while((RCC->CR&1<<27)==0); //等待I2S时钟开启成功.
tempreg=I2S_PSC_TBL[3]<<0; //设置I2SDIV
tempreg|=I2S_PSC_TBL[4]<<8; //设置ODD位
tempreg|=1<<9; //使能MCKOE位,输出MCK
SPI2->I2SPR=tempreg; //设置I2SPR寄存器
return 0;
}
/*I2S 数据格式初始化 */
//std:I2S标准,00,飞利浦标准;01,MSB对齐标准(右对齐);10,LSB对齐标准(左对齐);11,PCM标准
//mode:I2S工作模式,00,从机发送;01,从机接收;10,主机发送;11,主机接收
//cpol:0,时钟低电平有效;1,时钟高电平有效
//datalen:数据长度,0,16位标准;1,16位扩展(frame=32bit);2,24位;3,32位
static void My_I2S2_Init(void)
{
I2S_HandleTypeDef HI2S;
__HAL_I2S_DISABLE(&HI2S);
HI2S.Instance = SPI2;
HI2S.Init.MCLKOutput =I2S_MCLKOUTPUT_ENABLE;
HI2S.Init.Mode = I2S_MODE_MASTER_TX; //I2S主机发送工作模式
HI2S.Init.Standard = I2S_STANDARD_PHILIPS; //I2S飞利浦标准
HI2S.Init.DataFormat = I2S_DATAFORMAT_16B; //数据长度16位
HI2S.Init.MCLKOutput = I2S_MCLKOUTPUT_DISABLE;
HI2S.Init.AudioFreq = I2S_AUDIOFREQ_16K;
HI2S.Init.CPOL = I2S_CPOL_HIGH;
HI2S.Init.ClockSource = I2S_CLOCK_PLL;
HI2S.Init.FullDuplexMode = I2S_FULLDUPLEXMODE_ENABLE;
HI2S.State=HAL_I2S_STATE_RESET;
if(HAL_I2S_GetState(&HI2S) == HAL_I2S_STATE_RESET)
{
HAL_I2S_MspInit(&HI2S);
}
HAL_I2S_Init(&HI2S);
__HAL_I2S_ENABLE(&HI2S); //SPI2 I2S EN 使能
}
//I2S2ext配置,用于全双工模式配置,需要时,在I2S2_Init之后调用
//std:I2S标准,00,飞利浦标准;01,MSB对齐标准(右对齐);10,LSB对齐标准(左对齐);11,PCM标准
//mode:I2S工作模式,00,从机发送;01,从机接收;I2S2ext仅用于从机模式
//cpol:0,时钟低电平有效;1,时钟高电平有效
//datalen:数据长度,0,16位标准;1,16位扩展(frame=32bit);2,24位;3,32位.
static void My_I2S2ext_Init(void)
{
I2S_HandleTypeDef HI2Sext;
HI2Sext.Instance=I2S2ext;
HI2Sext.Init.Mode=I2S_MODE_SLAVE_RX; //I2S从机接受工作模式
HI2Sext.Init.Standard = I2S_STANDARD_PHILIPS; //I2S飞利浦标准
HI2Sext.Init.DataFormat = I2S_DATAFORMAT_16B; //数据长度16位
HI2Sext.Init.MCLKOutput = I2S_MCLKOUTPUT_DISABLE;
HI2Sext.Init.AudioFreq = I2S_AUDIOFREQ_16K;
HI2Sext.Init.CPOL = I2S_CPOL_HIGH;
HI2Sext.Init.ClockSource = I2S_CLOCK_PLL;
HI2Sext.Init.FullDuplexMode = I2S_FULLDUPLEXMODE_ENABLE;
HAL_I2S_Init1(&HI2Sext);
I2S2ext->CR2= SPI_CR2_RXDMAEN; //SPI2 Tx DMA请求使能
I2S2ext->I2SCFGR|=SPI_I2SCFGR_I2SE; //SPI2 I2S EN 使能.
}
//I2S2 TX DMA配置
//设置为双缓冲模式,并开启DMA传输完成中断
//buf0:M0AR地址.
//buf1:M1AR地址.
//num:每次传输数据量
void I2S2_TX_DMA_Init(u8* buf0, u8 *buf1, u16 num)
{
DMA_HandleTypeDef dma1;
DMA_TypeDef DMA_Type1;
__HAL_RCC_DMA1_CLK_ENABLE(); //DMA1时钟使能
dma1.Instance=DMA1_Stream4;
while(dma1.Instance->CR&0X01); //等待DMA1_Stream4可配置
DMA_Type1.HIFCR|=0X3D<<6*0 ; //清空通道4上所有中断标志
dma1.Instance->PAR=(u32)&SPI2->DR; //外设地址为:SPI2->DR
dma1.Instance->M0AR=(u32)buf0; //暂不设置
dma1.Instance->M1AR=(u32)buf1; //暂不设置
dma1.Instance->NDTR=num; //暂时设置长度为1
dma1.Init.Direction=DMA_MEMORY_TO_PERIPH; //存储器到外设模式
dma1.Init.Mode=DMA_CIRCULAR; //循环模式
dma1.Init.PeriphInc=DMA_PINC_DISABLE; //外设非增量模式
dma1.Init.MemInc=DMA_MINC_ENABLE; //存储器增量模式
dma1.Init.PeriphDataAlignment=DMA_PDATAALIGN_HALFWORD; //外设数据长度:16位
dma1.Init.MemDataAlignment=DMA_MDATAALIGN_HALFWORD; //存储器数据长度:16位
dma1.Init.Priority=DMA_PRIORITY_HIGH; //高优先级
dma1.Instance->CR|=1<<18; //双缓冲模式
dma1.Instance->CR|=0<<21; //外设突发单次传输
dma1.Instance->CR|=0<<23; //存储器突发单次传输
dma1.Init.Channel=DMA_CHANNEL_0; //选择通道0 SPI2_TX通道
dma1.Init.FIFOMode=DMA_FIFOMODE_DISABLE; //不使用FIFO模式
dma1.Instance->FCR&=~(3<<0); //无FIFO 设置
HAL_DMA_DeInit(&dma1); //先清除以前的设置
HAL_DMA_Init(&dma1); //初始化DMA
HAL_DMAEx_MultiBufferStart(&dma1,(u32)buf0,(u32)&SPI2->DR,(u32)buf1,num);//开启双缓冲
__HAL_DMA_DISABLE(&dma1); //先关闭DMA
delay_us(10); //10us延时
__HAL_DMA_ENABLE_IT(&dma1,DMA_IT_TC); //开启传输完成中断
__HAL_DMA_CLEAR_FLAG(&dma1, DMA_FLAG_TCIF0_4); //清除DMA传输完成中断标志位
HAL_NVIC_SetPriorityGrouping ( NVIC_PRIORITYGROUP_2);
HAL_NVIC_SetPriority( DMA1_Stream4_IRQn, 0, 0);
//抢占0,响应优先级0,组2
//NVIC_PreemptionPriority:抢占优先级
//NVIC_SubPriority :响应优先级
//NVIC_Channel :中断编号
//NVIC_Group :中断分组 0~4
HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn);
}
//I2S2ext RX DMA配置
//设置为双缓冲模式,并开启DMA传输完成中断a
//buf0:M0AR地址.
//buf1:M1AR地址.
//num:每次传输数据量
void I2S2ext_RX_DMA_Init(u8* buf0,u8 *buf1,u16 num)
{
DMA_HandleTypeDef dma2;
DMA_TypeDef DMA_Type2;
__HAL_RCC_DMA1_CLK_ENABLE(); //DMA1时钟使能
dma2.Instance=DMA1_Stream3;
while(dma2.Instance->CR&0X01); //等待DMA1_Stream4可配置
DMA_Type2.HIFCR|=0X3D<<22 ; //清空通道3上所有中断标志
dma2.Instance->PAR=(u32)&I2S2ext->DR; //外设地址为:I2S2ext->DR
dma2.Instance->M0AR=(u32)buf0; //暂不设置
dma2.Instance->M1AR=(u32)buf1; //暂不设置
dma2.Instance->NDTR=num; //暂时DMA传输设置长度
dma2.Init.Direction=DMA_PERIPH_TO_MEMORY; //存储器到外设模式
dma2.Init.Mode=DMA_CIRCULAR; //循环模式
dma2.Init.PeriphInc=DMA_PINC_DISABLE; //外设非增量模式
dma2.Init.MemInc=DMA_MINC_ENABLE; //存储器增量模式
dma2.Init.PeriphDataAlignment=DMA_PDATAALIGN_HALFWORD; //外设数据长度:16位
dma2.Init.MemDataAlignment=DMA_MDATAALIGN_HALFWORD; //存储器数据长度:16位
dma2.Init.Priority=DMA_PRIORITY_MEDIUM; //中等优先级
dma2.Instance->CR|=1<<18; //双缓冲模式
dma2.Instance->CR|=0<<21; //外设突发单次传输
dma2.Instance->CR|=0<<23; //存储器突发单次传输
dma2.Init.Channel=DMA_CHANNEL_3; //选择通道3 I2S2ext_RX通道
dma2.Init.FIFOMode=DMA_FIFOMODE_DISABLE; //不使用FIFO模式
dma2.Instance->FCR&=~(3<<0); //无FIFO 设置
HAL_DMA_DeInit(&dma2); //先清除以前的设置
HAL_DMA_Init(&dma2); //初始化DMA
HAL_DMAEx_MultiBufferStart(&dma2,(u32)buf0,(u32)&I2S2ext->DR,(u32)buf1,num);//开启双缓冲
__HAL_DMA_DISABLE(&dma2); //先关闭DMA
delay_us(10); //10us延时
__HAL_DMA_ENABLE_IT(&dma2,DMA_IT_TC); //开启传输完成中断
__HAL_DMA_CLEAR_FLAG(&dma2,DMA_FLAG_TCIF3_7); //清除DMA传输完成中断标志位 ?
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2);
HAL_NVIC_SetPriority( DMA1_Stream3_IRQn, 0, 1);
//抢占0,响应优先级1,组2
//NVIC_PreemptionPriority:抢占优先级
//NVIC_SubPriority :响应优先级
//NVIC_Channel :中断编号
//NVIC_Group :中断分组 0~4
HAL_NVIC_EnableIRQ(DMA1_Stream3_IRQn);
}
//I2S DMA回调函数指针
void (i2s_tx_callback)(void); //TX回调函数
void (i2s_rx_callback)(void); //RX回调函数
vu8 i2splaybuf=0;
vu8 i2ssavebuf=0;
#define BUF_NUM 10
u8 i2soutbuf[BUF_NUM][64]={0};
u8 i2semptybuf[64]={0};
void i2s_tx_callback(void)
{
if(i2splaybuf==i2ssavebuf)
{
if(DMA1_Stream4->CR&(1<<19))
{
DMA1_Stream4->M0AR=(u32)i2semptybuf;
}
else
{
DMA1_Stream4->M1AR=(u32)i2semptybuf;
}
}else
{
i2splaybuf++;
if(i2splaybuf>(BUF_NUM-1))i2splaybuf=0;
if(DMA1_Stream4->CR&(1<<19))
{
DMA1_Stream4->M0AR=(u32)&i2soutbuf[i2splaybuf][0];//指向下一个buf
}
else
{
DMA1_Stream4->M1AR=(u32)&i2soutbuf[i2splaybuf][0];//指向下一个buf
}
}
}
vu8 i2srecReadbuf=0;
vu8 i2srecsavebuf=0;
#define REC_BUF_NUM 10
vs16 i2sinbuf[REC_BUF_NUM][64]={0};
void i2s_rx_callback(void)
{
i2srecsavebuf++;
if(i2srecsavebuf>(REC_BUF_NUM-1))i2srecsavebuf=0;
if(DMA1_Stream3->CR&(1<<19))
{
DMA1_Stream3->M0AR=(u32)&i2sinbuf[i2srecsavebuf][0];//指向下一个buf
}else
{
DMA1_Stream3->M1AR=(u32)&i2sinbuf[i2srecsavebuf][0];//指向下一个buf
}
}
//DMA1_Stream4中断服务函数
void DMA1_Stream4_IRQHandler(void)
{
if(DMA1->HISR&(1<<5)) //DMA1_Steam4,传输完成标志
{
DMA1->HIFCR|=1<<5; //清除传输完成中断
i2s_tx_callback(); //执行回调函数,读取数据等操作在这里面处理
}
}
//DMA1_Stream3中断服务函数
void DMA1_Stream3_IRQHandler(void)
{
if(DMA1->LISR&(1<<27)) //DMA1_Steam3,传输完成标志
{
DMA1->LIFCR|=1<<27; //清除传输完成中断
i2s_rx_callback(); //执行回调函数,读取数据等操作在这里面处理
}
}
//I2S开始播放
void I2S_Play_Start(void)
{
DMA1_Stream4->CR|=1<<0; //开启DMA TX传输
}
//关闭I2S播放
void I2S_Play_Stop(void)
{
DMA1_Stream4->CR&=~(1<<0); //结束播放
}
//I2S开始录音
void I2S_Rec_Start(void)
{
DMA1_Stream3->CR|=1<<0; //开启DMA RX传输
}
//关闭I2S录音
void I2S_Rec_Stop(void)
{
DMA1_Stream3->CR&=~(1<<0); //结束录音
}
int main(void)
{
Stm32_Clock_Init(384,25,2,8); //设置时钟,192Mhz
delay_init(192); //初始化延时函数
My_I2S2_Init();
//My_I2S2ext_Init();
I2S2_SampleRate_Set(16000);
//I2S2_TX_DMA_Init((u8 *)&i2soutbuf[0][0],(u8 *)&i2soutbuf[1][0],32);
//I2S_Play_Start();
//I2S2ext_RX_DMA_Init((u8 *)&i2sinbuf[0][0],(u8 *)&i2sinbuf[1][0],32);
//I2S_Rec_Start();
while(1)
{
};
}
一周热门 更多>