VS1003 VS1053B电路图分析及程序

     MP3,MP4,数码相机曾经是奢侈品。科技发展了,这些东西也就成了普通手机的附属品了。但是作为手艺人学习这些芯片了解这些高性能芯片是很有必要的。学习了解它既拓展了自己的眼界,也可以提升自己对嵌入式系统的认识。原子战舰板上就板载了一颗高性能MP3音乐播放器芯片VS1053B芯片。通过原子源码对一些参数的修改,也能欣赏美妙的音乐。这是一款真正的数字产品。还可以作为录音机使用。

     VS1053是继VS1003后荷兰VLSI公司出品的又一款高性能解码芯片。该芯片可以实现对MP3/OGG/WMA/FLAC/WAV/AAC/MIDI等音频格式的解码,同时还可以支持ADPCM/OGG等格式的编码,性能相对以往的VS1003提升不少。VS1053拥有一个高性能的DSP处理器核VS_DSP,16K的指令RAM,0.5K的数据RAM,通过SPI控制,具有8个可用的通用IO口和一个串口,芯片内部还带了一个可变采样率的立体声ADC(支持咪头/咪头+线路/2线路)、一个高性能立体声DAC及音频耳机放大器。


     VS1053既然是高性能DSP,也就是说它本身就可以作为主机象普通MCU一样使用。同普通MCU一样DSP也具有一样的最小系统,所以在电路设计中自然就必须要晶振和复位电路。通过读datasheet知道,VS1053B也有中断功能,同样有GPIO!操作寄存器可以控制时钟频率。

        下面是电路图:
 


 下面是音频驱动电路图:即耳机驱动电路。


   
    这两张电路图是战舰板原理图,电路图设计是核心技术。本人对原子的电路设计只有学习和佩服的份。其中74HC4052和TDA1308分别是用作音频选择和耳机驱动,74HC4052芯片将板载的MP3,FM收音机和STM32发出的方波信号通过程序控制做出选择;也就是说将众多音频信号集于一身可以分别单独送到耳机驱动电路输出,既节约了空间也节约了成本。设计非常精妙!
   
     通过学习VS1053B,对电路分析能力也有提高。如果看不懂电路图,即便c语言代码分析的多么透彻也无济于事。  通过学习类似VS1053B芯片的驱动,能真正提高手艺人的编程能力。通过数据手册,写出相应芯片的驱动程序实现一些简单功能是一个程序员的核心竞争力!这里涉及到许多c语言编程技巧。一句话,目前我是没有这个能力。也就只能好好学习别人源码的份了。有所收获就记录下来。

    VS1053B,LCD,RDA5802收音机芯片,ADXL345重力加速度传感器芯片等等这些芯片,它们有一个共同点:寄存器,寄存器地址,数据帧,命令字,I2C, SPI 协议等等。学会这些外设芯片的驱动程序编写方法,才能真正发挥ARM处理器的强大功能。

     有感而发!

下面提供VS1003 VS1053B芯片的51单片机完整驱动程序和VS1053 pdf中文资料文件下载:http://www.51hei.com/f/VS1053.rar
下面是单片机程序的主要部分预览:
/*
 * MP3模块测试程序
 * 
 * 用途:MP3模块测试程序
 *       vs1003 的硬件测试程序,主控芯片为STC12LE5A60S2
 *       其他的微处理器(带SPI接口的)只需稍加修改即可适用
 *       对于不带硬SPI接口的微处理器可以用IO进行SPI的时序模拟
 * 
 * 作者日期备注
 * Huafeng Lin20010/09/10新增
 * Huafeng Lin20010/09/10修改
 * 
 */
