最近参考原子哥的SAI例子和标准库的例子用HAL库配置I2S,用逻辑分析仪查相关复用GPIO的引脚,没有电平,求大神帮忙看看

2019-07-20 14:20发布

#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)
        {

        };
}


友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。