OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 2151|回复: 7

求助!MP3软解后用自带DAC输出移植问题

[复制链接]

1

主题

11

帖子

0

精华

新手上路

积分
21
金钱
21
注册时间
2018-6-7
在线时间
1 小时
发表于 2018-6-7 16:56:52 | 显示全部楼层 |阅读模式
5金钱
开发板用的芯片是stm32f103ret。
参考的代码是:

http://www.openedv.com/posts/list/2345.htm
http://www.openedv.com/posts/list/10961.htm

基础工程,SD卡文件系统,MP3软解部分都OK,原本是通过WM8978输出音频。

现在想通过自带DAC输出,WAV的可以通过参考代码获取并且OK,但是MP3部分移植后NOK,

有没有了解DAC输出这块的大神?求助(请原谅我是新人没有太多金钱),附件是我现在的工程文件。

SD播放MP3.zip

18.82 MB, 下载次数: 170

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

1

主题

11

帖子

0

精华

新手上路

积分
21
金钱
21
注册时间
2018-6-7
在线时间
1 小时
 楼主| 发表于 2018-6-7 16:58:17 | 显示全部楼层
回复

使用道具 举报

1

主题

11

帖子

0

精华

新手上路

积分
21
金钱
21
注册时间
2018-6-7
在线时间
1 小时
 楼主| 发表于 2018-6-7 16:58:58 | 显示全部楼层
有没有人啊?长期在线等
回复

使用道具 举报

1

主题

11

帖子

0

精华

新手上路

积分
21
金钱
21
注册时间
2018-6-7
在线时间
1 小时
 楼主| 发表于 2018-6-7 17:06:43 | 显示全部楼层
顶一顶,不要沉啊
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165524
金钱
165524
注册时间
2010-12-1
在线时间
2116 小时
发表于 2018-6-8 01:52:44 | 显示全部楼层
一样可以才对啊,MP3解码最终也是输出到16位数据里面,你要做的就是将16位数组,按指定采样率输出到DAC即可。
回复

使用道具 举报

1

主题

11

帖子

0

精华

新手上路

积分
21
金钱
21
注册时间
2018-6-7
在线时间
1 小时
 楼主| 发表于 2018-6-8 08:35:46 | 显示全部楼层
正点原子 发表于 2018-6-8 01:52
一样可以才对啊,MP3解码最终也是输出到16位数据里面,你要做的就是将16位数组,按指定采样率输出到DAC即可 ...

谢谢原子哥指点!我再搞一搞
回复

使用道具 举报

1

主题

11

帖子

0

精华

新手上路

积分
21
金钱
21
注册时间
2018-6-7
在线时间
1 小时
 楼主| 发表于 2018-6-8 08:44:19 | 显示全部楼层
正点原子 发表于 2018-6-8 01:52
一样可以才对啊,MP3解码最终也是输出到16位数据里面,你要做的就是将16位数组,按指定采样率输出到DAC即可 ...

原子哥这是快凌晨三点给的回复啊,注意休息啊
回复

使用道具 举报

1

主题

11

帖子

0

精华

新手上路

积分
21
金钱
21
注册时间
2018-6-7
在线时间
1 小时
 楼主| 发表于 2018-6-9 13:30:10 | 显示全部楼层
正点原子 发表于 2018-6-8 01:52
一样可以才对啊,MP3解码最终也是输出到16位数据里面,你要做的就是将16位数组,按指定采样率输出到DAC即可 ...

原子哥,经过调整,目前MP3能得到解码信息,DAC也可以发声,但是听到的是有规律的杂音,可以麻烦帮我看一下代码吗?感谢!

[mw_shl_code=c,true]#include "wave.h"
#include "mp3.h"
#include "string.h"
#include "mp3dec.h"
#include "wm8978.h"
#include "i2s.h"


//__align(8)
//uint16_t Mp3DecodeBuf[DECODEBUFSIZE];
short *Mp3DecodeBuf;

