大家帮我看一下,下面配置是否有问题,时钟都是对的,但是无法接收到音频数据,求解!
//V1.1 20160129
//新增SAIB_Init、SAIA_RX_DMA_Init、SAI_Rec_Start和SAI_Rec_Stop等函数
//////////////////////////////////////////////////////////////////////////////////
extern u8 sai1arecbuf1[SAI_RX_DMA_BUF_SIZE*2]; //DMA接收缓存1
extern u8 sai1arecbuf2[SAI_RX_DMA_BUF_SIZE*2]; //DMA接收缓存2
extern u8 sai1brecbuf1[SAI_RX_DMA_BUF_SIZE*2]; //DMA接收缓存1
extern u8 sai1brecbuf2[SAI_RX_DMA_BUF_SIZE*2]; //DMA接收缓存2
SAI_HandleTypeDef SAI1A_Handler; //SAI1 Block A句柄
SAI_HandleTypeDef SAI1B_Handler; //SAI1 Block B句柄
DMA_HandleTypeDef SAI1A_RXDMA_Handler; //DMA接收句柄
DMA_HandleTypeDef SAI1B_RXDMA_Handler; //DMA接收句柄
extern void rec_sai1a_dma_rx_callback(void);
extern void rec_sai1b_dma_rx_callback(void);
//SAI1初始化
void marster_sai1_init(void) //初始化sai1
{
RCC_PeriphCLKInitTypeDef RCC_PeriphCLKInitStruct;
/* Configure PLLSAI prescalers */
/* PLL2SAI_VCO: VCO_429M
SAI_CLK(first level) = PLLSAI_VCO/PLLSAIP = 344/7 = 11.289 Mhz */
RCC_PeriphCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SAI1;
RCC_PeriphCLKInitStruct.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLL2;
RCC_PeriphCLKInitStruct.PLL2.PLL2P = 7;
RCC_PeriphCLKInitStruct.PLL2.PLL2Q = 1;
RCC_PeriphCLKInitStruct.PLL2.PLL2R = 1;
RCC_PeriphCLKInitStruct.PLL2.PLL2N = 344;
RCC_PeriphCLKInitStruct.PLL2.PLL2M = 25;
HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphCLKInitStruct);
SAIA1_RX_DMA_Init(sai1arecbuf1,sai1arecbuf2,SAI_RX_DMA_BUF_SIZE,1); //配置TX DMA,16位
SAIB1_RX_DMA_Init(sai1brecbuf1,sai1brecbuf2,SAI_RX_DMA_BUF_SIZE,1); //配置RX DMA
SAIB1_Init(3,1,4); //SAI1 Block B从模式接收,16位
SAIA1_Init(1,1,4); //SAI1 Block; A,主发送,16位数据
sai1a_rx_callback = rec_sai1a_dma_rx_callback; //回调函数指wav_sai_dma_callback
sai1b_rx_callback = rec_sai1b_dma_rx_callback; //回调函数指wav_i2s_dma_callback
}
//SAI Block A初始化,I2S,飞利浦标准
//mode:工作模式,可以设置:SAI_MODEMASTER_TX/SAI_MODEMASTER_RX/SAI_MODESLAVE_TX/SAI_MODESLAVE_RX
//cpol:数据在时钟的上升/下降沿选通,可以设置:SAI_CLOCKSTROBING_FALLINGEDGE/SAI_CLOCKSTROBING_RISINGEDGE
//datalen:数据大小,可以设置:SAI_DATASIZE_8/10/16/20/24/32
void SAIA1_Init(u32 mode,u32 cpol,u32 datalen)
{
HAL_SAI_DeInit(&SAI1A_Handler); //清除以前的配置
SAI1A_Handler.Instance=SAI1_Block_A; //SAI1 Bock A
SAI1A_Handler.Init.AudioMode=SAI_MODEMASTER_RX; //设置SAI1工作模式
SAI1A_Handler.Init.Synchro=SAI_ASYNCHRONOUS; //音频模块异步
SAI1A_Handler.Init.OutputDrive=SAI_OUTPUTDRIVE_ENABLE; //立即驱动音频模块输出
SAI1A_Handler.Init.NoDivider=SAI_MASTERDIVIDER_ENABLE; //使能主时钟分频器(MCKDIV)
SAI1A_Handler.Init.FIFOThreshold=SAI_FIFOTHRESHOLD_1QF; //设置FIFO阈值,1/4 FIFO
SAI1A_Handler.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_16K;
SAI1A_Handler.Init.MonoStereoMode=SAI_STEREOMODE; //立体声模式
SAI1A_Handler.Init.Protocol=SAI_FREE_PROTOCOL; //设置SAI1协议为:自由协议(支持I2S/LSB/MSB/TDM/PCM/DSP等协议)
SAI1A_Handler.Init.DataSize=SAI_DATASIZE_16; //设置数据大小
SAI1A_Handler.Init.FirstBit=SAI_FIRSTBIT_MSB; //数据MSB位优先
SAI1A_Handler.Init.ClockStrobing=SAI_CLOCKSTROBING_RISINGEDGE; //数据在时钟的上升/下降沿选通
//帧设置
SAI1A_Handler.FrameInit.FrameLength=32; //设置帧长度为32,左通道16个SCK,右通道16个SCK.
SAI1A_Handler.FrameInit.ActiveFrameLength=16; //设置帧同步有效电平长度,在I2S模式下=1/2帧长.
SAI1A_Handler.FrameInit.FSDefinition=SAI_FS_CHANNEL_IDENTIFICATION;//FS信号为SOF信号+通道识别信号
SAI1A_Handler.FrameInit.FSPolarity=SAI_FS_ACTIVE_LOW; //FS低电平有效(下降沿)
SAI1A_Handler.FrameInit.FSOffset=SAI_FS_BEFOREFIRSTBIT; //在slot0的第一位的前一位使能FS,以匹配飞利浦标准
//SLOT设置
SAI1A_Handler.SlotInit.FirstBitOffset=0; //slot偏移(FBOFF)为0
SAI1A_Handler.SlotInit.SlotSize=SAI_SLOTSIZE_16B; //slot大小为16位
SAI1A_Handler.SlotInit.SlotNumber=2; //slot数为2个
SAI1A_Handler.SlotInit.SlotActive=SAI_SLOTACTIVE_0|SAI_SLOTACTIVE_1;//使能slot0和slot1
HAL_SAI_Init(&SAI1A_Handler); //初始化SAI
SAIA1_DMA_Enable();
__HAL_SAI_ENABLE(&SAI1A_Handler); //使能SAI
}
//SAI Block B初始化,I2S,飞利浦标准
//mode:工作模式,可以设置:SAI_MODEMASTER_TX/SAI_MODEMASTER_RX/SAI_MODESLAVE_TX/SAI_MODESLAVE_RX
//cpol:数据在时钟的上升/下降沿选通,可以设置:SAI_CLOCKSTROBING_FALLINGEDGE/SAI_CLOCKSTROBING_RISINGEDGE
//datalen:数据大小,可以设置:SAI_DATASIZE_8/10/16/20/24/32
void SAIB1_Init(u32 mode,u32 cpol,u32 datalen)
{
HAL_SAI_DeInit(&SAI1B_Handler); //清除以前的配置
SAI1B_Handler.Instance=SAI1_Block_B; //SAI1 Bock B
SAI1B_Handler.Init.AudioMode=SAI_MODESLAVE_RX; //设置SAI1工作模式
SAI1B_Handler.Init.Synchro=SAI_SYNCHRONOUS; //音频模块同步
SAI1B_Handler.Init.OutputDrive=SAI_OUTPUTDRIVE_ENABLE; //立即驱动音频模块输出
SAI1B_Handler.Init.NoDivider=SAI_MASTERDIVIDER_ENABLE; //使能主时钟分频器(MCKDIV)
SAI1B_Handler.Init.FIFOThreshold=SAI_FIFOTHRESHOLD_1QF; //设置FIFO阈值,1/4 FIFO
SAI1B_Handler.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_16K;
SAI1B_Handler.Init.MonoStereoMode=SAI_STEREOMODE; //立体声模式
SAI1B_Handler.Init.Protocol=SAI_FREE_PROTOCOL; //设置SAI1协议为:自由协议(支持I2S/LSB/MSB/TDM/PCM/DSP等协议)
SAI1B_Handler.Init.DataSize=SAI_DATASIZE_16; //设置数据大小
SAI1B_Handler.Init.FirstBit=SAI_FIRSTBIT_MSB; //数据MSB位优先
SAI1B_Handler.Init.ClockStrobing=SAI_CLOCKSTROBING_RISINGEDGE;//数据在时钟的上升/下降沿选通
//帧设置
SAI1B_Handler.FrameInit.FrameLength=32; //设置帧长度为32,左通道16个SCK,右通道16个SCK.
SAI1B_Handler.FrameInit.ActiveFrameLength=16; //设置帧同步有效电平长度,在I2S模式下=1/2帧长.
SAI1B_Handler.FrameInit.FSDefinition=SAI_FS_CHANNEL_IDENTIFICATION;//FS信号为SOF信号+通道识别信号
SAI1B_Handler.FrameInit.FSPolarity=SAI_FS_ACTIVE_LOW; //FS低电平有效(下降沿)
SAI1B_Handler.FrameInit.FSOffset=SAI_FS_BEFOREFIRSTBIT; //在slot0的第一位的前一位使能FS,以匹配飞利浦标准
//SLOT设置
SAI1B_Handler.SlotInit.FirstBitOffset=0; //slot偏移(FBOFF)为0
SAI1B_Handler.SlotInit.SlotSize=SAI_SLOTSIZE_16B; //slot大小为16位
SAI1B_Handler.SlotInit.SlotNumber=2; //slot数为2个
SAI1B_Handler.SlotInit.SlotActive=SAI_SLOTACTIVE_0|SAI_SLOTACTIVE_1;//使能slot0和slot1
HAL_SAI_Init(&SAI1B_Handler);
SAIB1_DMA_Enable(); //使能SAI的DMA功能
__HAL_SAI_ENABLE(&SAI1B_Handler); //使能SAI
}
//SAI底层驱动,引脚配置,时钟使能
//此函数会被HAL_SAI_Init()调用
//hsdram:SAI句柄
void HAL_SAI_MspInit(SAI_HandleTypeDef *hsai)
{
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_SAI1_CLK_ENABLE(); //使能SAI1时钟
__HAL_RCC_GPIOE_CLK_ENABLE(); //使能GPIOE时钟
//初始化PE2,3,4,5,6
GPIO_Initure.Pin=GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6;
GPIO_Initure.Mode=GPIO_MODE_AF_PP; //推挽复用
GPIO_Initure.Pull=GPIO_NOPULL; //上拉
GPIO_Initure.Speed=GPIO_SPEED_FREQ_VERY_HIGH; //高速
GPIO_Initure.Alternate=GPIO_AF6_SAI1; //复用为SAI
HAL_GPIO_Init(GPIOE,&GPIO_Initure); //初始化
}
//SAI Block A采样率设置
//采样率计算公式:
//MCKDIV!=0: Fs=SAI_CK_x/[512*MCKDIV]
//MCKDIV==0: Fs=SAI_CK_x/256
//SAI_CK_x=(HSE/DIVM2)*PLLSAIN/PLLSAIQ/(PLLSAIDivQ+1)
//一般HSE=25Mhz
//pllm:在Stm32_Clock_Init设置的时候确定,一般是25
//PLLSAIN:一般是50~432
//PLLSAIQ:2~15
//PLLSAIDivQ:1~32
//MCKDIV:0~15
//SAI A分频系数表@pllm=25,HSE=25Mhz,即vco输入频率为1Mhz
const u16 SAI_PSC_TBL[][5]=
{
{800 ,344,7,25,12}, //8Khz采样率
{1102,429,38,25,2}, //11.025Khz采样率
{1600,344,7,25,6}, //16Khz采样率
{2205,429,38,25,1}, //22.05Khz采样率
{3200,344,7,25,3}, //32Khz采样率
{4410,429,38,25,0}, //44.1Khz采样率
{4800,344,7,25,2}, //48Khz采样率
{8820,271,38,25,1}, //88.2Khz采样率
{9600,344,7,25,1}, //96Khz采样率
{17640,271,38,25,0}, //176.4Khz采样率
{19200,344,7,25,0}, //192Khz采样率
};
//开启SAI的DMA功能,HAL库没有提供此函数
//因此我们需要自己操作寄存器编写一个
void SAIA1_DMA_Enable(void)
{
u32 tempreg=0;
tempreg=SAI1_Block_A->CR1; //先读出以前的设置
tempreg|=1<<17; //使能DMA
SAI1_Block_A->CR1=tempreg; //写入CR1寄存器中
}
//开启SAIB的DMA功能,HAL库没有提供此函数
//因此我们需要自己操作寄存器编写一个
void SAIB1_DMA_Enable(void)
{
u32 tempreg=0;
tempreg=SAI1_Block_B->CR1; //先读出以前的设置
tempreg|=1<<17; //使能DMA
SAI1_Block_B->CR1=tempreg; //写入CR1寄存器中
}
//SAIA TX DMA配置
//设置为双缓冲模式,并开启DMA传输完成中断
//buf0:M0AR地址.
//buf1:M1AR地址.
//num:每次传输数据量
//width:位宽(存储器和外设,同时设置),0,8位;1,16位;2,32位;
void SAIA1_RX_DMA_Init(u8* buf0,u8 *buf1,u16 num,u8 width)
{
u32 memwidth=0,perwidth=0; //外设和存储器位宽
switch(width)
{
case 0: //8位
memwidth=DMA_MDATAALIGN_BYTE;
perwidth=DMA_PDATAALIGN_BYTE;
break;
case 1: //16位
memwidth=DMA_MDATAALIGN_HALFWORD;
perwidth=DMA_PDATAALIGN_HALFWORD;
break;
case 2: //32位
memwidth=DMA_MDATAALIGN_WORD;
perwidth=DMA_PDATAALIGN_WORD;
break;
}
__HAL_RCC_DMA2_CLK_ENABLE(); //使能DMA2时钟
SAI1A_RXDMA_Handler.Init.Request= DMA_REQUEST_SAI1_A;
SAI1A_RXDMA_Handler.Instance=DMA2_Stream3; //DMA2数据流3
SAI1A_RXDMA_Handler.Init.Direction=DMA_PERIPH_TO_MEMORY; //存储器到外设模式
SAI1A_RXDMA_Handler.Init.PeriphInc=DMA_PINC_DISABLE; //外设非增量模式
SAI1A_RXDMA_Handler.Init.MemInc=DMA_MINC_ENABLE; //存储器增量模式
SAI1A_RXDMA_Handler.Init.PeriphDataAlignment=DMA_MDATAALIGN_HALFWORD;//外设数据长度:16/32位
SAI1A_RXDMA_Handler.Init.MemDataAlignment=DMA_PDATAALIGN_HALFWORD;//存储器数据长度:16/32位
SAI1A_RXDMA_Handler.Init.Mode=DMA_CIRCULAR; //使用循环模式
SAI1A_RXDMA_Handler.Init.Priority=DMA_PRIORITY_HIGH; //高优先级
SAI1A_RXDMA_Handler.Init.FIFOMode=DMA_FIFOMODE_DISABLE; //不使用FIFO
SAI1A_RXDMA_Handler.Init.FIFOThreshold= DMA_FIFO_THRESHOLD_FULL;
SAI1A_RXDMA_Handler.Init.MemBurst=DMA_MBURST_SINGLE; //存储器单次突发传输
SAI1A_RXDMA_Handler.Init.PeriphBurst=DMA_PBURST_SINGLE; //外设突发单次传输
__HAL_LINKDMA(&SAI1A_Handler,hdmarx,SAI1A_RXDMA_Handler); //将DMA与SAI联系起来
HAL_DMA_DeInit(&SAI1A_RXDMA_Handler); //先清除以前的设置
HAL_DMA_Init(&SAI1A_RXDMA_Handler); //初始化DMA
HAL_DMAEx_MultiBufferStart(&SAI1A_RXDMA_Handler,(u32)buf0,(u32)&SAI1_Block_A->DR,(u32)buf1,num);//开启双缓冲
__HAL_DMA_DISABLE(&SAI1A_RXDMA_Handler); //先关闭DMA
delay_us(10); //10us延时,防止-O2优化出问题
__HAL_DMA_ENABLE_IT(&SAI1A_RXDMA_Handler,DMA_IT_TC); //开启传输完成中断
HAL_NVIC_SetPriority(DMA2_Stream3_IRQn,1,0); //DMA中断优先级
HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn);
}
//SAIA TX DMA配置
//设置为双缓冲模式,并开启DMA传输完成中断
//buf0:M0AR地址.
//buf1:M1AR地址.
//num:每次传输数据量
//width:位宽(存储器和外设,同时设置),0,8位;1,16位;2,32位;
void SAIB1_RX_DMA_Init(u8* buf0,u8 *buf1,u16 num,u8 width)
{
u32 memwidth=0,perwidth=0; //外设和存储器位宽
switch(width)
{
case 0: //8位
memwidth=DMA_MDATAALIGN_BYTE;
perwidth=DMA_PDATAALIGN_BYTE;
break;
case 1: //16位
memwidth=DMA_MDATAALIGN_HALFWORD;
perwidth=DMA_PDATAALIGN_HALFWORD;
break;
case 2: //32位
memwidth=DMA_MDATAALIGN_WORD;
perwidth=DMA_PDATAALIGN_WORD;
break;
}
__HAL_RCC_DMA2_CLK_ENABLE(); //使能DMA2时钟
__HAL_LINKDMA(&SAI1B_Handler,hdmarx,SAI1B_RXDMA_Handler); //将DMA与SAI联系起来
SAI1A_RXDMA_Handler.Init.Request= DMA_REQUEST_SAI1_B;
SAI1B_RXDMA_Handler.Instance=DMA2_Stream5; //DMA2数据流5
SAI1B_RXDMA_Handler.Init.Direction=DMA_PERIPH_TO_MEMORY; //外设到存储器模式
SAI1B_RXDMA_Handler.Init.PeriphInc=DMA_PINC_DISABLE; //外设非增量模式
SAI1B_RXDMA_Handler.Init.MemInc=DMA_MINC_ENABLE; //存储器增量模式
SAI1B_RXDMA_Handler.Init.PeriphDataAlignment=DMA_MDATAALIGN_HALFWORD;//外设数据长度:16/32位
SAI1B_RXDMA_Handler.Init.MemDataAlignment=DMA_PDATAALIGN_HALFWORD; //存储器数据长度:16/32位
SAI1B_RXDMA_Handler.Init.Mode=DMA_CIRCULAR; //使用循环模式
SAI1B_RXDMA_Handler.Init.Priority=DMA_PRIORITY_MEDIUM; //中等优先级
SAI1B_RXDMA_Handler.Init.FIFOMode=DMA_FIFOMODE_DISABLE; //不使用FIFO
SAI1B_RXDMA_Handler.Init.MemBurst=DMA_MBURST_SINGLE; //存储器单次突发传输
SAI1B_RXDMA_Handler.Init.PeriphBurst=DMA_PBURST_SINGLE; //外设突发单次传输
HAL_DMA_DeInit(&SAI1B_RXDMA_Handler); //先清除以前的设置
HAL_DMA_Init(&SAI1B_RXDMA_Handler); //初始化DMA
HAL_DMAEx_MultiBufferStart(&SAI1B_RXDMA_Handler,(u32)&SAI1_Block_B->DR,(u32)buf0,(u32)buf1,num);//开启双缓冲
__HAL_DMA_DISABLE(&SAI1B_RXDMA_Handler); //先关闭接收DMA
delay_us(10); //10us延时,防止-O2优化出问题
__HAL_DMA_CLEAR_FLAG(&SAI1B_RXDMA_Handler,DMA_FLAG_TCIF1_5); //清除DMA传输完成中断标志位
__HAL_DMA_ENABLE_IT(&SAI1B_RXDMA_Handler,DMA_IT_TC); //开启传输完成中断
HAL_NVIC_SetPriority(DMA2_Stream5_IRQn,1,1); //DMA中断优先级
HAL_NVIC_EnableIRQ(DMA2_Stream5_IRQn);
}
//SAI DMA回调函数指针
void (*sai1a_rx_callback)(void); //TX回调函数
void (*sai1b_rx_callback)(void); //RX回调函数
//DMA2_Stream3中断服务函数
void DMA2_Stream3_IRQHandler(void)
{
if(__HAL_DMA_GET_FLAG(&SAI1A_RXDMA_Handler,DMA_FLAG_TCIF3_7)!=RESET) //DMA传输完成
{
__HAL_DMA_CLEAR_FLAG(&SAI1A_RXDMA_Handler,DMA_FLAG_TCIF3_7); //清除DMA传输完成中断标志位
if(sai1a_rx_callback!=NULL)sai1a_rx_callback(); //执行回调函数,读取数据等操作在这里面处理
}
}
//DMA2_Stream5中断服务函数
void DMA2_Stream5_IRQHandler(void)
{
if(__HAL_DMA_GET_FLAG(&SAI1B_RXDMA_Handler,DMA_FLAG_TCIF1_5)!=RESET) //DMA传输完成
{
__HAL_DMA_CLEAR_FLAG(&SAI1B_RXDMA_Handler,DMA_FLAG_TCIF1_5); //清除DMA传输完成中断标志位
if(sai1b_rx_callback!=NULL)sai1b_rx_callback(); //执行回调函数,读取数据等操作在这里面处理
}
}
//SAI开始播放
void SAIA1_Rec_Start(void)
{
__HAL_DMA_ENABLE(&SAI1A_RXDMA_Handler);//开启DMA TX传输
}
//关闭I2S播放
void SAIA1_Rec_Stop(void)
{
__HAL_DMA_DISABLE(&SAI1A_RXDMA_Handler); //结束播放
}
//SAI开始录音
void SAIB1_Rec_Start(void)
{
__HAL_DMA_ENABLE(&SAI1B_RXDMA_Handler);//开启DMA RX传输
}
//关闭SAI录音
void SAIB1_Rec_Stop(void)
{
__HAL_DMA_DISABLE(&SAI1B_RXDMA_Handler);//结束录音
}
一周热门 更多>