极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 26083|回复: 7

【分享】音频编解码芯片VS1003(播放器调试)

[复制链接]
发表于 2013-3-22 11:13:43 | 显示全部楼层 |阅读模式
本帖最后由 黄帅-深圳市源合 于 2013-5-14 16:21 编辑

在调试vs1003之前就已经翻阅过vs1003的datasheet(数据手册,帖子下方有);基本上懂了其通讯原理,和一些基本设置。
  在调试的时候只是拿网上找的代码,做了相应的修改(接口改为我自己的,功能改为我自己想要的功能),这样只是为了快速测试我的vs1003模块能不能用,当然这首先是要你能理解其代码,要不然是第一次调试你也不知道是程序有错还是硬件有错。在确定程序没错之后,我就可以确定如果没有效果,那肯定是我的解码模块不行。测试通过之后我就可以放心的使用我自己的解码模块。接下来的程序我就可以根据自己想要的慢慢来写。
  第一次写程序进去就听到耳机里输出了很高的鸣叫声,这是因为我把正弦测试(vs1003自带的一种测试,这样就能很快确定你的vs1003是否能工作)频率调的很高 所以声音很尖,被吓了一次。第二次就把它改小了一点,嘟的一声,呵呵相当激动,这说明我的vs1003可以用(s1003非常脆弱 很容易坏 又贵又不好买)
  正弦测试成功之后我就开始想给vs1003发送MP3音频数据 看能不能解码放出声音来
  我最初的想法是通过winhex软件打开查看MP3代码然后拷贝出来作为一个数组发给vs1003。这个数据要储存在我的单片机的程序储存区里,还好我的单片机程序储存区够大有64K。这样多的MP3代码也只能够听到一点点声音,效果肯定是无法体会的道。果然 ,在耳机里只听到吱~的一声就没了 根本没用
  之后我就想把sd卡加进来,让MCU一边从sd里读取MP3数据,再一边发送到vs1003里边去解码,这样就可以一直把一首MP3的数据全部发送到vs1003进行解码。于是我先拷贝了一个码率比较低的MP3,因为单片机的速度毕竟很慢 从sd卡里读取数据然后又要发送给vs1003解码 先找一个码率比较低的MP3做测试这是明智的选择。
