记录一下:DIY 固态CD WAV播放器遇到的讨厌“咯咯”噪声。
材料清单如下:AT91sam7s256 最小系统板一块
SD卡 一张
TDA1543 一块
DIY步聚如下:
步聚1:
用双路PWM模拟DAC播放8位双声道wav文件。
用耳机试听,低频段的低音丰富,仅是高频段有点生硬,解析度不够。大喜过望。
在这过程碰到一个问题,就是在用spi 读sd卡,缓冲区设定为4096(4k),当读卡时钟在12M,产生了非周期性的咯咯声。
把缓冲区开到极限30K,结果依旧。但是当spi的时钟提高到24M时,咯咯声完全消失。
步聚2:
再测试用PWM模拟双8位DAC读取16位wav文件效果,spi的时钟24M。效果同上。
步聚3:
接上外挂IIS接口的TDA1543 DAC,开通ssc 时钟,使用ssc中断,没有用DMA.
试听结果,音质有了质的飞跃。
但是又碰到了那该死的咯咯声,有点象火车声,这时的缓冲区为4096(4k)。
当缓冲区开足到极限30K(30K*2=60K)时,咯咯声的周期变成大约一秒左右,一秒咯一次,并且居然有回音效果。
用示波器测量TDA1543的5v输入电源,脉冲噪声竟高达50mv, 加上一只电感和超大的滤波电容,并上小瓷片,很难完全消除。
超级的郁闷,特此记录。 http://cache.amobbs.com/bbs_upload782111/files_36/ourdev_618293DH87FN.jpg
AT91SAM7s256最小系统板连接TDA1543.jpg (原文件名:AT91SAM7s256最小系统板连接TDA1543.jpg)
http://cache.amobbs.com/bbs_upload782111/files_36/ourdev_618294ISPKCS.jpg
最小系统板的近照.jpg (原文件名:最小系统板的近照.jpg)
http://cache.amobbs.com/bbs_upload782111/files_36/ourdev_618295CBU2G7.jpg
用到的调试设备仪器.jpg (原文件名:用到的调试设备.jpg)
http://cache.amobbs.com/bbs_upload782111/files_36/ourdev_618296AWAOU3.jpg
PC机与板子的交互调试界面 (原文件名:人机交互调度通信界面.jpg)
http://cache.amobbs.com/bbs_upload782111/files_36/ourdev_618297XGKTSI.jpg
兵兵读代码.jpg (原文件名:兵兵读代码.jpg)
http://cache.amobbs.com/bbs_upload782111/files_36/ourdev_618298GY4Z99.jpg
兼容XP自带媒体播放器的WAV头文件代码.jpg (原文件名:兼容XP自带媒体播放器的WAV头文件代码.jpg) 调试读写SD卡时间的记录
AT91sam7s256 主时钟47.932M 单条指令时间1M/47.932M=1000ns/47.932=20.86ns
CD采样频率是44.1k 周期时间=22.6us
----------------12M读卡---------------------
SPI 时钟 设定为47.932/4 =12M
BUFSIZE 3072最大读时间是:14ms , 最小12ms 。
14000/3072=4.5us(每字节)若是8位双声道为9us ,若是16位双声道数据,再乘以2 得18us
以最大的14ms 计得:
22.6us - 18us = 4.6us
在中断服务程序中可运行: 4600 ns/20.86ns = 220 条单周期指令
----------------24M 读卡-------------------
SPI 时钟 47.932M/2 =24MHz
BUFSIZE 3072最大读时间是:12.5ms12500/3072=4.06us 双声道为8.12us若是16位数据,再乘以2 得16.24us
最小10.7ms
以最大的12.5ms 计得:
22.6us - 16.24us = 6.4 us
在中断服务程序中可运行:6400ns/20.86ns = 306 条单周期指令 1.咯咯声是因为断流, 数据跟不上, 建议SSC使用DMA, 开启自动装载.
2.兼容XP自带媒体播放器的WAV头文件代码感觉写得不好, 某些wav文件头可能会比较大, 查找"fmt" "data"等chunk会比较慢. 建议改写修改库函数strstr来查找chunk 原先是使用字符串库读写,对于xp自带的媒体播放器生成的WAV格式根本就出错。
再者 WAV的文件头不会超过100K吧?
假设是100K,对于24M的SPI 时钟,反应时间:4.06us *100K=406 ms =0.4秒。
特注:
以上这些图片显示的关键算法代码是本人原创。
不经本人同意,任何人不得转载用于要注_册并要扣积分下载的网站。
特别是一些变态的还要至少上传多少个技术贴子才能下载的网站! 非也,WAV头只在头一扇,从fmt到data+4止。data+1~4(int32)是从data+4开始到soundend的字符大小。
我开2K DMA BUFFER ,主频45MHZ, 96khz时断流,4秒/次。 咯咯火车声是由于中断服务时间过长造成的,改写服务程序后咯咯声消除。
上示波器实测图片:
http://cache.amobbs.com/bbs_upload782111/files_36/ourdev_618416L32WFA.JPG
用PWM-DAC播放正常的中断服务程序时间.JPG (原文件名:用PWM-DAC播放正常的中断服务程序时间.JPG)
http://cache.amobbs.com/bbs_upload782111/files_36/ourdev_618417ZXX5HF.JPG
IIS中断非DMA服务时间过长播放不正常.JPG (原文件名:IIS中断非DMA服务时间过长播放不正常.JPG)
http://cache.amobbs.com/bbs_upload782111/files_36/ourdev_618418L8WY5R.JPG
重新改写IIS非DMA中断服务程序后正常播放的时间.JPG (原文件名:重新改写IIS非DMA中断服务程序后正常播放的时间.JPG) 由图上看出:5.2us 正常;9.2us 火车咯咯声;2.4us 正常。符合本人在2楼所作的计算分析。
并由此推得SPI的时钟下降到12M也能正常工作。 IIS接口的DAC硬件基本调试完毕,余下的就是把18.432M的晶振换成16.9344M,改写一下启动代码。
对于人机界面,打算用带EEPROM的AVR mega16来做,通过串口发送接收命令,开机时通过存储wav 结尾后缀的歌名,做成菜单点菜任意排序的形式。
这样现有的整个播放WAV的程序框架就不用作任何的修改。另外再加入红外摇控,触摸控制,对于红外摇控器,就直接做成智能学习识别现有电视机或
DVD机的摇控器按键,存储入M16中去,而电阻触摸屏直接挂在mega16的AD转换IO口上。整个系统就用两块MCU作控制,这样设计耦合度低,方便日后更
换更好的MCU。过些日子再找时间把MP3的压缩与解压程序移植入来。
其实许多年前自已就想DIY一台固态CD WAV播放器,只因工作中项目的关系,一直没有时间。
用PWM作DAC播放WAV格式早在三年前就用AVR完成。读写SD卡的源码也是老外基于AVR的开源程序,个人经历过的所有开源的FAT16/FAT32读写源码中,
基于AVR的是最完整并最容易明白的。
从AVR移植到ARM7中,一开始是使用LPC2124,只是LPC的ARM7系列都不带IIS音频接口,因此仅是移植成功PWM DAC播放后就没有作进一步的研究改进。
今年春节与老同学们聚会,发觉他们竟然还为CD机不能读碟非要本人推荐款好点的CD机。就暗暗下了决心,在明年的春节定要DIY一种有钱也买不到的
固态CD机来。在日后聚会中好让他们以抽签的方式增送(非卖品)。
本人没啥大本事,但是顺手捏几个电子零件,花区区数百元的成本,就能做出比拼市场上数十万元的超级音响来。
这也是DIY 固态CD WAV播放器的动力来源。
看看市面上的顶级音响价值:
一台发烧级CD : 4万 (RMB)
一台单声道纯甲类后级:18万(RMB)双声道:36万
其实我们电工真的很富有。 回复【8楼】zhousd 银河一号
iis接口的dac硬件基本调试完毕,余下的就是把18.432m的晶振换成16.9344m,
-----------------------------------------------------------------------
内部倍频到多少?
音质和PWM方式有多少区别? 用原板子上的18.432M晶振,倍频到47.932M ,分频比17,目前的实测频率是44.06K。
若用CD机上专用的频率:16.9344M 主时钟:16.9344M*3 =50.8032M
IIS分频比: 16.9344M*3 =50.8032M/1.4112M = 36 刚好是整数分频。
若主时钟降一倍: 16.9344M*2 =33.8688/ 1.4112M = 24
若DMA传送: 主时钟不用倍频 16.9344M/ 1.4112M = 12
对于音质的比较:
得先说说本人的听音耳朵的级别:木耳,金耳,还是其它?
本人其实可以听到40K连续发射的超声波(非倒车雷达探头的哒哒声),
这里面有一个小故事,话说当年在做汽车全封闭多普勒超声波防盗器时,竟然发觉自已
能出听到超声探头的吱吱声,当时的研发,设计和生产都在同一车间,就跟女孩子们打赌,
放两只探头在两耳边,听出哪一个在加电发射。赢了就得给一个吻,哈,哈。。。。
所以嘛本人的耳朵属于钻石级别。
对于音频的开关失真产生的谐波非常敏感,并且本人10多年前DIY过纯甲类(水冷降温)全晶体管功放,
听过其甜美百听不心烦的效果。
DAC的滤波器,参考的是小日本一玩家用TDA1543制作获得冠军的LCR电路,把其输入到EWB10 仿真分析,发觉在20K频段附近有小微的提升。
由于手上没有其对应数值的电感,只能把其参数稍作改动。频率特性曲线基本上与其相同。
直接用耳机试听,听了半小时,没感觉到有心烦(可能是功率不够)。
再打开电脑,听同一首歌,听了10分钟,明显感到是被运放中的谐波失真搞烦了。
再把其输入到很普通的后级功放,开机试听,兴奋得眼睛都开始潮湿了,人声和笛子悠扬的换气声。
这一刻的心情很难用语言表达形容。
至于PWM做的DAC由于解析力只有8位仅有256级,不在发烧之列,不评也罢。一句话--->干硬。 下一步的计划就是整IIS是索尼格式的TDA1543A DAC。
并且要追踪解决RAM中加载调试时IIS偶然会难以复位而产生的沙沙刺耳噪声。 回复【11楼】zhousd银河一号
下一步的计划就是整iis是索尼格式的tda1543a dac。
并且要追踪解决ram中加载调试时iis偶然会难以复位而产生的沙沙刺耳噪声。
-----------------------------------------------------------------------
1543A 问题也不大,很好解决。 银河兄同道中人,而且很幸福,有副金耳朵,还有这么多设备仪器用。小弟很馋啊,呵呵。
俺木耳,外加耳鸣,手头上也没什么像样的仪器,就一破万用表,整那播放器完全靠盲调。还好谢天谢地比较顺利。发烧是烧不起来了,纯粹自娱自乐,不过也是乐在其中。
感觉银河兄对音响有很深的认识,有机会还要多跟兄台学习。 人各有志,我没啥特别的爱好,就喜欢玩电子。身边朋友们的钱都花去购买小车和楼房。
但是我却把这些钱的一部份用来购买仪器设备,另一部份用来打的士(若和家里人一起出外玩,规划大约1万/年,平时还是挤大巴),
其余的全投入到基金中去。这样就可以做自已喜欢的事了。 回复【5楼】90999 张耀扬
非也,wav头只在头一扇,从fmt到data+4止。data+1~4(int32)是从data+4开始到soundend的字符大小。
我开2k dma buffer ,主频45mhz, 96khz时断流,4秒/次。
-----------------------------------------------------------------------
"非也, wav头只在头一扇"---- 见过wav头占用1024字节的
http://cache.amobbs.com/bbs_upload782111/files_36/ourdev_619899RXU7X5.JPG
(原文件名:1.JPG) mark~~ 加载到RAM中调试出现偶尔难以复位的刺耳噪音,是由于初始化IIS接口过早开启了TXEN引起。
把其初始化顺序调整后就再没有出现过。
------------------------
在此不得不提到下载了让人恼火不合格的‘方波’WAV音频测试文件。
用下载的方波音频文件在SD卡上作循环加载测试,把示波器接在DAC的输出端竟然观测到有相移脉冲跳动,
周期频率是44.1k,这时开始怀凝MCU内部硬件IIS的续流能力?
仔细检查了程序,没发现有任何不合理的问题。
再怀凝由于PLL锁相噪声引起?用示波器监测试了几天,未果。
到最后,不得不怀凝起下载的方波音频测试文件的正确性?
通过以下对方波简单的计算分析,
1K 方波: 周期时间 = 1ms 半波时间= 0.5ms =500us
44.1k 采样率:周期时间 = 22.67us 半波时间=11.337us
500us/11.337us =44.103783... 是没法除尽的。
因此,从数学上证明了下载的音频测试文件中的1K方波,在输出端必然会产生相位跳动噪声。
用winHEX工具打开测试文件分析其数据,发现竟然有本底噪声,这时恍然大悟,
原来下载的1K方波WAV文件是经由硬件信号发生器产生,再经电脑的A/D录制生成,难怪会产生相位跳动。
为了验证这个推论计算,同时也必需验证MCU内部的IIS是否会产生断流。
马上用matlab 生成无相位跳动的方波WAV文件,转入到SD卡中。
重新加载测试,我的天啊!从示波器上观测到的方波实在是太纯净太稳定了!这方波可爱到了极点!
至此,在DAC输出端得到了真正理想无相噪跳动的方波。
也终于全部完成了微控器AT91SAM7SXXX 内部硬件IIS接口外挂DAC的所有测试。
后续工作的重点部分的就是重新设计调整DAC的输出滤波器。 基于AT91SAM7S64的经济版终于完成了。
功能如下:
目录循环播放:
设有四只按键(中断方式):(快进一曲,快退一曲,播放/停止,CD目录选择)
通过串口打印时间信息与接收命令(可与另一MCU通信并由其负责键盘扫描和显示),实现按健显示部份零耦合。
三只发光二极管指示选择的CD目录,每个目录最多可存99首歌曲。
名字统一:Track01 ,Track02 .....Track99
打算整几个版本:
1。经济版
2。有万年历用电池供电续行半年以上,并由点阵液晶显示的超低功耗版
3。界面真彩屏显示带摇控功能的超豪华版
呵呵,终于拥有了超一流的音源。 呵呵,恭喜银河兄!
俺的那个算什么版呢?
我觉得是搭棚版。。。,现在买了个外壳,不过还没时间把板子弄进去。
现在每天晚上都听,比我那IAUDIO 7 MP3(也是播放FLAC,爱欧迪的音质口碑相当不错,就是有点白开水,不温不火,开所谓的BBE对无损来说只是弄巧成拙,声音相当不自然)音质可好多了,听多久都不累,解析力明显上一个档次.
就是太”壮观“了,4块板子拼起来。。。
那IAUDIO 7花了 1200大洋,而这个播放器加起来不到500,当然咱就是俗一点比比价格满足一下成就感,真的说是没有可比性。 回复【18楼】zhousd 银河一号
-----------------------------------------------------------------------
是3只LED数码管吧?
按键的处理我也是放在定时器的中断中处理,产生长按和短按的按键值.这样主流程中使用起来非常方便。 因数码管体积太大,接线又多,所以用三只发光二极管作CD目录切换指示。
整个程序目前没有用到定时器中断。
按键处理是用外部边沿中断,平常不按键时,键值是零,当有按健按下,触发了IO中断,在IO中断服务中置相应的键值后立即返回。
然后在每次读SD卡声音数据之前处理键值,因快进一曲,快退一曲,都有关闭文件的动作,关闭时肯定会静音,既然这时不播放了,
就可以加入一些任意的软件延时。
目前只有DMA中断和兵兵程序,若不用兵兵算法,可以开通软中断,并在DMA中断服务中触发软中断实现切换读SD卡声音的数据。
而中断优先级DMA 设为最高级 7 ,软中断为6。
这样上层的代码就可以随便写而不必再管时序是否会存在问题了。 强。以后有空了做 回复【21楼】zhousd 银河一号
-----------------------------------------------------------------------
使用定时器定时扫描按键的好处是可以进行任意时间长短按键的区分,而又不占用主流程的时间,处理也非常方便。比如习惯上来说快进、快退功能就是长按上一曲、下一曲键。 回复【15楼】cheungman
回复【5楼】90999 张耀扬
非也,wav头只在头一扇,从fmt到data+4止。data+1~4(int32)是从data+4开始到soundend的字符大小。
我开2k dma buffer ,主频45mhz, 96khz时断流,4秒/次。
-----------------------------------------------------------------------
"非也, wav头只在头一扇"---- 见过wav头占用1024字节的
(原文件名:1.jpg)
-----------------------------------------------------------------------
太夸张了......... 回复【24楼】90999 张耀扬
回复【15楼】cheungman
回复【5楼】90999 张耀扬
非也,wav头只在头一扇,从fmt到data+4止。data+1~4(int32)是从data+4开始到soundend的字符大小。
我开2k dma buffer ,主频45mhz, 96khz时断流,4秒/次。
-----------------------------------------------------------------------
"非也, wav头只在头一扇"---- 见过wav头占用1024字节的
(原文件名:1.jpg)
-----------------------------------------------------------------------
太夸张了............
-----------------------------------------------------------------------
呵呵, 我手头有两首wav文件头占用1024字节的, 一首是24bit, 44.1KHz的wav, 一首是24bit, 96KHz的wav IIS接口定义是怎样的?是专为音频DAC设计的不?谁有这方面的资料? 回复【26楼】hefanghua
iis接口定义是怎样的?是专为音频dac设计的不?谁有这方面的资料?
-----------------------------------------------------------------------
是专门设计的数字音频传输接口,主要有3个信号:字时钟,位时钟,数据。标准IIS接口数据左对齐,MSB优先;字时钟和采样率相同;字长度可变;字时钟比MSB提前一位跳变。 回复【25楼】cheungman
-----------------------------------------------------------------------
呵呵, 我手头有两首wav文件头占用1024字节的, 一首是24bit, 44.1KHz的wav, 一首是24bit, 96KHz的wav
-----------------------------------------------------------------------
估计是带讯息吧,我这里用GOLDWAVE或者千千,FB出来的都是很小的头。 从网上给的WAVE文件格式定义看截图,4字节的10H偏移为16或18,18表示有扩展信息,但这里是16,那么wav文件头占用1024字节又是由哪个决定呢?
另,LZ的读SD卡时间计算好像不对。
CD是44.1k,16bit,2声道,则每次读取需2x16/8=4BYTE, 对于缓存3072Byte可播放的时间为:(1/44100)*(3072/4)≈17.4ms
而读卡并装满该缓存需花“最大读时间是:14ms”,只有3.4ms时间处理其它任务,结果是单片机CPU占用率太高,很容易跳帧或者断流。
读卡并填缓存可以放到主程序中,不断判断缓存是否减少,如果减少就从卡里读4字节(虽然每次是1扇区,但每读完4B暂停供应时钟就相当于读4B了)。也要提高读卡的效率才好。 /*
RIFF WAVE Chunk
==================================
| |所占字节数|具体内容 |
==================================
| ID |4 Bytes | 'RIFF' |
----------------------------------
| Size|4 Bytes | |
----------------------------------
| Type|4 Bytes | 'WAVE' |
----------------------------------
*/
__packed struct stRiffHead {
BYTEriffID;
DWORD Size;
BYTEwaveID;
};
/*
Format Chunk
====================================================================
| | 字节数| 具体内容 |
====================================================================
| ID |4 Bytes| 'fmt ' |
--------------------------------------------------------------------
| Size |4 Bytes| 数值为16或18,18则最后又附加信息 |
------------------------------------------------------------------------
| FormatTag |2 Bytes| 编码方式,一般为0x0001 | |
-------------------------------------------------------------------- |
| Channels |2 Bytes| 声道数目,1--单声道;2--双声道 | |
-------------------------------------------------------------------- |
| SamplesPerSec |4 Bytes| 采样频率 | |
-------------------------------------------------------------------- |
| AvgBytesPerSec|4 Bytes| 每秒所需字节数 | |===> WAVE_FORMAT
-------------------------------------------------------------------- |
| BlockAlign |2 Bytes| 数据块对齐单位(每个采样需要的字节数) | |
-------------------------------------------------------------------- |
| BitsPerSample |2 Bytes| 每个采样需要的bit数 | |
-------------------------------------------------------------------- |
| |2 Bytes| 附加信息(可选,通过Size来判断有无) | |
------------------------------------------------------------------------
*/
__packedstruct stFmtChunk {
charfmtID;
DWORD Size;
WORDFormatTag;
WORDChannels;
DWORD SamplePerSec;
DWORD AvgBytesPerSec;
WORDBlockAlign;
WORD BitsPerSample;
char Addtional;
};
/*
Fact Chunk
==================================
| |所占字节数|具体内容 |
==================================
| ID |4 Bytes | 'fact' |
----------------------------------
| Size|4 Bytes | 数值为4 |
----------------------------------
| data|4 Bytes | |
----------------------------------
*/
__packedstruct stFactBlock {
BYTEfactID;
DWORD FactSize;
};
__packedstruct stDataBlock {
BYTEdataID;
DWORD DataSize;
};
struct wavhead
{
struct stFmtChunk fmt;
struct stDataBlockdata;
DWORD dataOffset;
};
typedef struct wavhead wavhead;
/********************************************************************************
读取WAV文件头
********************************************************************************/
void LoadWavHead(FIL *file1,wavhead * head)
{
struct stRiffHeadriff;
struct stFactBlockfact;
UINT br;
//memcpy(head,0,sizeof(struct wavhead));
f_lseek (file1, 0 );
f_read(file1,(BYTE *)&(riff),sizeof(riff),&br);
if(strncmp((char *)riff.riffID, "RIFF", 4) || strncmp((char *)riff.waveID, "WAVE", 4)) return ;
f_read(file1,(BYTE *)(&head->fmt),sizeof(head->fmt)-2,&br);
if(head->fmt.Size==18)f_read(file1,head->fmt.Addtional,2,&br);
//fact block
f_read(file1,&fact,sizeof(fact),&br);
if(strncmp((char *)fact.factID, "fact", 4))
{
//not factblock,check for data
if(strncmp((char*)fact.factID,"data",4)==0)
{
memcpy(head->data.dataID,fact.factID,4);
head->data.DataSize=fact.FactSize;
head->dataOffset=28+head->fmt.Size;
return ;
}
else return;
}
else {
f_lseek(file1,file1->fptr+fact.FactSize);
}
f_read(file1,&head->data,sizeof(head->data),&br);
if(strncmp((char*)head->data.dataID,"data",4))return;
head->dataOffset=36 + head->fmt.Size + fact.FactSize;
} 回复【10楼】zhousd银河一号
-----------------------------------------------------------------------
你听到的应该只是驱动电路谐波产生的差拍频率吧,能听到40k超声波的已经不是人类了。 回:gzhuli 咕唧霖
连续正弦波发射应该不会产生差拍(是否产生谐波差拍没有考究过)。 放在耳边两三厘米远,就能听到发出的嘶嘶声,当时除了我之外在场的所有人都没法听出来。
若要究其原因,其实也真的很难说清楚,可能因人而异。但是现在仔细回想起来,最有可能就是读初中时沉迷于玩弄装调收音机,需要高度集中注意力来调台听音,相当于每天都在锻练耳朵的神经。还有就是读高中的几年都一直在DIY功放和录音机,当时一放学回家,就开着DIY的磁带全裸放音机和土炮功放听音乐。这应该是跟少年时声音对耳神经的刺激得多有关系。 在此谈谈如何用耳朵选低音喇叭,现在市面上的低音喇叭盆材质已经不是纯纸盆了。
应如何选?有一个很简单的方法,就是用手指尖在喇叭盆上轻轻来回刮一刮,目的是让其振动,若听起来浑身想起鸡皮。
就一定做不出耐听的重低音。谐振频率低的喇叭盆不会令人起鸡皮。 MARK一下,做的时候参考 是否用单片机读取wav,dac部份由专门的IC去处理,这样的方案应该更合理些
有这个想法,可却对单片机却只是入门级。
页:
[1]