FIL Mp3File;
mp3Info Mp3Info;
uint8_t* Readptr;        //MP3解码读指针
int32_t ByteLeft;//buffer还剩余的有效数据
uint8_t        InitMp3InfoFlag;
HMP3Decoder Mp3Decoder;
uint32_t DmaBufSize;


/*==========================================================*/
unsigned char DACbz_mp3;
unsigned char CH_mp3;
unsigned int DApc_mp3;
unsigned char buffer_switch;
HMP3Decoder hMP3Decoder;
FIL f_MP3;
//int16_t         *buffer1={0x00};
//int16_t         *buffer2={0x00};
short *buffer1;
short *buffer2;


void TIM3_IRQHandler(void)
{                  
        if(TIM3->SR&0X0001)//溢出中断
        {
                if(CH_mp3==1)//单声道
                {
                        if(buffer_switch==0)
                        {
                                DAC->DHR12R1=(((uint16_t)buffer1[DApc_mp3]+0x8000)>>4);//*10/volume;
                                DAC->DHR12R2=(((uint16_t)buffer1[DApc_mp3]+0x8000)>>4);//*10/volume;
                                DApc_mp3++;
                                DAC->SWTRIGR|=0x03;//软件启动两个通道的转换   
                        }
                        else
                        {
                                DAC->DHR12R1=(((uint16_t)buffer2[DApc_mp3]+0x8000)>>4);//*10/volume;
                                DAC->DHR12R2=(((uint16_t)buffer2[DApc_mp3]+0x8000)>>4);//*10/volume;
                                DApc_mp3++;
                                DAC->SWTRIGR|=0x03;//软件启动两个通道的转换
                        }      
                }
                else //if(CH_mp3==2)//立体声    10110010  10110010
                {
                        if(buffer_switch==0)
                        {
                                DAC->DHR12R1=(((uint16_t)buffer1[DApc_mp3]+0x8000)>>4);//*10/volume;
                                DApc_mp3++;
                                DAC->DHR12R2=(((uint16_t)buffer1[DApc_mp3]+0x8000)>>4);//*10/volume;
                                DApc_mp3++;
                                DAC->SWTRIGR|=0x03;//软件启动两个通道的转换   
                        }
                        else
                        {
                                DAC->DHR12R1=(((uint16_t)buffer2[DApc_mp3]+0x8000)>>4);//*10/volume;
                                DApc_mp3++;
                                DAC->DHR12R1=(((uint16_t)buffer2[DApc_mp3]+0x8000)>>4);//*10/volume;
                                DApc_mp3++;
                                DAC->SWTRIGR|=0x03;//软件启动两个通道的转换
                        }
                }  
                if(DApc_mp3==2304)///    //1帧MP3输出2304数据
                {
                        DApc_mp3=0;
                        DACbz_mp3=1;
                }                             
        }      
        TIM3->SR&=~(1<<0);//清除中断标志位     
}
//设置NVIC分组
//NVIC_Group:NVIC分组 0~4 总共5组
//CHECK OK
//091209
void MY_NVIC_PriorityGroupConfig(unsigned char NVIC_Group)         
{
        uint32_t temp,temp1;          
        temp1=(~NVIC_Group)&0x07;//取后三位
        temp1<<=8;
        temp=SCB->AIRCR;  //读取先前的设置
        temp&=0X0000F8FF; //清空先前分组
        temp|=0X05FA0000; //写入钥匙
        temp|=temp1;          
        SCB->AIRCR=temp;  //设置分组                                                        
}
//设置NVIC
//NVIC_PreemptionPriority:抢占优先级
//NVIC_SubPriority       :响应优先级
//NVIC_Channel           :中断编号
//NVIC_Group             :中断分组 0~4
//注意优先级不能超过设定的组的范围!否则会有意想不到的错误
//组划分:
//组0:0位抢占优先级,4位响应优先级
//组1:1位抢占优先级,3位响应优先级
//组2:2位抢占优先级,2位响应优先级
//组3:3位抢占优先级,1位响应优先级
//组4:4位抢占优先级,0位响应优先级
//NVIC_SubPriority和NVIC_PreemptionPriority的原则是,数值越小,越优先
//CHECK OK
//100329
void MY_NVIC_Init(unsigned char NVIC_PreemptionPriority,unsigned char NVIC_SubPriority,unsigned char NVIC_Channel,unsigned char NVIC_Group)         
{
        uint32_t temp;       
        unsigned char IPRADDR=NVIC_Channel/4;  //每组只能存4个,得到组地址
        unsigned char IPROFFSET=NVIC_Channel%4;//在组内的偏移
        IPROFFSET=IPROFFSET*8+4;    //得到偏移的确切位置
        MY_NVIC_PriorityGroupConfig(NVIC_Group);//设置分组
        temp=NVIC_PreemptionPriority<<(4-NVIC_Group);          
        temp|=NVIC_SubPriority&(0x0f>>NVIC_Group);
        temp&=0xf;//取低四位

        if(NVIC_Channel<32)NVIC->ISER[0]|=1<<NVIC_Channel;//使能中断位(要清除的话,相反操作就OK)
        else NVIC->ISER[1]|=1<<(NVIC_Channel-32);   
        NVIC->IP[IPRADDR]|=temp<<IPROFFSET;//设置响应优先级和抢断优先级                                                           
}