开始组合程序,编写相应的主函数,通电测试。没有任何反应,串口调试(如果读写sd正常可以从串口接收到sd'卡的第0扇区数据(逻辑扇区)这是我程序特意设定的,为了方便看出sd是否在工作)也接收不到任何数据 ,确定sd卡未启用。我以为sd卡的读写又出问题了 ,拿之前做好的sd测试程序重新测试,也没有数据输出,很晕。
不经意间我发现当我拔掉解码模块sd卡读写正常,找到这一重要点之后,我开始分析问题。
  因为我的sd卡和vs1003与MCU的通讯方式都是spi。而我的MCU只有一个硬件spi,所以都统一连接到一起了 只是通过不同的片选让它们轮流使用spi。可惜的是这样不行。经过多次试验,猜想,也在网上寻求答案(未果)。最终我自己搞明白了,是应为我用的MCU为5V器件,为了能跟vs1003、sd卡正常通讯 ,我把MCU的spi口设置成为开漏形式,让后加3.3v的上拉。这样我的单片机spi口最大电压也只能是3.3v了。不过同时开漏形式让它的驱动能力变得很弱,无法同时接两个spi通讯模块~~~
于是我把sd卡的接口换到P0口采用软件模拟spi读取数据,这样一来,呵呵串口可以看到接收到数据了随之耳机里传来了久违的音乐,不过声音很乱,就像快进一样。还是很兴奋 ,毕竟是能出声音了。
为什么声音会乱掉,这个时候开始找问题,一直花了我两天的时间,vs1003的datasheet看了一遍又一遍 ,敢肯定我的程序绝对是没错。那就是硬件了。
分析它的原理开始查问题,看看是那步错了。
  vs1003解码MP3数据,你只要把正确的MP3数据传送给它,它就能自动识别你的MP3是多少码率的,然后通过一定的解码速率进行解码。这个时候就有疑问了,既然解码的速率确定了,为了能流畅的播放出音乐来,你给vs1003发送MP3数据的速率必须跟它解码的速率一样,那怎么去保证这两个速度一样呢?如果送给vs1003的数据过快,那我们可以加延时让它一样,那这时候又出问题了,难道每一首不同码率的歌都要去加个延时吗(这里是按发送数据永远比解码速率快的情况来分析),这样肯定是不合理的。不用担心,vs1003为用户准备了0.5k的数据缓冲区做为音频数据的缓冲,这就好像一个漏斗一样,0.5k空间就像漏斗的容量,你只要保证漏斗里边始终有东西,那么漏斗底下就始终有东西流出,保持连续。你给漏斗加料的速度无所谓,只要你别让漏斗里边为空就行。vs1003是一样的为了解码正常,播放流畅,你只要保证数据缓冲区里始终有数据作为待解码对象,这样就可以放出流畅的音乐来。这里又有问题了,我们怎么确定数据缓冲区里到低有没有数据,或者是还有多少,怎么控制发送数据。vs1003也帮你考虑到这一点了,所以他专门设定了一个中断脚DREQ,当DREQ变高时,外部可以至少为vs1003发送 32字节的数据(这是SDI数据,还有一种SCI数据,这里不说了),为了保证播放流畅。当vs1003收到32字节的数据之后他的DREQ脚变为低,此时可以暂时不往里边发送数据,如果数据缓冲区内少于32字节的有效数据,那么vs1003将DREQ置为高电平,此时需要往里边发送数据(对于DREQ脚的变化,网上有异议,这是我个人的理解)。这里你会发现,我之前不是说数据缓冲区是0.5k,为什么每次才32个数据就可以了。vs1003只是设置了一个32byte为标准,当然 你可以当在检测到DREQ脚变高时,往里边一次性发送少于(这是必须的)0.5k的字节,然后再去检测DREQ的状态,当再次变高时 你就可以再往里边发送那么多数据,是可以的。32byte只是一个最低标准。个人理解~~
按这个寻到问题的根源~~~我的DREQ没有在工作,屏蔽了他 播放跟本没变,所以说,我的MCU无法判断vs1003的数据区是否满了 是否需要新数据,这里只是一股脑的往vs1003里灌数据
所以导致我的音乐播放不正常,测量初始化之后的vs1003的DREQ脚,发现竟然出现1.8v,不高不低,处于模糊状态。
确定DREQ脚不能工作,网上寻求答案,对我的情况都没用。之后又翻到pcb图上去,发现一个很重要的地方未连接,就是当用spi模式给vs1003发送数据的时候,其串口RX必须接到IOVDD.
我把那条线补上去,初始化vs1003一测DREQ脚为3.3(高)。很是激动,DREQ可以工作了,那么音乐播放就可以了,哈哈。下载程序测试。
一切OK!!!!
  交流Q 380100225 TEL13751145915

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

发表于 2013-3-23 00:31:16 | 显示全部楼层
一直在找教程,能不能发一下你的源码、照片或者视频?谢谢了~
回复 支持 反对

使用道具 举报

发表于 2013-3-23 03:04:14 | 显示全部楼层
这种自我探索的经验很难得,谢谢楼主无私分享
回复 支持 反对

使用道具 举报

发表于 2013-3-25 14:08:08 | 显示全部楼层

好消息   世界上最集成的音频编解码芯片VS1005已经量产上市。 欢迎咨询  QQ2355355260。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-4-10 10:17:11 | 显示全部楼层
本帖最后由 黄帅-深圳市源合 于 2013-4-10 10:19 编辑

用MSP430F149(MCLK=SMCLK=8M,SPI高速2分频,低速8分频)和VS1003B、12864做MP3 下附代码:
  1. if(CurrentOffset<(SectorsPerCluster))
  2. {
  3. ReadSectorFromCluster(CurrentCluster,CurrentOffset);
  4. WriteDataToVs1003();
  5. if(IndexFlag)
  6. {
  7. VS1003B_ReadBitRate();
  8. if(BitRate>99)
  9. LCD_DisNum(0,0,BitRate);
  10. else
  11. LCD_DisNum(0,1,BitRate);
  12. IndexFlag=0;
  13. }
  14. CurrentOffset++;
  15. }
  16. else
  17. {
  18. CurrentOffset=0;
  19. CurrentCluster=FindNextCluster(CurrentCluster);
  20. if(CurrentCluster==0x0ffffff8 || CurrentCluster==0x0fffffff)
  21. {
  22. switch(mode)
  23. {
  24. case Repet_All:
  25. if(CurrentAudioFileIndex==AudioFileNumber)
  26. CurrentAudioFileIndex=1;
  27. else CurrentAudioFileIndex++;
  28. break;
  29. case Repet_One:
  30. CurrentCluster = GetAudioFile( CurrentAudioFileIndex);
  31. LCD_Print(3,3,Filestyle);
  32. CurrentOffset=0;
  33. break;
  34. case Shuffle :
  35. uint rand_val = TAR;
  36. srand(rand_val);
  37. CurrentAudioFileIndex = rand()%AudioFileNumber + 1;
  38. CurrentOffset=0;
  39. break;
  40. }
  41. LCD_Print(2,1," ");
  42. GetShortAudioFileName(CurrentAudioFileIndex);
  43. LCD_Print(2,1,ShortFileName);
  44. }
  45. }
  46. }
  47. .读取比特率和解码时间.spi的速率,变成8分频,也就是1M下附代码:
  48. uchar ReceiveByte0() //read one byte from spi port
  49. {
  50. unsigned char temp=0;
  51. while ((IFG1 & UTXIFG0)==0); // USCI_A0 TX buffer ready?
  52. U0TXBUF =0xff; //8 clocks
  53. temp=U0RXBUF;
  54. return temp;
  55. }

  56. uint VS1003B_ReadCMD(unsigned char addr)
  57. {
  58. uint temp;
  59. while(VS1003B_NeedData()==0);
  60. SPI0_Low();
  61. VS1003B_XDCS_H();
  62. VS1003B_XCS_L();
  63. SendByte0(0x03);
  64. SendByte0(addr);
  65. temp = ReceiveByte0();
  66. temp <<= 8;
  67. temp += ReceiveByte0();
  68. VS1003B_XCS_H();
  69. SPI0_High();
  70. return temp;
  71. }

  72. uint VS1003B_ReadDecodeTime()
  73. {
  74. return VS1003B_ReadCMD(0x04);
  75. }

  76. uint VS1003B_ReadBitRate(void)
  77. {
  78. uint HDAT0,HDAT1;
  79. HDAT0=VS1003B_ReadCMD(0x08);
  80. HDAT1=VS1003B_ReadCMD(0x09);
  81. switch(HDAT1)
  82. {
  83. case 0x7665:return 0;//WAV格式
  84. case 0X4D54:return 1;//MIDI格式
  85. case 0X574D://WMA格式
  86. {
  87. HDAT1=HDAT0*2/25;
  88. if((HDAT1%10)>5)return HDAT1/10+1;
  89. else return HDAT1/10;
  90. }
  91. default://MP3格式
  92. {
  93. HDAT1>>=3;
  94. HDAT1=HDAT1&0x03;
  95. if(HDAT1==3)HDAT1=1;
  96. else HDAT1=0;
  97. return BitRate_Table[HDAT1][HDAT0>>12];
  98. }
  99. }
  100. }
