关于VS1053的一些说明

前言


VS1053是一款利用SPI通讯的音频解码模块,支持大部分的音频文件的解码播放和编码保存

我现在记录下来我的学习经历,仅做参考


注意


如果是录音的话,不要频繁的打开写入关闭你的音频文件,因为这样的话,有可能你的音频文件会写入的不完整,表现是:保存的音频文件很小,而且语速很快,模糊不清。一般是录音时先进入录音模式,再打开你的音频文件,写入wav头,之后不要关闭!继续将读到的音频数据写下去,最后再回去修改wav头中的数据块大小,关闭文件就可以了。

我是先将数据先保存到sdram中,最后结束录音再慢慢将sdram中的数据写入到音频文件中,比如sd卡或者外部Flash中。


正文


第一步当然是如何播放音乐了

思路:先初始化你的SPI及其引脚,SPI通信流程是先发送读命令或者写命令,写的话再发送你要写的VS1053寄存器的地址,再发送你要发送的数据,先是高8位之后是低8位。读的话就是再发送你要读的寄存器地址,再去读,读到的值先是高8位,之后是低8位,组合为16位。注意的是读写的SPI是低速的,还有DCS和CS通信时的电平顺序。

再初始化你的VS1053,硬复位,软复位一下就可以了,硬复位就是再拉高一次RST,然后等待DREQ为高就好了。软复位就是配置VS1053的MODE寄存器和CLOCKF寄存器。配置一下播放的寄存器,比如音量、音效、音速。。。,重新设置一下你的解码时间,最后来直接循环向VS1053发送32字节的音频文件就可以了,VS1053会自动解码你的音频文件并且播放。在发送音频数据的时候可以使用SPI高速模式。

下面是我带ucosiii的相关代码,配合fatfs文件系统。我是先将音频文件先缓存到SDRAM中再播放的。