#include "vs1003.h"
#include "MusicDataMP3.c"
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
#define bool bit
#define true 1
#define flase 0
//针对SD卡读写板调整引脚
#define uint8 unsigned char
sbit  MP3_XRESET  = P3^2;
#define Mp3PutInReset()  { MP3_XRESET = 0; }
#define Mp3ReleaseFromReset()  { MP3_XRESET =1; }
sbit MP3_XCS = P3^3;
#define Mp3SelectControl()  { MP3_XCS = 0; }
#define Mp3DeselectControl()  { MP3_XCS = 1; }
sbit MP3_XDCS  = P3^4;
#define Mp3SelectData(){ MP3_XDCS = 0; }
#define Mp3DeselectData(){ MP3_XDCS = 1; }
sbit MP3_DREQ = P3^5;
sbit c_SPI_SI = P1^5;
sbit c_SPI_SO = P1^6;
sbit c_SPI_CLK = P1^7;
#define Macro_Set_SI_High()  c_SPI_SI = 1
#define Macro_Set_SI_Low()  c_SPI_SI = 0
#define Macro_Set_CLK_High()  c_SPI_CLK = 1
#define Macro_Set_CLK_Low()  c_SPI_CLK = 0
void LCD_write_english_string(unsigned char X,unsigned char Y,char *s);
//#define SPIWait(){ while((S0SPSR & 0x80) == 0); }//等待SPI将数据发送完毕
//#define SPI_RESULT_BYTE  S0SPDR
//extern long volatile timeval; //用于延时的全局变量
//1ms Delayfunction
//void Delay(uchar ucDelayCount)
void wait(uchar ucDelayCount)
{
uchar ucTempCount;
uchar uci;
for(ucTempCount=0; ucTempCount<ucDelayCount; ucTempCount++)
{
//uci = 200;//Err
//uci = 250;//OK
uci = 230;
while(uci--)
{
_nop_();
  }
}
}
//#define wait(x) Delay(x)
/**********************************************************/
/*  函数名称 :   MSPI_Init                                */
/*  函数功能 : 初始化SPI接口,设置为主机。               */
/*  参数     :  无                                        */
/*  返回值   :  无                                        */
/*--------------------------------------------------------*/
void  MSPI_Init(void)
{  
/*
PINSEL0 = (PINSEL0 & 0xFFFF00FF) | 0x00005500;//选择 SPI 
        S0SPCCR = 0x08;                        // SPI 时钟设置
 S0SPCR  = (0 << 3) |// CPHA = 0, 
   (0 << 4) |// CPOL = 0, 
   (1 << 5) |// MSTR = 1, 
   (0 << 6) |// LSBF = 0, 
           (0 << 7);// SPIE = 0, 
*/
c_SPI_SO = 1;
MP3_DREQ = 1;
}
/**********************************************************/
/*  函数名称 :  InitPortVS1003                            */
/*  函数功能 : MCU与vs1003接口的初始化                   */
/*  参数     :  无                                        */
/*  返回值   :  无                                        */
/*--------------------------------------------------------*/
void  InitPortVS1003(void)
{
MSPI_Init();//SPI口的初始化
//IODIR &= 0xfffeffff;   //其他接口线的设置,其中dreq 为输入口
//IODIR |= MP3_XRESET | MP3_XCS | MP3_XDCS;//xRESET,xCS,xDS均为输出口
//IOSET |= MP3_XRESET | MP3_XCS | MP3_XDCS;//xRESET,xCS,xDS默认输出高电平
MP3_DREQ = 1;//置为输入
MP3_XRESET = 1;
MP3_XCS = 1;
MP3_XDCS = 1;
}
//uint8 SD_SPI_ReadByte(void);
//void SD_SPI_WriteByte(uint8 ucSendData);
//#define SPI_RecByte()  SD_SPI_ReadByte()
//#define SPIPutChar(x) SD_SPI_WriteByte(x)
#if 1
/**********************************************************/
/*  函数名称 :  SPIPutChar                                */
/*  函数功能 : 通过SPI发送一个字节的数据                 */
/*  参数     :  待发送的字节数据                          */
/*  返回值   :  无                                        */
/*--------------------------------------------------------*/
void  SPIPutChar(unsigned char ucSendData)
{      
//S0SPDR = c;
//while((S0SPSR & 0x80) == 0); //等待SPI将数据发送完毕
uchar ucCount;
uchar ucMaskCode;
ucMaskCode = 0x80;
for(ucCount=0; ucCount<8; ucCount++)
{
Macro_Set_CLK_Low();
if(ucMaskCode & ucSendData)
{
Macro_Set_SI_High();
}
else
{
Macro_Set_SI_Low();
}
Macro_Set_CLK_High();
ucMaskCode >>= 1;
}
}
/*******************************************************************************************************************
** 函数名称: INT8U SPI_RecByte()Name:  INT8U SPI_RecByte()
** 功能描述: 从SPI接口接收一个字节Function: receive a byte from SPI interface
** 输   入: 无Input:  NULL
** 输   出: 收到的字节Output:  the byte that be received
********************************************************************************************************************/
static uchar SPI_RecByte(void)
{
uchar ucReadData;
uchar ucCount;
ucReadData = 0;
Macro_Set_SI_High();
for(ucCount=0; ucCount<8; ucCount++)
{
ucReadData <<= 1;
//降低时钟频率
Macro_Set_CLK_Low();
if(c_SPI_SO)
{
ucReadData |= 0x01;
}
Macro_Set_CLK_High();
}
return(ucReadData);
}
#endif
/*************************************************************/
/*  函数名称 :  Mp3WriteRegister                             */
/*  函数功能 : 写vs1003寄存器                               */
/*  参数     :  寄存器地址,待写数据的高8位,待写数据的低8位 */
/*  返回值   :  无                                           */
/*-----------------------------------------------------------*/
void Mp3WriteRegister(unsigned char addressbyte, unsigned char highbyte, unsigned char lowbyte)
{
Mp3DeselectData();
Mp3SelectControl();//XCS = 0
SPIPutChar(VS_WRITE_COMMAND); //发送写寄存器命令
SPIPutChar(addressbyte);      //发送寄存器的地址
SPIPutChar(highbyte);         //发送待写数据的高8位
SPIPutChar(lowbyte);          //发送待写数据的低8位
Mp3DeselectControl();
}
/*************************************************************/
/*  函数名称 :  Mp3ReadRegister                              */
/*  函数功能 : 写vs1003寄存器                               */
/*  参数     :  寄存器地址     */
/*  返回值   :  vs1003的16位寄存器的值                       */
/*-----------------------------------------------------------*/
unsigned int Mp3ReadRegister(unsigned char addressbyte)
{
unsigned int resultvalue = 0;
uchar ucReadValue;
Mp3DeselectData();
Mp3SelectControl();//XCS = 0
SPIPutChar(VS_READ_COMMAND); //发送读寄存器命令
SPIPutChar((addressbyte)); //发送寄存器的地址
//SPIPutChar(0xff); //发送读时钟
//resultvalue = (SPI_RESULT_BYTE) << 8;//读取高8位数据
ucReadValue = SPI_RecByte();
resultvalue = ucReadValue<<8;
//SPIPutChar(0xff);   //发送读时钟
//resultvalue |= (SPI_RESULT_BYTE);  //读取低8位数据
ucReadValue = SPI_RecByte();
resultvalue |= ucReadValue;
Mp3DeselectControl();              
return resultvalue;                 //返回16位寄存器的值
}
/**********************************************************/
/*  函数名称 :  Mp3SoftReset                              */
/*  函数功能 : vs1003软件复位                            */
/*  参数     :  无                                        */
/*  返回值   :  无                                        */
/*--------------------------------------------------------*/
void Mp3SoftReset(void)
{
Mp3WriteRegister (SPI_MODE, 0x08, 0x04); //软件复位
wait(1); //延时1ms
while (MP3_DREQ == 0); //等待软件复位结束
Mp3WriteRegister(SPI_CLOCKF, 0x98, 0x00);//设置vs1003的时钟,3倍频
Mp3WriteRegister (SPI_AUDATA, 0xBB, 0x81); //采样率48k,立体声
Mp3WriteRegister(SPI_BASS, 0x00, 0x55);//设置重音
Mp3SetVolume(10,10);//设置音量
    wait(1); //延时1ms
    //向vs1003发送4个字节无效数据,用以启动SPI发送
   Mp3SelectData();
SPIPutChar(0);
SPIPutChar(0);
SPIPutChar(0);
SPIPutChar(0);
Mp3DeselectData();
}
/**********************************************************/
/*  函数名称 :  Mp3Reset                                  */
/*  函数功能 : vs1003硬件复位                            */
/*  参数     :  无                                        */
/*  返回值   :  无                                        */
/*--------------------------------------------------------*/
void Mp3Reset(void)
{
Mp3PutInReset();//xReset = 0   复位vs1003      
wait(200);//延时100ms
SPIPutChar(0xff);//发送一个字节的无效数据,启动SPI传输
Mp3DeselectControl();   //xCS = 1
Mp3DeselectData();     //xDCS = 1
Mp3ReleaseFromReset(); //xRESET = 1
wait(200);            //延时100ms
while (MP3_DREQ == 0);//等待DREQ为高
    wait(200);            //延时100ms
 Mp3SetVolume(50,50);  
    Mp3SoftReset();//vs1003软复位
}
bool CheckVS1003B_DRQ(void)
{
bool bResult;
bResult =MP3_DREQ;
return(bResult);
}
/***********************************************************/
/*  函数名称 :  VsSineTest                                 */
/*  函数功能 : vs1003正弦测试,将该函数放在while循环中,  */
/*              如果能持续听到一高一低的声音,证明测试通过 */                            
/*  参数     :  无                                         */
/*  返回值   :  无                                         */
/*---------------------------------------------------------*/
void VsSineTest(void)
{
Mp3PutInReset();  //xReset = 0   复位vs1003
wait(200);        //延时100ms        
SPIPutChar(0xff);//发送一个字节的无效数据,启动SPI传输
Mp3DeselectControl();  
Mp3DeselectData();     
Mp3ReleaseFromReset(); 
wait(200);               
Mp3SetVolume(50,50);  
 Mp3WriteRegister(SPI_MODE,0x08,0x20);//进入vs1003的测试模式
while (MP3_DREQ == 0);     //等待DREQ为高
 Mp3SelectData();       //xDCS = 1,选择vs1003的数据接口
 //向vs1003发送正弦测试命令:0x53 0xef 0x6e n 0x00 0x00 0x00 0x00
 //其中n = 0x24, 设定vs1003所产生的正弦波的频率值,具体计算方法见vs1003的datasheet
   SPIPutChar(0x53);      
SPIPutChar(0xef);      
SPIPutChar(0x6e);      
SPIPutChar(0x24);      
SPIPutChar(0x00);      
SPIPutChar(0x00);
SPIPutChar(0x00);
SPIPutChar(0x00);
//wait(500);
wait(250);
wait(250);
Mp3DeselectData();//程序执行到这里后应该能从耳机听到一个单一频率的声音
        //退出正弦测试
Mp3SelectData();
SPIPutChar(0x45);
SPIPutChar(0x78);
SPIPutChar(0x69);
SPIPutChar(0x74);
SPIPutChar(0x00);
SPIPutChar(0x00);
SPIPutChar(0x00);
SPIPutChar(0x00);
//wait(500);
wait(250);
wait(250);
Mp3DeselectData();
        //再次进入正弦测试并设置n值为0x44,即将正弦波的频率设置为另外的值
    Mp3SelectData();       
SPIPutChar(0x53);      
SPIPutChar(0xef);      
SPIPutChar(0x6e);      
SPIPutChar(0x44);      
SPIPutChar(0x00);      
SPIPutChar(0x00);
SPIPutChar(0x00);
SPIPutChar(0x00);
//wait(500);
wait(250);
wait(250);
Mp3DeselectData(); 
//退出正弦测试
Mp3SelectData();
SPIPutChar(0x45);
SPIPutChar(0x78);
SPIPutChar(0x69);
SPIPutChar(0x74);
SPIPutChar(0x00);
SPIPutChar(0x00);
SPIPutChar(0x00);
SPIPutChar(0x00);
//wait(500);
wait(250);
wait(250);
Mp3DeselectData();
 }