//通用定时器4中断初始化
//这里始终选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数
//这里使用的是定时器4!
void Timer3_Init(unsigned int arr,unsigned int psc)
{
        RCC->APB1ENR|=1<<1;//TIM3时钟使能   
        TIM3->ARR=arr;  //设定计数器自动重装值//刚好1ms   
        TIM3->PSC=psc;  //预分频器7200,得到10Khz的计数时钟
        //这两个东东要同时设置才可以使用中断
        TIM3->DIER|=1<<0;   //允许更新中断                               
        TIM3->DIER|=1<<6;   //允许触发中断
                                                                              
        TIM3->CR1|=0x01;    //使能定时器3
          MY_NVIC_Init(1,3,0x1D,2);//抢占1,子优先级3,组2                                                                         
}

void DAC1_SetData(unsigned int data)
{
        DAC->DHR12R1=data;//通道1的12位右对齐数据
        DAC->SWTRIGR|=0x01;//软件启动转换
}

void DAC2_SetData(unsigned int data)
{
        DAC->DHR12R2=data;//通道2的12位右对齐数据
        DAC->SWTRIGR|=0x02;//软件启动转换
}
void Dac1_Init(void)//DAC channel1 Configuration
{
          unsigned int tmpreg1=0,tmpreg2=0;
        RCC->APB2ENR|=1<<2;//使能PORTA时钟
        RCC->APB1ENR|=0x20000000;//使能DAC时钟
        GPIOA->CRL&=0XFF00FFFF;
        GPIOA->CRL|=0X00440000;//PA4,5 浮空输入            

          tmpreg1=DAC->CR;//Get the DAC CR value  
          tmpreg1&=~(0x00000FFE<<0x00000000);//Clear BOFFx, TENx, TSELx, WAVEx and MAMPx bits  
          tmpreg2=(0x0000003C|0x00000000|0x00000800|0x00000000);
          tmpreg1|=tmpreg2<<0x00000000;//Calculate CR register value depending on DAC_Channel
          DAC->CR=tmpreg1;//Write to DAC CR
        DAC->CR|=0x00000001<<0x00000000;//DAC Channel1使能,PA4自动连接到DAC
        DAC1_SetData(0x000);

          tmpreg1=DAC->CR;//Get the DAC CR value  
          tmpreg1&=~(0x00000FFE<<0x00000010);//Clear BOFFx, TENx, TSELx, WAVEx and MAMPx bits  
          tmpreg2=(0x0000003C|0x00000000|0x00000800|0x00000000);
          tmpreg1|=tmpreg2<<0x00000010;//Calculate CR register value depending on DAC_Channel
          DAC->CR=tmpreg1;//Write to DAC CR
        DAC->CR|=0x00000001<<0x00000010;//DAC Channel2使能,PA5自动连接到DAC
        DAC2_SetData(0x000);
}