FATFS fs;							     /* FatFs文件系统对象 */
FIL fnew;						         /* 文件对象 */
FRESULT res_flash;                       /* 文件操作结果 */
UINT fnum;            					 /* 文件成功读写数量 */
//播放音乐
void vs1053_player_song(uint8_t *filepath,unsigned long* file_size )
{
	uint32_t i=0;
	OS_ERR      err;	
	VS_HD_Reset();
	VS_Soft_Reset();
    OSTimeDly(5,OS_OPT_TIME_DLY,&err);  
    
//	VS_Restart_Play();      //切歌不会出现失真  					
	VS_Set_All();    
	VS_Reset_DecodeTime();
	
	if(strstr((const char*)filepath,".flac")||strstr((const char*)filepath,".FLAC"))
		VS_Load_Patch((u16*)vs1053b_patch,VS1053B_PATCHLEN);
	
	res_flash=f_open(&fnew,(const TCHAR*)filepath,FA_READ);

	if(res_flash==0)
	{ 
		VS_SPI_SpeedHigh();				   
		while(1)
		{
			i=0;	
			res_flash=f_read(&fnew,VS1053_Mem,f_size(&fnew),&fnum);
            OSSchedLock(&err);            
			do
			{  	
				if(VS_Send_MusicData(VS1053_Mem+i)==0)
				{
					i+=32;
				}
			}
            while(i

这是一些具体的函数,网上的资料都有,我放一些关键的出来。

//设定VS10XX播放的音量和高低音
//volx:音量大小(0~254)
void VS_Set_Vol(u8 volx)
{
    u16 volt=0; 			//暂存音量值
    volt=254-volx;			//取反一下,得到最大值,表示最大的表示 
	volt<<=8;
    volt+=254-volx;			//得到音量设置后大小
    VS_WR_Cmd(SPI_VOL,volt);//设音量 
}
//设定高低音控制
//bfreq:低频上限频率	2~15(单位:10Hz)
//bass:低频增益			0~15(单位:1dB)
//tfreq:高频下限频率 	1~15(单位:Khz)
//treble:高频增益  	 	0~15(单位:1.5dB,小于9的时候为负数)
void VS_Set_Bass(u8 bfreq,u8 bass,u8 tfreq,u8 treble)
{
    u16 bass_set=0; //暂存音调寄存器值
    signed char temp=0;   	 
	if(treble==0)temp=0;	   		//变换
	else if(treble>8)temp=treble-8;
 	else temp=treble-9;  
	bass_set=temp&0X0F;				//高音设定
	bass_set<<=4;
	bass_set+=tfreq&0xf;			//高音下限频率
	bass_set<<=4;
	bass_set+=bass&0xf;				//低音设定
	bass_set<<=4;
	bass_set+=bfreq&0xf;			//低音上限    
	VS_WR_Cmd(SPI_BASS,bass_set);	//BASS 
}
//设定音效
//eft:0,关闭;1,最小;2,中等;3,最大.
void VS_Set_Effect(u8 eft)
{
	u16 temp;	 
	temp=VS_RD_Reg(SPI_MODE);	//读取SPI_MODE的内容
	if(eft&0X01)temp|=1<<4;		//设定LO
	else temp&=~(1<<4);			//取消LO
	if(eft&0X02)temp|=1<<7;		//设定HO
	else temp&=~(1<<7);			//取消HO						   
	VS_WR_Cmd(SPI_MODE,temp);	//设定模式    
}	 
//设置播放速度(仅VS1053有效) 
//t:0,1,正常速度;2,2倍速度;3,3倍速度;4,4倍速;以此类推
void VS_Set_Speed(u8 t)
{
	VS_WRAM_Write(0X1E04,t);		//写入播放速度 
}
//重设解码时间                          
void VS_Reset_DecodeTime(void)
{
	VS_WR_Cmd(SPI_DECODE_TIME,0x0000);
	VS_WR_Cmd(SPI_DECODE_TIME,0x0000);//操作两次
}
//软复位VS10XX
void VS_Soft_Reset(void)
{	 
	u8 retry=0;  				   
	while(VS_DREQ_IN==0); 					//等待软件复位结束	   
	VS_SPI_ReadWriteByte(0Xff);			//启动传输
	retry=0;
	while(VS_RD_Reg(SPI_MODE)!=0x0800)	// 软件复位,新模式  
	{
		VS_WR_Cmd(SPI_MODE,0x0804);		// 软件复位,新模式	    
		Delay_ms(2);//等待至少1.35ms 
		if(retry++>100)break; 	    
	}	 		 
	while(VS_DREQ_IN==0);//等待软件复位结束	 
	retry=0;
	while(VS_RD_Reg(SPI_CLOCKF)!=0X9800)//设置VS1053的时钟,3倍频 ,1.5xADD 
	{
		VS_WR_Cmd(SPI_CLOCKF,0X9800);	//设置VS1053的时钟,3倍频 ,1.5xADD
		if(retry++>100)break; 	    
	}	 
	Delay_ms(20);
}
//硬复位MP3
//返回1:复位失败;0:复位成功	   
u8 VS_HD_Reset(void)
{
	u8 retry=0;
	VS_RST_CLR;
	Delay_ms(20);
	VS_XDCS_SET;//取消数据传输
	VS_XCS_SET;//取消数据传输
	VS_RST_SET;	   
	while(VS_DREQ_IN==0&&retry<200)//等待DREQ为高
	{
		retry++;
		delay_us(50);
	};
	Delay_ms(20);	
	if(retry>=200)return 1;
	else return 0;	    		 
}

接下来是如何录音。

先进入录音模式 8K采样率,再将从SPI_HDAT0寄存器中读值保存下来,最后在文件开头加上具体的wav文件头,保存下来就是你录制的音频文件了。

static uint32_t write_time;  //用来记录究竟读到了多少的音频数据的标志位

void vs1053_record_start()    //开始录音,会听到它的监听音,而这监听音就是你录下的音
{
	OS_ERR      err;	
	VS_HD_Reset();
	VS_Soft_Reset();
    OSTimeDly(5,OS_OPT_TIME_DLY,&err);   
    recoder_enter_rec_mode(4*1024);  
	while(VS_RD_Reg(SPI_HDAT1)>>8);			//等到buf 较为空闲再开始
    
}

void vs1053_record_run()        //记录一次音频数据,建议33ms左右执行一次
{
    uint16_t regval;
    uint16_t idx;
    regval=VS_RD_Reg(SPI_HDAT1);	
	if((regval>=256)&&(regval<896))
     {  
        idx=0;    
        while(idx<512)
        {
        regval=VS_RD_Reg(SPI_HDAT0);
		VS1053_Mem[write_time]=regval&0XFF;
		VS1053_Mem[write_time+1]=regval>>8;  
		idx+=2;  
        write_time+=2;                
        }         
     }
}

void vs1053_record_stop(char* filepath)    //停止录音并且保存录音
{
    __WaveHeader   pWav_Header; 
    
	pWav_Header.riff.ChunkID=0X46464952;	//"RIFF"
	pWav_Header.riff.ChunkSize=write_time+36;			
	pWav_Header.riff.Format=0X45564157; 	//"WAVE"
	pWav_Header.fmt.ChunkID=0X20746D66; 	//"fmt "
	pWav_Header.fmt.ChunkSize=16; 			//大小为16个字节
	pWav_Header.fmt.AudioFormat=0X01; 		//0X01,表示PCM;0X01,表示IMA ADPCM
 	pWav_Header.fmt.NumOfChannels=1;		//单声道
 	pWav_Header.fmt.SampleRate=8000;		//8Khz采样率 采样速率
 	pWav_Header.fmt.ByteRate=pWav_Header.fmt.SampleRate*2;//16位,即2个字节
 	pWav_Header.fmt.BlockAlign=2;			//块大小,2个字节为一个块
 	pWav_Header.fmt.BitsPerSample=16;		//16位PCM
    pWav_Header.data.ChunkID=0X61746164;	//"data"
 	pWav_Header.data.ChunkSize=write_time;			 

    f_open(&fnew, (const TCHAR*)filepath, FA_OPEN_ALWAYS| FA_WRITE); 
    f_write(&fnew,&pWav_Header,sizeof(__WaveHeader),&fnum);                 //从SDRAN写入SPI_Flash
    f_close(&fnew);
    f_open(&fnew, (const TCHAR*)filepath, FA_OPEN_ALWAYS| FA_WRITE);     
    f_lseek(&fnew,f_size(&fnew));    
    f_write(&fnew,VS1053_Mem,write_time,&fnum);        
    f_close(&fnew); 
    VS_HD_Reset();		   	//硬复位
    VS_Soft_Reset();  		//软复位  
    memset(VS1053_Mem,0,write_time);  
    write_time=0;     
}

下面是进入录音模式相关代码

/*----------------- 录音功能函数 --------------------------*/
//VS1053的WAV录音有bug,这个plugin可以修正这个问题 							    
const uint16_t wav_plugin[40]=/* Compressed plugin */ 
{ 
0x0007, 0x0001, 0x8010, 0x0006, 0x001c, 0x3e12, 0xb817, 0x3e14, /* 0 */ 
0xf812, 0x3e01, 0xb811, 0x0007, 0x9717, 0x0020, 0xffd2, 0x0030, /* 8 */ 
0x11d1, 0x3111, 0x8024, 0x3704, 0xc024, 0x3b81, 0x8024, 0x3101, /* 10 */ 
0x8024, 0x3b81, 0x8024, 0x3f04, 0xc024, 0x2808, 0x4800, 0x36f1, /* 18 */ 
0x9811, 0x0007, 0x0001, 0x8028, 0x0006, 0x0002, 0x2a00, 0x040e,  
}; 

//激活PCM 录音模式
//agc:0,自动增益.1024相当于1倍,512相当于0.5倍,最大值65535=64倍		  
void recoder_enter_rec_mode(u16 agc)
{
	//如果是IMA ADPCM,采样率计算公式如下:
 	//采样率=CLKI/256*d;	
	//假设d=0,并2倍频,外部晶振为12.288M.那么Fc=(2*12288000)/256*6=16Khz
	//如果是线性PCM,采样率直接就写采样值 
    VS_WR_Cmd(SPI_BASS,0x0000);    
 	VS_WR_Cmd(SPI_AICTRL0,8000);	//设置采样率
 	VS_WR_Cmd(SPI_AICTRL1,agc);		//设置增益,0,自动增益.1024相当于1倍,512相当于0.5倍,最大值65535=64倍	
 	VS_WR_Cmd(SPI_AICTRL2,0);		//设置增益最大值,0,代表最大值65536=64X
 	VS_WR_Cmd(SPI_AICTRL3,6);		//4:线性PCM模式 + 2: 左通道 3: 右通道
	VS_WR_Cmd(SPI_CLOCKF,0X2000);	//设置VS10XX的时钟,MULT:2倍频;ADD:不允许;CLK:12.288Mhz
	VS_WR_Cmd(SPI_MODE,0x1804);		//MIC,录音激活    
 	Delay_ms(5);					//等待至少1.35ms 
 	VS_Load_Patch((u16*)wav_plugin,40);//VS1053的WAV录音需要patch
}

其中的VS1053_Mem是一个 4MByte的SDRAM的数组作为缓存。如果没有的话,可以自行修改程序,先写入RAM中,再写入SD卡中或外部Flash中。


如果还是不理解的朋友可以看正点原子的教学视频学习,这里只是做一个比较精简的汇总。

附上传送门:https://chuanke.baidu.com/v7206678-245150-1858328.html

你可能感兴趣的:(关于VS1053的一些说明)