void test_1003_PlayMP3File();
void TestVS1003B(void)
{
Mp3Reset();
VsSineTest();
Mp3SoftReset();
test_1003_PlayMP3File();
}
//写寄存器,参数,地址和数据
void VS1003B_WriteCMD(unsigned char addr, unsigned int dat)
{
/*
VS1003B_XDCS_H();
VS1003B_XCS_L();
VS1003B_WriteByte(0x02);
//delay_Nus(20);
VS1003B_WriteByte(addr);
VS1003B_WriteByte(dat>>8);
VS1003B_WriteByte(dat);
//delay_Nus(200);
VS1003B_XCS_H();
*/
Mp3WriteRegister(addr,dat>>8,dat);
}
//读寄存器,参数 地址 返回内容
unsigned int VS1003B_ReadCMD(unsigned char addr)
{
/*
unsigned int temp;
unsigned char temp1;
VS1003B_XDCS_H();
VS1003B_XCS_L();
VS1003B_WriteByte(0x03);
//delay_Nus(20);
VS1003B_WriteByte(addr);
temp=  VS1003B_ReadByte();
temp=temp<<8;
temp1= VS1003B_ReadByte();
temp=temp|temp1;;
VS1003B_XCS_H();
return temp;
*/
return(Mp3ReadRegister(addr));
}
//写数据,音乐数据
void VS1003B_WriteDAT(unsigned char dat)
{
//VS1003B_XDCS_L();
//VS1003B_WriteByte(dat);
//VS1003B_XDCS_H();
//VS1003B_XCS_H();
   Mp3SelectData();
SPIPutChar(dat);
Mp3DeselectData();
Mp3DeselectControl();
}
//开启环绕声
void VS1003B_SetVirtualSurroundOn(void)
{
uchar ucRepeatCount;
uint uiModeValue;
ucRepeatCount =0;
while(1)//写时钟寄存器
{
uiModeValue = VS1003B_ReadCMD(0x00);
if(uiModeValue & 0x0001)
{
break;
}
else
{
uiModeValue |= 0x0001;
VS1003B_WriteCMD(0,uiModeValue);
}
ucRepeatCount++;
if(ucRepeatCount++ >10 )break;
}
}
//关闭环绕声
void VS1003B_SetVirtualSurroundOff(void)
{
uchar ucRepeatCount;
uint uiModeValue;
ucRepeatCount =0;
while(1)//写时钟寄存器
{
uiModeValue = VS1003B_ReadCMD(0x00);
if(uiModeValue & 0x0001)
{
break;
}
else
{
uiModeValue |= 0x0001;
VS1003B_WriteCMD(0,uiModeValue);
}
ucRepeatCount++;
if(ucRepeatCount++ >10 )break;
}
}
//增强重音
//入口参数1.强度0-15
//2.频率0-15 (X10Hz)
void VS1003B_SetBassEnhance(uchar ucValue, ucFrequencyID)
{
uchar ucRepeatCount;
uint uiWriteValue;
uint uiReadValue;
ucRepeatCount =0;
uiWriteValue = VS1003B_ReadCMD(0x02);
uiWriteValue &= 0xFF00;
uiWriteValue |= ucValue<<4;
uiWriteValue &= (ucFrequencyID & 0x0F);
while(1)//写时钟寄存器
{
VS1003B_WriteCMD(2,uiWriteValue);
uiReadValue = VS1003B_ReadCMD(0x02);
if(uiReadValue == uiWriteValue)
{
break;
}
ucRepeatCount++;
if(ucRepeatCount++ >10 )break;
}
}
 uint uiVolumeCount;//当前音量值