复制代码
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-5-16 16:09:19 | 显示全部楼层
stm32 与VS1003的接口设置
第一点,STM32的端口设置,设置为SCK和MOSI复用推挽,而片选设为推挽输出即可,MISO设为input floating即可。
第二点,因为VS1003控制寄存器是八位数据读写的,所以STM32需要设置发送和接收数据也是八位的。
第三点,根据VS1003的时序关系,需要设置STM32的时钟信号的相位和极性为CPOL为0,CPHA为0。
第四点,NSS模式需要设置软件模式,这样就可以利用另作他用了,可以用GPIO口控制作为片选了。
  1. void  SPI1_Init(void)
  2. {   
  3.      SPI_InitTypeDef SPIStruct_Init;
  4.      SPIStruct_Init.SPI_Direction = SPI_Direction_2Lines_FullDuplex;    //配置SPI为全双工模式
  5.      SPIStruct_Init.SPI_Mode = SPI_Mode_Master;        //配置SPI为主模式
  6.      SPIStruct_Init.SPI_DataSize = SPI_DataSize_8b;    //配置SPI为8位数据传送
  7.      SPIStruct_Init.SPI_CPOL = SPI_CPOL_Low;           //配置CPOL为低
  8.      SPIStruct_Init.SPI_CPHA = SPI_CPHA_1Edge;         //配置CPHA为第一个上升沿
  9.      SPIStruct_Init.SPI_NSS = SPI_NSS_Soft;            //配置NSS为软件控制
  10.      SPIStruct_Init.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;   //配置SPI时钟预分频
  11.      SPIStruct_Init.SPI_FirstBit = SPI_FirstBit_MSB;   //配置传输字节高位在前
  12.      SPIStruct_Init.SPI_CRCPolynomial = 7;             //配置CRC,可不用理
  13.      SPI_Init(SPI1,&SPIStruct_Init);                   //SPI初始化函数   
  14.      SPI_Cmd(SPI1, ENABLE);                            //使能SPI
  15. }
  16. void Mp3WriteRegister(uint8_t addressbyte,uint8_t high,uint8_t low)
  17. {         
  18. Mp3DeselectData();   //释放数据端口
  19. Mp3SelectControl();  //选择控制端口
  20.       
  21.         while(!SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)); //判断发送缓冲器是否为空   
  22.         SPI_I2S_SendData(SPI1,VS_WRITE_COMMAND);    //发送写寄存器命令
  23.             
  24.         while(!SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE));
  25.         SPI_I2S_SendData(SPI1, addressbyte);        //发送寄存器的地址
  26.            
  27.         while(!SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE));
  28.         SPI_I2S_SendData(SPI1, high);              //发送参数的高八位
  29.       
  30.         while(!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE));
  31.         SPI_I2S_SendData(SPI1, low);              //发送参数的低八位      
  32. Mp3DeselectControl();
  33. }



  34. /*************************************************************/
  35. /*  函数名称 :  CheckVS1003B_DRQ(void)                             */
  36. /*  函数功能 : 判断DREQ引脚状态                             */
  37. /*-----------------------------------------------------------*/
  38. bool CheckVS1003B_DRQ(void)
  39. {
  40. bool bResult;
  41. bResult =GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_4);
  42. return(bResult);
  43. }
复制代码
回复 支持 反对

使用道具 举报

发表于 2014-9-3 10:45:08 | 显示全部楼层
新手求教:楼主能给个软件模拟SPI的教程吗?
回复 支持 反对

使用道具 举报

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

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-3-29 15:09 , Processed in 0.047354 second(s), 23 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

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