/************************************************************************************/
/*
* File Name  : Convert_Stereo  μ¥éùμàμ?á¢ì?éù×a??
* Description    : I have do some modification in Subband() function due to the long time of
*                  decode.Using PolyphaseMono() function which is used in decode mono mp3,to decode
*                  Stereo,so must use this funtion to convert mono to Stereo.
* Input          : Adress of buffer data
* Output         : None
* Return         : None
*/
/************************************************************************************/
void Convert_Stereo(short *buffer)
{
        int i,j,k=0;
        for(i=0;i<(2304/64);i++)           //36
        {
                for(j=31+i*64,k=j+32;j>=0+i*64;j--,k-=2)
                {
                        buffer[k]=buffer[j];
                        buffer[k-1]=buffer[j];
                }
        }
}

/***********************************************************************************/
/*
* File Name  : Convert_Mono
* Description    : ?o3?oóμ?μ¥éùμàMP3?a???÷μ??ò?ü£???ì?211152°?×?£??a??1|?ü*????±?μ¥éùμàμ?á¢ì?éù?£
* Input          : Adress of buffer data
* Output         : None
* Return         : None
*/
/***********************************************************************************/
void Convert_Mono(short *buffer)
{
        int i;
        for (i = 1152 - 1; i >= 0; i--)
        {
                buffer[i * 2] = buffer;
                buffer[i * 2 + 1] = buffer;
        }
}


uint8_t PlayMp3File(char* path)
{
        uint8_t res=0;
        uint32_t br=0;
        //uint32_t Mp3DataStart=0;
        CloseFileFlag=0;
        EndFileFlag=0;
        FillBufFlag=0xFF;
        //ID3V2_TagHead *TagHead;
       
       Mp3DecodeBuf=buffer1;
        Mp3Decoder=MP3InitDecoder();
        if(Mp3Decoder==0)
        {
                printf("Init Mp3Decoder failed!\r\n");
                //res=4;
                //break;
        }

       
        Dac1_Init();
        res=f_open(&Mp3File,(TCHAR*)path,FA_READ);
        while(1)
        {
                if(res!=FR_OK)
                {
                        printf("Open file failed!\r\n");
                        res=1;
                        break;
                }
                CloseFileFlag=1;
                res=f_read(&Mp3File,TempBuf,WAVEFILEBUFSIZE,&br);
                if(res!=FR_OK)
                {
                        printf("Read file failed!\r\n");
                        res=2;
                        break;
                }

                Readptr=TempBuf;
                ByteLeft=br;

                FillMp3Buf(WaveFileBuf+DmaBufSize/2);
                //break;
        }

                f_close(&Mp3File);
       
        TIM4->CR1&=~0x01;//关定时器,切歌时不产生噪音
        DAC->CR&=0<<0; //关闭DAC1

        MP3FreeDecoder(Mp3Decoder);       
        return 0;
}