//VS1003初始化,0成功 1失败
unsigned char VS1003B_Init()
{
unsigned char retry;
/*
PORT_INI();
DDRB|=0xa0;
VS1003B_DDR &=~(1<<VS1003B_DREQ);
//delay_Nus(50);
VS1003B_XCS_H();
VS1003B_XDCS_H();
VS1003B_XRESET_L();
VS1003B_Delay(0xffff);
VS1003B_XRESET_H();//使能芯片
VS1003B_SPI_Low();//先以低频操作
VS1003B_Delay(0xffff);//延时
*/
Mp3Reset();
retry=0;
while(VS1003B_ReadCMD(0x00) != 0x0800)//写mode寄存器
{
VS1003B_WriteCMD(0x00,0x0800);
if(retry++ >10 )break;//{PORTB|=_BV(PB1);break;}
}
retry=0;
/*while(VS1003B_ReadCMD(0x02) != 0x75)//写mode寄存器
{
VS1003B_WriteCMD(0x02,0x75);
if(retry++ >10 )break;//{PORTB|=_BV(PB1);break;}
}*/
retry=0;
while(VS1003B_ReadCMD(0x03) != 0x9800)//写时钟寄存器
{
VS1003B_WriteCMD(0x03,0x9800);
if(retry++ >10 )break;
}
retry=0;
//while(VS1003B_ReadCMD(0x0b) != 0x1111)//设音量
//{
//VS1003B_WriteCMD(0x0b,0x1111);
//if(retry++ >10 )break;
//}
while(VS1003B_ReadCMD(0x0b) != uiVolumeCount)//设音量
{
VS1003B_WriteCMD(0x0b,uiVolumeCount);
if(retry++ >10 )break;
}
//VS1003B_SPI_High();//提高速度,全速运行
if(retry > 10)return 1;
return 0;
}
//VS1003软件复位
void VS1003B_SoftReset()
{
VS1003B_WriteCMD(0x00,0x0804);//写复位
//VS1003B_Delay(0xffff);//延时,至少1.35ms
wait(2);
}
void VS1003B_Fill2048Zero()
{
unsigned char i,j;
for(i=0;i<64;i++)
{
if(CheckVS1003B_DRQ())
{
Mp3SelectData();
for(j=0;j<32;j++)
{
VS1003B_WriteDAT(0x00);
}
Mp3DeselectData();
}
}
}
void test_1003_PlayMP3File() 
{
   unsigned int data_pointer;unsigned char i;
unsigned int uiCount;
uiCount = sizeof(MusicData);
data_pointer=0; 
VS1003B_SoftReset();
    while(uiCount>0)
  { 
  if(CheckVS1003B_DRQ())
      {
    for(i=0;i<32;i++)
           {
     VS1003B_WriteDAT(MusicData[data_pointer]);
     data_pointer++;
            }
uiCount -= 32;
         }
    }
VS1003B_Fill2048Zero();
}

调试过程详见:http://www.51hei.com/mcu/758.html

关闭窗口
以上是VS1003 VS1053B电路图分析及程序的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>