野火电子论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 11153|回复: 1

STM32H7 SAI4无法正常工作

[复制链接]
发表于 2018-9-29 18:33:41 | 显示全部楼层 |阅读模式
大家有没有STM32H743的SAI4的例子啊
/**********************SAI4配置信息******************************/
//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 SAI4A_Init(u32 mode,u32 cpol,u32 datalen)
{
    HAL_SAI_DeInit(&SAI4A_Handler);                          //清除以前的配置
    SAI4A_Handler.Instance=SAI4_Block_A;                     //SAI4 Bock A
    SAI4A_Handler.Init.AudioMode=SAI_MODESLAVE_RX;           //设置SAI4工作模式
    SAI4A_Handler.Init.Synchro=SAI_SYNCHRONOUS_EXT_SAI1;     //音频模块异步
    SAI4A_Handler.Init.OutputDrive=SAI_OUTPUTDRIVE_ENABLE;   //立即驱动音频模块输出
    SAI4A_Handler.Init.NoDivider=SAI_MASTERDIVIDER_ENABLE;   //使能主时钟分频器(MCKDIV)
          SAI4A_Handler.Init.FIFOThreshold=SAI_FIFOTHRESHOLD_1QF;  //设置FIFO阈值,1/4 FIFO
    SAI4A_Handler.Init.MonoStereoMode=SAI_STEREOMODE;        //立体声模式
    SAI4A_Handler.Init.Protocol=SAI_FREE_PROTOCOL;           //设置SAI1协议为:自由协议(支持I2S/LSB/MSB/TDM/PCM/DSP等协议)
    SAI4A_Handler.Init.DataSize=SAI_DATASIZE_16;                     //设置数据大小
    SAI4A_Handler.Init.FirstBit=SAI_FIRSTBIT_MSB;            //数据MSB位优先
    SAI4A_Handler.Init.ClockStrobing=SAI_CLOCKSTROBING_RISINGEDGE;                   //数据在时钟的上升/下降沿选通
    //帧设置
    SAI4A_Handler.FrameInit.FrameLength=32;                  //设置帧长度为32,左通道16个SCK,右通道16个SCK.
    SAI4A_Handler.FrameInit.ActiveFrameLength=16;            //设置帧同步有效电平长度,在I2S模式下=1/2帧长.
    SAI4A_Handler.FrameInit.FSDefinition=SAI_FS_CHANNEL_IDENTIFICATION;//FS信号为SOF信号+通道识别信号
    SAI4A_Handler.FrameInit.FSPolarity=SAI_FS_ACTIVE_LOW;    //FS低电平有效(下降沿)
    SAI4A_Handler.FrameInit.FSOffset=SAI_FS_BEFOREFIRSTBIT;  //在slot0的第一位的前一位使能FS,以匹配飞利浦标准       

    //SLOT设置
    SAI4A_Handler.SlotInit.FirstBitOffset=0;                 //slot偏移(FBOFF)为0
    SAI4A_Handler.SlotInit.SlotSize=SAI_SLOTSIZE_16B;        //slot大小为16位
    SAI4A_Handler.SlotInit.SlotNumber=2;                     //slot数为2个   
    SAI4A_Handler.SlotInit.SlotActive=SAI_SLOTACTIVE_0|SAI_SLOTACTIVE_1;//使能slot0和slot1

    HAL_SAI_Init(&SAI4A_Handler);                            //初始化SAI
                SAI4A_DMA_Enable();                                      //使能SAI的DMA功能
                __HAL_SAI_ENABLE(&SAI4A_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 SAI4B_Init(u32 mode,u32 cpol,u32 datalen)
{
    HAL_SAI_DeInit(&SAI4B_Handler);                         //清除以前的配置
    SAI4B_Handler.Instance=SAI4_Block_B;                    //SAI4 Bock B
    SAI4B_Handler.Init.AudioMode=SAI_MODESLAVE_RX;          //设置SAI4工作模式
    SAI4B_Handler.Init.Synchro=SAI_SYNCHRONOUS_EXT_SAI1;    //音频模块同步
    SAI4B_Handler.Init.OutputDrive=SAI_OUTPUTDRIVE_ENABLE;  //立即驱动音频模块输出
    SAI4B_Handler.Init.NoDivider=SAI_MASTERDIVIDER_ENABLE;  //使能主时钟分频器(MCKDIV)
    SAI4B_Handler.Init.FIFOThreshold=SAI_FIFOTHRESHOLD_1QF; //设置FIFO阈值,1/4 FIFO            
          SAI4B_Handler.Init.MonoStereoMode=SAI_STEREOMODE;       //立体声模式
    SAI4B_Handler.Init.Protocol=SAI_FREE_PROTOCOL;          //设置SAI1协议为:自由协议(支持I2S/LSB/MSB/TDM/PCM/DSP等协议)
    SAI4B_Handler.Init.DataSize=SAI_DATASIZE_16;            //设置数据大小
    SAI4B_Handler.Init.FirstBit=SAI_FIRSTBIT_MSB;           //数据MSB位优先
    SAI4B_Handler.Init.ClockStrobing=SAI_CLOCKSTROBING_RISINGEDGE;//数据在时钟的上升/下降沿选通

    //帧设置
    SAI4B_Handler.FrameInit.FrameLength=32;                 //设置帧长度为32,左通道16个SCK,右通道16个SCK.
    SAI4B_Handler.FrameInit.ActiveFrameLength=16;           //设置帧同步有效电平长度,在I2S模式下=1/2帧长.
    SAI4B_Handler.FrameInit.FSDefinition=SAI_FS_CHANNEL_IDENTIFICATION;//FS信号为SOF信号+通道识别信号
    SAI4B_Handler.FrameInit.FSPolarity=SAI_FS_ACTIVE_LOW;   //FS低电平有效(下降沿)
    SAI4B_Handler.FrameInit.FSOffset=SAI_FS_BEFOREFIRSTBIT; //在slot0的第一位的前一位使能FS,以匹配飞利浦标准       

    //SLOT设置
    SAI4B_Handler.SlotInit.FirstBitOffset=0;                //slot偏移(FBOFF)为0
    SAI4B_Handler.SlotInit.SlotSize=SAI_SLOTSIZE_16B;       //slot大小为16位
    SAI4B_Handler.SlotInit.SlotNumber=2;                    //slot数为2个   
    SAI4B_Handler.SlotInit.SlotActive=SAI_SLOTACTIVE_0|SAI_SLOTACTIVE_1;//使能slot0和slot1

    HAL_SAI_Init(&SAI4B_Handler);
    SAI4B_DMA_Enable();                                      //使能SAI的DMA功能
    __HAL_SAI_ENABLE(&SAI4B_Handler);                       //使能SAI
}  

//开启SAI的DMA功能,HAL库没有提供此函数
//因此我们需要自己操作寄存器编写一个
void SAI4A_DMA_Enable(void)
{
        u32 tempreg=0;
        tempreg=SAI4_Block_A->CR1;          //先读出以前的设置                       
        tempreg|=1<<17;                                                    //使能DMA
        SAI4_Block_A->CR1=tempreg;                      //写入CR1寄存器中
}

//开启SAIB的DMA功能,HAL库没有提供此函数
//因此我们需要自己操作寄存器编写一个
void SAI4B_DMA_Enable(void)
{
        u32 tempreg=0;
        tempreg=SAI4_Block_B->CR1;          //先读出以前的设置                       
        tempreg|=1<<17;                                            //使能DMA
        SAI4_Block_B->CR1=tempreg;                    //写入CR1寄存器中
}

//SAIA TX DMA配置
//设置为双缓冲模式,并开启DMA传输完成中断
//buf0:M0AR地址.
//buf1:M1AR地址.
//num:每次传输数据量
//width:位宽(存储器和外设,同时设置),0,8位;1,16位;2,32位;
void SAI4A_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_BDMA_CLK_ENABLE();                                     //使能BDMA时钟
    __HAL_LINKDMA(&SAI4A_Handler,hdmarx,SAI4A_RXDMA_Handler);        //将DMA与SAI联系起来
                SAI4A_RXDMA_Handler.Init.Request= BDMA_REQUEST_SAI4_A;                 
    SAI4A_RXDMA_Handler.Instance=BDMA_Channel0;                      //DMA2数据流3               
    SAI4A_RXDMA_Handler.Init.Direction=DMA_PERIPH_TO_MEMORY;         //存储器到外设模式
    SAI4A_RXDMA_Handler.Init.PeriphInc=DMA_PINC_DISABLE;             //外设非增量模式
    SAI4A_RXDMA_Handler.Init.MemInc=DMA_MINC_ENABLE;                 //存储器增量模式
    SAI4A_RXDMA_Handler.Init.PeriphDataAlignment=perwidth;           //外设数据长度:16/32位
    SAI4A_RXDMA_Handler.Init.MemDataAlignment=memwidth;              //存储器数据长度:16/32位
    SAI4A_RXDMA_Handler.Init.Mode=DMA_CIRCULAR;                      //使用循环模式
    SAI4A_RXDMA_Handler.Init.Priority=DMA_PRIORITY_HIGH;             //高优先级
    SAI4A_RXDMA_Handler.Init.FIFOMode=DMA_FIFOMODE_DISABLE;          //不使用FIFO
    SAI4A_RXDMA_Handler.Init.MemBurst=DMA_MBURST_SINGLE;             //存储器单次突发传输
    SAI4A_RXDMA_Handler.Init.PeriphBurst=DMA_PBURST_SINGLE;          //外设突发单次传输
    HAL_DMA_DeInit(&SAI4A_RXDMA_Handler);                            //先清除以前的设置
    HAL_DMA_Init(&SAI4A_RXDMA_Handler);                                    //初始化DMA

    HAL_NVIC_SetPriority(BDMA_Channel0_IRQn,2,0);                    //DMA中断优先级
    HAL_NVIC_EnableIRQ(BDMA_Channel0_IRQn);
                HAL_DMA_Start_IT(&SAI4A_RXDMA_Handler,(u32)&SAI4_Block_A->DR,(u32)buf0,200);
               
}


//SA2A TX DMA配置
//设置为双缓冲模式,并开启DMA传输完成中断
//buf0:M0AR地址.
//buf1:M1AR地址.
//num:每次传输数据量
//width:位宽(存储器和外设,同时设置),0,8位;1,16位;2,32位;
void SAI4B_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_BDMA_CLK_ENABLE();                                    //使能DMA2时钟
    __HAL_LINKDMA(&SAI4B_Handler,hdmarx,SAI4B_RXDMA_Handler);        //将DMA与SAI联系起来
                SAI4B_RXDMA_Handler.Init.Request= BDMA_REQUEST_SAI4_B;                 
                SAI4B_RXDMA_Handler.Instance=BDMA_Channel1;                       //DMA2数据流6       
    SAI4B_RXDMA_Handler.Init.Direction=DMA_PERIPH_TO_MEMORY;         //外设到存储器模式
    SAI4B_RXDMA_Handler.Init.PeriphInc=DMA_PINC_DISABLE;             //外设非增量模式
    SAI4B_RXDMA_Handler.Init.MemInc=DMA_MINC_ENABLE;                 //存储器增量模式
    SAI4B_RXDMA_Handler.Init.PeriphDataAlignment=memwidth;           //外设数据长度:16/32位
    SAI4B_RXDMA_Handler.Init.MemDataAlignment=perwidth;              //存储器数据长度:16/32位
    SAI4B_RXDMA_Handler.Init.Mode=DMA_CIRCULAR;                      //使用循环模式
    SAI4B_RXDMA_Handler.Init.Priority=DMA_PRIORITY_MEDIUM;           //中等优先级
    SAI4B_RXDMA_Handler.Init.FIFOMode=DMA_FIFOMODE_DISABLE;          //不使用FIFO
    SAI4B_RXDMA_Handler.Init.MemBurst=DMA_MBURST_SINGLE;             //存储器单次突发传输
    SAI4B_RXDMA_Handler.Init.PeriphBurst=DMA_PBURST_SINGLE;          //外设突发单次传输
    HAL_DMA_DeInit(&SAI4B_RXDMA_Handler);                            //先清除以前的设置
    HAL_DMA_Init(&SAI4B_RXDMA_Handler);                                    //初始化DMA

    HAL_NVIC_SetPriority(BDMA_Channel1_IRQn,1,3);                    //DMA中断优先级
    HAL_NVIC_EnableIRQ(BDMA_Channel1_IRQn);
                HAL_DMA_Start_IT(&SAI4B_RXDMA_Handler,(u32)&SAI4_Block_B->DR,(u32)buf0,200);               
}

回复

使用道具 举报

发表于 2018-9-30 10:05:01 | 显示全部楼层
这个不了解,之前我们用I2S也有奇怪的问题,使能了就是不正常开启
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

联系站长|手机版|野火电子官网|野火淘宝店铺|野火电子论坛 ( 粤ICP备14069197号 ) 大学生ARM嵌入式2群

GMT+8, 2024-9-23 03:33 , Processed in 0.045286 second(s), 24 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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