一种使用SPI连接I2S接口的音频DAC的方法
年前搞了个LPC2148最小板,写了些简单的程序后,打算做一个WAV播放器玩玩。结果发现LPC2148不带I2S接口,而非I2S接口的音频DAC基本没有,这下有些后悔买的是不带I2S的片子。后来在网上转啊转,终于发现有人成功用SPI接口模拟I2S的:1、http://www.k9spud.com/traxmod/
下了源代码后读了半天始终没搞懂SPI的CS信号是怎么控制的,而且PCM1770我这里还买不到。
2、坛子里面有人用LPC2136连接PCM1716,不过据作者本人说只能有一个声道有声音
……
最后只好自己搞,研究了两个礼拜,终于成功搞了出来。
到NXP的网站上可以找到I2S接口的说明书,分析一下I2S总线特点:1、数据不能断流;2、时序上有严格的要求。这两条决定了如果我打算用没有FIFO的SPI接口模拟I2S总线,SPI就不可能工作在主机方式,事实上两面两个成功的例子当中SPI也都是工作在从机方式的。I2S总线上的数据位可以从16bit-24
bit不等,为了使SPI就口有足够的时间装填数据,因此选择24bit的数据格式。剩下的就是如何产生I2S总线的2个信号BCLK、LRCK,音频DAC的工作信号MCLK和SPI接口的CS信号的问题了。起初打算用LPC2148自己产生这些信号,结果发现不行,因为没有足够的PWM通道。最后想了一个不太经济的方法,就是用单片机产生这些信号。起初用的是tiny2331 — 两路独立的PWM(BCLK、LRCK) + 系统时钟输出(MCLK),但是CS的时序时钟调不好;后来打算换成mega8 — 三路独立的PWM(BCLK、LRCK、CS) + 74HC04(MCLK);在查找手册的时候发现mega48与tiny2313一样有系统时钟输出功能,重要的是mega48时可以跑20MHz的,正好手头有一片mega48,就用它了。
整理一下方案:
I2S数据输出使用LPC2148的SPI接口,16-bit从机方式,MISO输出I2S数据,在中断中加载下一输出数据;
mega48工作在16.9344.MHz,分别由PB0(设置熔丝位)、PD6、PB1、PB3输出MCLK、LRCK、BCLK和CS,程序比较简单如下
#include <avr\io.h>
#include <util\delay.h>
#define SYS_LED PD1
#define SET_LEDPORTD &= ~_BV(SYS_LED)
#define CLR_LEDPORTD |=_BV(SYS_LED)
#define NOP __asm__ __volatile__("nop")
int main(void){
CLR_LED;
DDRB = _BV(PB0) | _BV(PB1) | _BV(PB3);
DDRD = _BV(PD6);
_delay_ms(10);
/* use Timer0 to generate LRCK : CTC mode, TOP = OCR0A, OCR0A toggle */
OCR0A= 192 - 1;
TCCR0A = 0x42;
/* use Timer1 to generate SSEL : fast PWM mode, TOP = ICR1, OCR1A set on match and clear on TOP */
ICR1H = 0;
ICR1L = 192 - 1;
OCR1AH = 0;
OCR1AL = 128 - 1 - 2;
TCCR1A = 0xC2;
/* use Timer2 to generate BCLK : CTC mode, TOP = OCR2A, OCR1A toggle */
OCR2A= 4 - 1;
TCCR2A = 0x42;
TCCR2B = 0x01;// BCLK start
NOP;
NOP;
NOP;
NOP;
NOP;
NOP;
NOP;
TCCR0B = 0x01;// LRCK start
NOP;
NOP;
NOP;
NOP;
NOP;
NOP;
NOP;
NOP;
TCCR1B = 0x19;// SSEL start
SET_LED;
while(1);
return 0;
}
用上述方法连接CS4334成功,两个声道均能正常发生;LPC2148中开两个1K(小了没试过)的Buffer可以流畅播放44.1KHz 16bit的WAV文件(经过FAT系统,用fatgetc读取数据)。
http://cache.amobbs.com/bbs_upload782111/files_12/ourdev_420460.JPG
(原文件名:1.JPG)
http://cache.amobbs.com/bbs_upload782111/files_12/ourdev_420461.JPG
(原文件名:2.JPG)
不过用此法连接PCM1742的时候,输出有极大的噪音,不知道是DAC输出部分没搞好还是芯片有问题。有兴趣的朋友可以交流一下。 狂顶啊~我想用I2s模拟SPI,先参考一下楼主 楼主高人啊。学习了。 cool 我能问句嘛,你的SD卡做是怎么用万用表焊的呀,能否给上个图啊? 呵呵,不错。前一阵子我也想干这个事来着,后来怕不保靠就没弄,还是选了颗带i2s的。
给楼主提个问题,关于bclk和lrck信号,把DAC配成master mode不行吗? DAC自己产生这个信号,SPI这边slave收,就不需要mega48了。 SD卡看下图。模拟的难点不是产生BCLK和LRCK,而是SPI的CS信号;因为这个CS信号并不是在LRCK跳变的时候变低的,而是在跳变之后的一个SCLK周期之后变低的,而且16个SCLK周期之后要变高。也就是说CS信号的周期是LRCK的二倍,占空比低:高 = 2:1,与LRCK有固定“相位差”。我之前用LPC2148的定时器捕获SCLK然后产生CS信号,没能成功,主要是同步调不好,后来干脆这部分就全用单片机处理。
http://cache.amobbs.com/bbs_upload782111/files_12/ourdev_420679.JPG
(原文件名:IMG_0669.JPG) 请教楼主,如果仅仅用mega48/88/168传输数据给DAC芯片而不做任何数据处理的话,就是类似于mega将内部ram数据直接传输给DAC,将maga48设成主机模式,在LRCK跳变后的一个SCLK输出SPI(音频)数据,这样是否可行?
还有,怎么确定MCLK、LRCK、BCLK这些时钟频率啊?外部晶振和ctc的计数怎么算呢? 以我做的为例:WAV音频文件的采样率是44.1KHz,也就是说LRCK的频率就是44.1KHz(高电平一个声道,低电平另一个声道),这个频率也称为fs;一般音频DAC要求MCLK为256倍或者384倍的fs,我这里i2s采用的是24-bit格式,为了使MCLK能整除因此采用的是MCLK=384*fs,也就是16.9344MHz;而BCLK=fs*i2s位数*2=2.1168MHz。综上,采用mega48工作在16.9344MHz,PB0输出系统时钟;一个定时器工作在CTC模式、不分频、计时192-1输出一翻转,这样得到LRCK;一个定时器工作在CTC模式、不分频、计时4-1输出一翻转,这样得到BCLK;一个定时器工作在PWM模式,周期192-1清零、比较匹配128-1-2(略小于16个BCLK周期)时置位,这样得到SPI的片选信号。
你的意思是mega48的SPI设置成主机向DAC送信号吧,这样做你的BCLK是不连续的,会出现问题。 spi->iis 牛 to 314forever:
如果将mega48的SPI设置成从机,那把mega48的PB3输出的CS又接到mega48的spi sck端口?
PS:forever写的好详细啊,十分感动,3Q!!!
以前avr的定时器我都是用普通模式来定时,ctc,pwm没用过,对照你的初值设定理解了不少。__@ mega48的SPI从机方式输出8位数据,这样的话在当前Byte发送完到下一Byte发送开始,你一共有大约只有128个系统时钟周期的时间;这期间要响应中断并且在中断中填充数据,如果数据存放在mega48的flash中应该是够用了;不过此时Timer2的输出要换成PD3,应为PB3要用于SPI。 mega48的SPI从机方式输出8位数据,这样的话在当前Byte发送完到下一Byte发送开始,你一共有大约只有128个系统时钟周期的时间;
按照你的思路,这里应该只有64个系统时钟周期啊?就是在CS为高时才不对I2S操作,只要CS=0,则CPU一直与DAC通信,是这样的吗?
我想把BCLK设为32bit,这样就有96个系统时钟周期了。
另外,这里的NOP起什么作用?
TCCR2B = 0x01;// BCLK start
NOP;
NOP;
NOP;
NOP;
NOP;
NOP;
NOP;
TCCR0B = 0x01;// LRCK start
NOP;
NOP;
NOP;
NOP;
NOP;
NOP;
NOP;
NOP;
TCCR1B = 0x19;// SSEL start CS为低发送8-bit数据,一共是8 * 8 = 64时钟周期(注:顶楼的例子中CS为低的时间左右略微缩了一点);
CS为高响应中断、充填数据,一共是16 * 8 = 128时钟周期;
注意这里工作在CTC方式的Timer的周期是OCRA的两倍;
好像不是所有DAC都工作在32-bit下,起码我手上的CS4334不行,倒是16-bit的DAC你给他24-bit数据是可以的;
NOP起同步作用,数数个数就知道怎么回事了。 牛~搂主焊接超漂亮整洁~能不能把背面也照几张照片? 关心模拟出来的时序对音频指标是否有影响 好强。。。 一个定时器工作在PWM模式,周期192-1清零、比较匹配128-1-2(略小于16个BCLK周期)时置位,这样得到SPI的片选信号。CS信号的周期是LRCK的二倍,占空比低:高 = 2:1.
-------这里貌似看懂了!
CS为低发送8-bit数据,一共是8 * 8 = 64时钟周期(注:顶楼的例子中CS为低的时间左右略微缩了一点);
CS为高响应中断、充填数据,一共是16 * 8 = 128时钟周期;
-------这里没明白。
我的理解:
以左声道为例:CS为低期间(占128个时钟周期)SPI向DAC输出16bit数据,之后CS变为高电平(占64个时钟周期),因设定分辨率为24bit,所以在CS为高电平器件DAC自动填充8bit个0,因此在DAC填充8bit个0期间(即64个时钟周期),单片机可响应中断加载SPI数据(即右声道数据)。
314forever帮忙看看我走到那条岔道上去了。-_-!
PS:你用的是什么AD呢?推荐几个便宜点的立体声AD。 你理解得没错,不过AVR的SPI只有8bit(你不是打算用mega48做么),因此DAC自动充填剩下的16bit(DATA线最好有上拉或下拉),所以有128时钟周期来响应中断。AD?DAC吧,去TI网站上查查有不少,想便宜挑一个SNR100db左右的就行;关键是看你能买到什么,我这只能买到PCM1742,买了两片貌似还都有问题。
关于“关心模拟出来的时序对音频指标是否有影响”,我认为这样做和原生i2s接口区别不大。说是模拟,其实关键信号都是由硬件完成。除了位数上可能会存在差别,毕竟最重要LRCK和MCLK都是严格按照i2s协议生成的。至于某个帖子中说SPI接口存在噪声,不晓得是怎么得出这个结论的。 楼主能否提供一个I2s的时序图和SPI的时序图我们好理解啊~
NXP的网站找了一下没看见有。。。 好,谢谢314forever !
这2天搭个板子试试效果如何。
另外,你的DAC是cs4334,音频信号来自SD卡是吧?我要采集音频,用什么ADC芯片好呢?打算用WM8951,但管脚太多,不知道CS5340/1/2/3/4这些怎么样? 155107149 ,NXP的I2SBUS我只找到了个7页的文档(不知道314forever 找的是哪个),里面都是些触发器什么的,模电没学好,一看到触发器就头大,还是随便下一个DAC的资料好,里面也都有讲时序。。
点击此处下载 ourdev_421993.pdf(文件大小:60K) (原文件名:I2SBUS.pdf) 这个7页的资料足够了,只要把前面几页的时序搞明白就行。8bit数据用AVR自带的AD应该够吧(处理16bit数据估计AVR吃不消),其实如果音频数据只有8bit,不必拘泥于音频DAC,一般的DAC就够用了。 发现一个问题:如果想要mega48的spi输出16bit数据给DAC,怎么办?
我这个单片机一定要输出16bit给DAC,要不然DAC自动充填剩下的16bit,这输出的声音质量也太差了。。 换ARM,否则无解…… 直接由44.1的256倍 11.2896M晶体提供MCLK,然后由定时器1做256分频得到LRCK,接着由定时器2做4分频得到BCK,
SPI的CS 致H 则定时器1,2重置,一个BCK周期(或者按LJ【左对齐】,不需要一个BCK周期)后输出DATA(左)
然后等待LRCK致L,一个BCK周期(或者按LJ【左对齐】,不需要一个BCK周期)后输出DATA(右)
完成一次I2S的信号传送。
意思大概是这样吧~ 我现在想,直接由M16【A】向SD卡读出数据,但是M16【A】不进行数据处理,而是,而由另一片M16【B】来数据转换,输出到DAC,这样是否可以?
此外就是按照读出的数据量,只要整体和BCK同步,即可~~~~~~~
请问各位有何见解~ 我现在使用的是LPC2368,这款芯片带有I2S接口,使用的音频芯片则是PCM1770,数据位数是16位,44.1KHZ,我设置BCK为1.4117MHZ,LRCK为44.1KHZ,PCM1770 上有个系统时钟SCKI,它的时钟设为256Fs=11.2896MHZ,SCKI是外接的。SCKI是不是一定要与BCK同步呢?我输入数据给PCM1770后,耳机中出来的噪音,这是为什么呢? mark mark 早应该COOL 好东西啊,正是我目前所需要的 上传常用音频接口的资料:
http://cache.amobbs.com/bbs_upload782111/files_24/ourdev_523923.jpg
(原文件名:i2s.jpg) mark 焊接的很漂亮~~ 高手! mark 不错!!!!! 学习 有用啊!Mark了 mark 我能不能用12M晶振提供芯片主时钟?可不可以解释一下 给大家一个技术参考,ti的msp430接i2s的pdf
一直没找到焊接TLV320AIC23B的转接板,心痒了好久
这个资料应该很有用!!
点击此处下载 ourdev_573299.pdf(文件大小:73K) (原文件名:slaa449a_I2S with MSP430.pdf) 另外TLV320AIC23B还有一个dsp模式
nxp和luminary的ssp接口(估计他们的ip核是一样的)都有一个ti serial模式,
和23b可以非常方便的连接.(时序也有少许不同,但更好处理) mark 正在研究怎么模拟I2S,感谢楼主。。。 MARK 楼主没有用什么软件编译的,IO.H delay.h没有提供,不知道延时多少? 能用Mega 8 代替 mega48吗? mark 下一个可能就要搞音频解码,学习一下。 学习一下 mark! 楼主你好,我按照你这个方法做了一个MEGA48程序写了PB0熔丝位已经写了。 产生I2S 已经用了16.9934 MHZ晶振输入PB6 (但没有加30pf的电容),输入用示波器测过是16.9344M 正弦波没有错。但PB0输出MCLK 却是只有1MHZ左右的方波。而CS 有5.190KHZ BCLK 124.56KHZLRCK 2.594HKZ 不能发声
主机显示时间也慢了16倍。究竟怎么回事
示波器显示MCLK还不够1MHZourdev_683413K6SLWZ.JPG(文件大小:2.34M,只有400K以内的图片才能直接显示) (原文件名:IMG_1165.JPG)
电路板焊接检查没有错ourdev_683414J8A0GF.JPG(文件大小:2.12M,只有400K以内的图片才能直接显示) (原文件名:IMG_1166.JPG)
http://cache.amobbs.com/bbs_upload782111/files_46/ourdev_683415H552VF.jpg
这是逻辑分析仪时序,仍然只有1MHZ (原文件名:1123.jpg)
http://cache.amobbs.com/bbs_upload782111/files_46/ourdev_683416J24ITK.jpg
放大后的时序0为CS 1为MCLK 2为LRCK 3为BCLK (原文件名:1124.jpg)
http://cache.amobbs.com/bbs_upload782111/files_46/ourdev_683417FBP054.jpg
AVRSudio 熔丝位图片1 (原文件名:1125.jpg)
http://cache.amobbs.com/bbs_upload782111/files_46/ourdev_683418M9V35Q.jpg
熔丝位图2 (原文件名:1126.jpg)
请问有mega48 的电路图吗?不知道是否连接正确,尤其复位部分。 楼主我也按照你的方式模拟SPI 接PCM1794的时候产生很大的噪音。不知道楼主之前的噪音问题解决没有,问题出现在那里? 模拟I2S,第一次见到,Mark 楼主的有电路图上传吗?http://www.k9spud.com/traxmod/这个网站 已经上不到了。到底mega48接晶振,晶振电源要不要接104和10UF电容。还有输出LRCK MCLK BCLK到DAC,到MCU 还有从MCU到DAC的DATA 四根线要不要接33R电阻。我见一般的DAC芯片I2S的线上都有33R电阻,还有DATA要不要做上拉? 能够提供时序,1794有I2S 标准模式,向右对齐,向左对齐,不知道是不是这些模式设置导致噪音。而我的是PCM1794 官方资料只有FM0 FM1 有三种模式I2S 立体声;标准16bit 和标准24bit。不知道I2S是否24bit 是选择I2S 还是标准24bit。 mark 昨天,问朋友接了一个高阻耳机。在DAC输出的引脚接上,发现极大的噪音依旧,排除了IV 和LRF的电路的问题。是不是正如楼主所说这种I2S接法CS系列的DAC就正常,接PCM的就有噪音。楼主你的1793到底又是如何成功的。有没有DAC或者MEGA48部分的电路给参考一下 我终于发现为何使用PCM1794有如此大噪音了。原因在于I2S PCM1794 的I2S是只支持24bit而mega48配合产生的时序是24bit 后面没有数据填充。所以导致噪音,PCM1793却支持I2S 16BIT 自动检测,至于CS系列可能有自动兼容模式 楼主,我发现你这个模拟I2S数据有很大问题。虽然我不知道为什么你的CS4334能正常发声,但我知道你的PCM1742有很大噪音的原因。一个LRCK周期有一个高电平和低电平。各输出左右声道个一个,半个LRCK周期代表一个声道。就一个声道来说。对应是32个周期的BCLK 一个BCLK周期对应一位数据。如果DAC是16bit数据的话,后面剩下的16个BCLK就填充0 如果是24bitDAC 后面的剩余8个填充0.现在完整32bit数据的DAC还不多但现在楼主的I2S 一个声道是24bit数据所以导致PC1794产生错误的误读。导致噪声出现! MARK 先记号一下,以后学习 MARK, 回复【楼主位】314forever
-----------------------------------------------------------------------
mark!正想着这方面资料 参考一下,也想用单片机模拟i2s 硬件平台搭的好漂亮~~~ mark..................... Mark!! 真好,能继续讨论下去就好了,菜鸟需要模拟I2S的知识 mark mark 杜邦线的问题
页:
[1]