新手入门
- 积分
- 16
- 金钱
- 16
- 注册时间
- 2020-3-24
- 在线时间
- 7 小时
|
6金钱
本帖最后由 吴春盈 于 2020-4-20 16:48 编辑
正点原子探索者F4 资料盘(A盘)\4,程序源码\3,标准例程-HAL库版本\实验44 录音机实验//默认是48000
代码都是照搬原子哥的,只是把双声道改为单声道,I2S2_Init和I2S2ext_RX_DMA_Init只是在上电时初始化,后面如果要播放才调用I2S_Play_Start,尝试过每次播放前也初始化DMA,问题仍在,因为程序有录音调用,所以不可能在播放前初始化I2S2_Init
1. 有点不明白的是:为什么原子哥下面配置为4播放的声音才正常,但原子哥的源码是2
I2S2_TX_DMA_Init(audiodev.i2sbuf1,audiodev.i2sbuf2,I2S_TX_DMA_BUFSIZE/4); //配置TX DMA
2. 根据wav_buffill的内容,应该每次发送的数据是左声道低字节、左声道高字节、0、0,MCLK低电平左声道时才有数据
播放多几次后,发现播放静音,开是我用示波器看
有时候MCLK低电平左声道没有数据,变成MCLK高电平右声道有数据,为什么会这样呢?
下面是代码部分
- #define I2S_TX_DMA_BUFSIZE (1920) //2*48*2(2个字节,48指采样率,2声道)
- #define I2S_RX_DMA_BUFSIZE 192 //定义RX DMA 数组大小
- //音乐播放控制器
- typedef struct
- {
- //2个I2S解码的BUF
- u8 i2sbuf1[I2S_TX_DMA_BUFSIZE];
- u8 i2sbuf2[I2S_TX_DMA_BUFSIZE];
- u8 i2rbuf1[I2S_RX_DMA_BUFSIZE];
- u8 i2rbuf2[I2S_RX_DMA_BUFSIZE];
- u32 current_read_wav_flash_size;//当前读wav保存在flash里的位置
- }__audiodev;
- __audiodev audiodev; //音乐播放控制器
- void DMA1_Stream4_IRQHandler(void)
- {
- if(__HAL_DMA_GET_FLAG(&I2S2_TXDMA_Handler,DMA_FLAG_TCIF0_4)!=RESET) //DMA传输完成
- {
- __HAL_DMA_CLEAR_FLAG(&I2S2_TXDMA_Handler,DMA_FLAG_TCIF0_4); //清除DMA传输完成中断标志位
- if(i2s_tx_callback!=NULL) i2s_tx_callback(); //执行回调函数,读取数据等操作在这里面处理
- }
- }
- u8 buff[I2S_TX_DMA_BUFSIZE/4];
- u32 wav_buffill(u8 *buf)
- {
- int i, len;
-
- u8 *p;
- len = I2S_TX_DMA_BUFSIZE/4;
- sFLASH_ReadBuffer(buff, WAV_Address + audiodev.current_read_wav_flash_size, len);//flash保存的是单声道16位的wav数据
- p = buff;
-
- for(i = 0; i < len; i++)
- {
- buf[4*i+0] = p[0];//左声道低字节
- buf[4*i+1] = p[1];//左声道高字节
- buf[4*i+2] = 0;
- buf[4*i+3] = 0;
- p+=2;
- }
- audiodev.current_read_wav_flash_size += (len);
-
- if(audiodev.current_read_wav_flash_size >= wav_param.sizelen)
- {
- return 0;//read all wav data finish
- }
- }
-
- return I2S_TX_DMA_BUFSIZE;
- }
- //WAV播放时,I2S DMA传输回调函数
- void wav_i2s_dma_tx_callback(void)
- {
- if(DMA1_Stream4->CR&(1<<19))
- {
- chx_param[0].playfillnum=wav_buffill(audiodev.i2sbuf1);//填充buf1
- }
- else
- {
- chx_param[0].playfillnum=wav_buffill(audiodev.i2sbuf2);//填充buf2
- }
- }
- //I2S开始播放
- void I2S_Play_Start(void)
- {
- printf("I2S_Play_Start __HAL_DMA_ENABLE\n");
- __HAL_DMA_ENABLE(&I2S2_TXDMA_Handler);//开启DMA TX传输
- }
- u8 I2S2_SampleRate_Set(u32 samplerate)
- {
- u8 i=0;
- u32 tempreg=0;
- RCC_PeriphCLKInitTypeDef RCCI2S2_ClkInitSture;
-
- for(i=0;i<(sizeof(I2S_PSC_TBL)/10);i++)//看看改采样率是否可以支持
- {
- if((samplerate/10)==I2S_PSC_TBL[0])break;
- }
- if(i==(sizeof(I2S_PSC_TBL)/10))return 1;//搜遍了也找不到
-
- RCCI2S2_ClkInitSture.PeriphClockSelection=RCC_PERIPHCLK_I2S; //外设时钟源选择
- RCCI2S2_ClkInitSture.PLLI2S.PLLI2SN=(u32)I2S_PSC_TBL[1]; //设置PLLI2SN
- RCCI2S2_ClkInitSture.PLLI2S.PLLI2SR=(u32)I2S_PSC_TBL[2]; //设置PLLI2SR
- RCCI2S2_ClkInitSture.PLLI2S.PLLI2SM=12;//12m晶振
- HAL_RCCEx_PeriphCLKConfig(&RCCI2S2_ClkInitSture); //设置时钟
-
- 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;
- }
- void I2S2_Init(u32 freq)
- { //飞利浦标准,主机发送,时钟低电平有效,16位帧长度
- I2S2_Handler.Instance=SPI2;
- I2S2_Handler.Init.Mode=I2S_MODE_MASTER_TX; //IIS模式
- I2S2_Handler.Init.Standard=I2S_STANDARD_PHILIPS; //IIS标准
- I2S2_Handler.Init.DataFormat=I2S_DATAFORMAT_16B; //IIS数据长度
- I2S2_Handler.Init.MCLKOutput=I2S_MCLKOUTPUT_ENABLE; //主时钟输出使能
- I2S2_Handler.Init.AudioFreq=I2S_AUDIOFREQ_DEFAULT; //IIS频率设置必须为I2S_AUDIOFREQ_DEFAULT否则调出来的频率不对
- I2S2_Handler.Init.CPOL=I2S_CPOL_LOW; //空闲状态时钟电平
- I2S2_Handler.Init.ClockSource=I2S_CLOCK_PLL; //IIS时钟源为PLL
- I2S2_Handler.Init.FullDuplexMode=I2S_FULLDUPLEXMODE_ENABLE; //IIS全双工
- HAL_I2S_Init(&I2S2_Handler);
-
- SPI2->CR2|=1<<1; //SPI2 TX DMA请求使能.
- I2S2ext->CR2|=1<<0; //I2S2ext RX DMA请求使能.
- __HAL_I2S_ENABLE(&I2S2_Handler); //使能I2S2
- __HAL_I2SEXT_ENABLE(&I2S2_Handler); //使能I2S2ext
- I2S2_SampleRate_Set(freq);
- }
- void I2S2_TX_DMA_Init(u8* buf0,u8 *buf1,u16 num)
- {
- __HAL_RCC_DMA1_CLK_ENABLE(); //使能DMA1时钟
- __HAL_LINKDMA(&I2S2_Handler,hdmatx,I2S2_TXDMA_Handler); //将DMA与I2S联系起来
-
- I2S2_TXDMA_Handler.Instance=DMA1_Stream4; //DMA1数据流4
- I2S2_TXDMA_Handler.Init.Channel=DMA_CHANNEL_0; //通道0
- I2S2_TXDMA_Handler.Init.Direction=DMA_MEMORY_TO_PERIPH; //存储器到外设模式
- I2S2_TXDMA_Handler.Init.PeriphInc=DMA_PINC_DISABLE; //外设非增量模式
- I2S2_TXDMA_Handler.Init.MemInc=DMA_MINC_ENABLE; //存储器增量模式
- I2S2_TXDMA_Handler.Init.PeriphDataAlignment=DMA_PDATAALIGN_HALFWORD; //外设数据长度:16位
- I2S2_TXDMA_Handler.Init.MemDataAlignment=DMA_PDATAALIGN_HALFWORD; //存储器数据长度:16位
- I2S2_TXDMA_Handler.Init.Mode=DMA_CIRCULAR; //使用循环模式
- I2S2_TXDMA_Handler.Init.Priority=DMA_PRIORITY_HIGH; //高优先级
- I2S2_TXDMA_Handler.Init.FIFOMode=DMA_FIFOMODE_DISABLE; //不使用FIFO
- I2S2_TXDMA_Handler.Init.MemBurst=DMA_MBURST_SINGLE; //存储器单次突发传输
- I2S2_TXDMA_Handler.Init.PeriphBurst=DMA_PBURST_SINGLE; //外设突发单次传输
- HAL_DMA_DeInit(&I2S2_TXDMA_Handler); //先清除以前的设置
- HAL_DMA_Init(&I2S2_TXDMA_Handler); //初始化DMA
- HAL_DMAEx_MultiBufferStart(&I2S2_TXDMA_Handler,(u32)buf0,(u32)&SPI2->DR,(u32)buf1,num);//开启双缓冲
- __HAL_DMA_DISABLE(&I2S2_TXDMA_Handler); //先关闭DMA
- delay_us(1000); //10us延时,防止-O2优化出问题
- __HAL_DMA_ENABLE_IT(&I2S2_TXDMA_Handler,DMA_IT_TC); //开启传输完成中断
- __HAL_DMA_CLEAR_FLAG(&I2S2_TXDMA_Handler,DMA_FLAG_TCIF0_4); //清除DMA传输完成中断标志位
-
- HAL_NVIC_SetPriority(DMA1_Stream4_IRQn,0,0); //DMA中断优先级
- HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn);
- }
复制代码
|
|