uint32_t FillMp3Buf(uint8_t *Buf)
{
        uint32_t br=0;
        int32_t Offset;
        int32_t err=0;
        //int32_t i;
        uint16_t *PlayPtr;
        //uint16_t *Mp3Ptr;
        MP3FrameInfo Mp3FrameInfo;
        int8_t init=0;
        Offset=MP3FindSyncWord(Readptr,ByteLeft);        //在readptr位置,开始查找同步字符
        if(Offset<0)                                                                                                                        //没有找到同步字符,跳出帧解码循环
        {
                printf("Can not play the file!\r\n");
                return 1;
        }
        Readptr+=Offset;                                                                                                        //MP3读指针偏移到同步字符处.
        ByteLeft-=Offset;                                                                                                        //buffer里面的有效数据个数,必须减去偏移量
        //printf("ByteLeft=%d\r\n",ByteLeft);
        if(ByteLeft<MAINBUF_SIZE*2)//当数组内容小于2倍MAINBUF_SIZE的时候,必须补充新的数据进来.
        {
                memmove(TempBuf,Readptr,ByteLeft);//移动readptr所指向的数据到buffer里面,数据量大小为:bytesleft
                /*
                ReadBytesNum=WAVEFILEBUFSIZE-ByteLeft;
                if(ReadBytesNum%2)
                        ReadBytesNum-=1;
                f_read(&Mp3File,TempBuf+ByteLeft,ReadBytesNum,&br);//补充余下的数据
                printf("rd=%d,br=%d\r\n",ReadBytesNum,br);
                if(br<ReadBytesNum)
                {
                        memset(TempBuf+ByteLeft+br,0,WAVEFILEBUFSIZE-ByteLeft-br);
                        //EndFileFlag=1;
                }
                ByteLeft=ByteLeft+ReadBytesNum;
                */
                f_read(&Mp3File,TempBuf+ByteLeft,WAVEFILEBUFSIZE-ByteLeft,&br);//补充余下的数据
                //printf("rd=%d,br=%d\r\n",WAVEFILEBUFSIZE-ByteLeft,br);
                if(br<WAVEFILEBUFSIZE-ByteLeft)
                {
                        memset(TempBuf+ByteLeft+br,0,WAVEFILEBUFSIZE-ByteLeft-br);
                        EndFileFlag=1;
                }
                ByteLeft=WAVEFILEBUFSIZE;
                Readptr=TempBuf;
        }
        err=MP3Decode(Mp3Decoder,&Readptr,&ByteLeft,Mp3DecodeBuf,0);//解码一帧MP3数据
        //printf("Decode error:%d\r\n",err);
        if(err!=0)
        {
                printf("Decode error:%d\r\n",err);
                return 2;
        }
        if(InitMp3InfoFlag==0)
        {
                MP3GetLastFrameInfo(Mp3Decoder,&Mp3FrameInfo);        //得到刚刚解码的MP3帧信息
                Mp3Info.bitsPerSample=Mp3FrameInfo.bitsPerSample;
                Mp3Info.nChans=Mp3FrameInfo.nChans;
                Mp3Info.OutSamples=Mp3FrameInfo.outputSamps;
                Mp3Info.samprate=Mp3FrameInfo.samprate;
                printf("bitsPerSample=%d\r\n",Mp3Info.bitsPerSample);
                printf("nChans=%d\r\n",Mp3Info.nChans);
                printf("OutSamples=%d\r\n",Mp3Info.OutSamples);
                printf("samprate=%d\r\n",Mp3Info.samprate);
                InitMp3InfoFlag=1;

                        if(init==0)   //根据MP3帧信息初始化音频接口
                        {
                                Timer3_Init(1000000/(Mp3Info.samprate),71);//   1MHz的计数频率,产生和采样率一样的中断频率
                                CH_mp3=Mp3Info.nChans;   //几声道      
                                init=1;//              //1帧MP3输出2304pcm数据
                        }      
                        if(Mp3Info.nChans==1)Convert_Mono(Mp3DecodeBuf);//单声道
                        else Convert_Stereo(Mp3DecodeBuf);//立体声
                        while(!DACbz_mp3);        //等待转换完成
                        DACbz_mp3=0;   //定时器中断会置1

                        if(buffer_switch == 0)     //双缓存切换
                        {
                                Mp3DecodeBuf=buffer1;      
                                buffer_switch = 1;
                        }
                        else
                        {   
                                Mp3DecodeBuf=buffer2;
                                buffer_switch = 0;
                        }

               
                if(Mp3Info.bitsPerSample!=16)
                {
                        printf("Can not play the file!\r\n");
                        return 3;
                }
        }
        //Mp3Ptr=Mp3DecodeBuf;
        PlayPtr=(uint16_t*)Buf;
        /*if(Mp3Info.nChans==2)
        {
                for(i=0;i<Mp3Info.OutSamples;i++)
                {
                        PlayPtr=Mp3Ptr;
                }
        }
        else
        {
                for(i=0;i<Mp3Info.OutSamples;i++)
                {
                        PlayPtr[0]=Mp3Ptr[0];
                        PlayPtr[1]=Mp3Ptr[0];
                        PlayPtr+=2;
                        Mp3Ptr+=1;
                }
        }*/
        return 0;
}
[/mw_shl_code]
回复

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-5-29 10:34

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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