314forever 发表于 2009-2-19 16:35:44

一种使用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输出部分没搞好还是芯片有问题。有兴趣的朋友可以交流一下。

155107149 发表于 2009-2-19 18:25:08

狂顶啊~我想用I2s模拟SPI,先参考一下楼主

ifree64 发表于 2009-2-19 18:54:08

楼主高人啊。学习了。

asdasd 发表于 2009-2-19 19:26:55

cool

hanbao0371 发表于 2009-2-19 19:41:25

我能问句嘛,你的SD卡做是怎么用万用表焊的呀,能否给上个图啊?

fantaq 发表于 2009-2-19 19:53:16

呵呵,不错。前一阵子我也想干这个事来着,后来怕不保靠就没弄,还是选了颗带i2s的。

给楼主提个问题,关于bclk和lrck信号,把DAC配成master mode不行吗? DAC自己产生这个信号,SPI这边slave收,就不需要mega48了。

314forever 发表于 2009-2-19 20:46:20

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)

xullin 发表于 2009-2-23 12:22:49

请教楼主,如果仅仅用mega48/88/168传输数据给DAC芯片而不做任何数据处理的话,就是类似于mega将内部ram数据直接传输给DAC,将maga48设成主机模式,在LRCK跳变后的一个SCLK输出SPI(音频)数据,这样是否可行?

还有,怎么确定MCLK、LRCK、BCLK这些时钟频率啊?外部晶振和ctc的计数怎么算呢?

314forever 发表于 2009-2-23 14:13:16

以我做的为例: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是不连续的,会出现问题。

laoye 发表于 2009-2-23 14:52:52

spi->iis 牛

xullin 发表于 2009-2-23 19:06:54

to 314forever:
如果将mega48的SPI设置成从机,那把mega48的PB3输出的CS又接到mega48的spi sck端口?


PS:forever写的好详细啊,十分感动,3Q!!!
以前avr的定时器我都是用普通模式来定时,ctc,pwm没用过,对照你的初值设定理解了不少。__@

314forever 发表于 2009-2-23 21:31:47

mega48的SPI从机方式输出8位数据,这样的话在当前Byte发送完到下一Byte发送开始,你一共有大约只有128个系统时钟周期的时间;这期间要响应中断并且在中断中填充数据,如果数据存放在mega48的flash中应该是够用了;不过此时Timer2的输出要换成PD3,应为PB3要用于SPI。

xullin 发表于 2009-2-24 13:14:36

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

314forever 发表于 2009-2-24 14:36:30

CS为低发送8-bit数据,一共是8 * 8 = 64时钟周期(注:顶楼的例子中CS为低的时间左右略微缩了一点);
CS为高响应中断、充填数据,一共是16 * 8 = 128时钟周期;
注意这里工作在CTC方式的Timer的周期是OCRA的两倍;
好像不是所有DAC都工作在32-bit下,起码我手上的CS4334不行,倒是16-bit的DAC你给他24-bit数据是可以的;
NOP起同步作用,数数个数就知道怎么回事了。

soulmate 发表于 2009-2-24 14:38:43

牛~搂主焊接超漂亮整洁~能不能把背面也照几张照片?

szxw 发表于 2009-2-24 15:06:29

关心模拟出来的时序对音频指标是否有影响

xiaozhiyong 发表于 2009-2-24 16:27:12

好强。。。

xullin 发表于 2009-2-24 18:20:13

一个定时器工作在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。

314forever 发表于 2009-2-24 21:31:46

你理解得没错,不过AVR的SPI只有8bit(你不是打算用mega48做么),因此DAC自动充填剩下的16bit(DATA线最好有上拉或下拉),所以有128时钟周期来响应中断。AD?DAC吧,去TI网站上查查有不少,想便宜挑一个SNR100db左右的就行;关键是看你能买到什么,我这只能买到PCM1742,买了两片貌似还都有问题。

关于“关心模拟出来的时序对音频指标是否有影响”,我认为这样做和原生i2s接口区别不大。说是模拟,其实关键信号都是由硬件完成。除了位数上可能会存在差别,毕竟最重要LRCK和MCLK都是严格按照i2s协议生成的。至于某个帖子中说SPI接口存在噪声,不晓得是怎么得出这个结论的。

155107149 发表于 2009-2-24 21:57:46

楼主能否提供一个I2s的时序图和SPI的时序图我们好理解啊~
NXP的网站找了一下没看见有。。。

xullin 发表于 2009-2-25 09:14:33

好,谢谢314forever !
这2天搭个板子试试效果如何。

另外,你的DAC是cs4334,音频信号来自SD卡是吧?我要采集音频,用什么ADC芯片好呢?打算用WM8951,但管脚太多,不知道CS5340/1/2/3/4这些怎么样?

xullin 发表于 2009-2-25 09:20:37

155107149 ,NXP的I2SBUS我只找到了个7页的文档(不知道314forever 找的是哪个),里面都是些触发器什么的,模电没学好,一看到触发器就头大,还是随便下一个DAC的资料好,里面也都有讲时序。。

点击此处下载 ourdev_421993.pdf(文件大小:60K) (原文件名:I2SBUS.pdf)

314forever 发表于 2009-2-25 11:52:24

这个7页的资料足够了,只要把前面几页的时序搞明白就行。8bit数据用AVR自带的AD应该够吧(处理16bit数据估计AVR吃不消),其实如果音频数据只有8bit,不必拘泥于音频DAC,一般的DAC就够用了。

xullin 发表于 2009-2-25 15:38:45

发现一个问题:如果想要mega48的spi输出16bit数据给DAC,怎么办?
我这个单片机一定要输出16bit给DAC,要不然DAC自动充填剩下的16bit,这输出的声音质量也太差了。。

314forever 发表于 2009-2-25 16:17:14

换ARM,否则无解……

90999 发表于 2009-4-2 23:24:13

直接由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的信号传送。

意思大概是这样吧~

90999 发表于 2009-4-2 23:30:19

我现在想,直接由M16【A】向SD卡读出数据,但是M16【A】不进行数据处理,而是,而由另一片M16【B】来数据转换,输出到DAC,这样是否可以?

此外就是按照读出的数据量,只要整体和BCK同步,即可~~~~~~~

请问各位有何见解~

liaoxiaoqing18 发表于 2009-5-4 10:22:47

我现在使用的是LPC2368,这款芯片带有I2S接口,使用的音频芯片则是PCM1770,数据位数是16位,44.1KHZ,我设置BCK为1.4117MHZ,LRCK为44.1KHZ,PCM1770 上有个系统时钟SCKI,它的时钟设为256Fs=11.2896MHZ,SCKI是外接的。SCKI是不是一定要与BCK同步呢?我输入数据给PCM1770后,耳机中出来的噪音,这是为什么呢?

simond 发表于 2009-5-19 20:10:40

mark

csclz 发表于 2009-8-11 23:58:03

mark

MANANDFEMAN 发表于 2009-11-10 11:23:57

早应该COOL

rosy_li 发表于 2010-1-8 13:46:58

好东西啊,正是我目前所需要的

zsmbj 发表于 2010-1-8 14:10:05

上传常用音频接口的资料:

http://cache.amobbs.com/bbs_upload782111/files_24/ourdev_523923.jpg
(原文件名:i2s.jpg)

2004ip 发表于 2010-3-12 17:27:50

mark

zbjzxc 发表于 2010-5-12 23:44:30

焊接的很漂亮~~

leifeng 发表于 2010-5-13 17:37:15

高手!

yusufu 发表于 2010-5-13 18:20:03

mark

ZZL520 发表于 2010-5-13 19:10:30

不错!!!!!

eworker 发表于 2010-5-13 19:41:43

学习

qiujianben 发表于 2010-5-13 20:35:39

有用啊!Mark了

ysu533 发表于 2010-6-3 20:38:21

mark

swj33 发表于 2010-8-6 17:04:45

我能不能用12M晶振提供芯片主时钟?可不可以解释一下

lryylryy 发表于 2010-8-6 17:07:10

给大家一个技术参考,ti的msp430接i2s的pdf
一直没找到焊接TLV320AIC23B的转接板,心痒了好久
这个资料应该很有用!!

点击此处下载 ourdev_573299.pdf(文件大小:73K) (原文件名:slaa449a_I2S with MSP430.pdf)

lryylryy 发表于 2010-8-6 17:11:54

另外TLV320AIC23B还有一个dsp模式
nxp和luminary的ssp接口(估计他们的ip核是一样的)都有一个ti serial模式,
和23b可以非常方便的连接.(时序也有少许不同,但更好处理)

duxingkei 发表于 2010-10-29 14:57:33

mark

junhonghe 发表于 2010-12-16 13:48:19

正在研究怎么模拟I2S,感谢楼主。。。

spk459 发表于 2011-7-4 18:16:41

MARK

yeson 发表于 2011-8-30 15:16:42

楼主没有用什么软件编译的,IO.H delay.h没有提供,不知道延时多少?

yeson 发表于 2011-9-2 16:48:16

能用Mega 8 代替 mega48吗?

lostmj 发表于 2011-9-24 10:22:35

mark

lanjingjing 发表于 2011-9-24 17:23:22

下一个可能就要搞音频解码,学习一下。

jeasen 发表于 2011-9-24 17:58:24

学习一下

lixupeng 发表于 2011-9-24 19:48:03

mark!

yeson 发表于 2011-10-9 21:17:02

楼主你好,我按照你这个方法做了一个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 的电路图吗?不知道是否连接正确,尤其复位部分。

yeson 发表于 2011-10-22 10:01:57

楼主我也按照你的方式模拟SPI 接PCM1794的时候产生很大的噪音。不知道楼主之前的噪音问题解决没有,问题出现在那里?

rj1985 发表于 2011-10-22 13:53:00

模拟I2S,第一次见到,Mark

yeson 发表于 2011-10-27 10:30:51

楼主的有电路图上传吗?http://www.k9spud.com/traxmod/这个网站 已经上不到了。到底mega48接晶振,晶振电源要不要接104和10UF电容。还有输出LRCK MCLK BCLK到DAC,到MCU 还有从MCU到DAC的DATA 四根线要不要接33R电阻。我见一般的DAC芯片I2S的线上都有33R电阻,还有DATA要不要做上拉?

yeson 发表于 2011-10-27 21:50:07

能够提供时序,1794有I2S 标准模式,向右对齐,向左对齐,不知道是不是这些模式设置导致噪音。而我的是PCM1794 官方资料只有FM0 FM1 有三种模式I2S 立体声;标准16bit 和标准24bit。不知道I2S是否24bit 是选择I2S 还是标准24bit。

bluelool 发表于 2011-10-27 22:17:11

mark

yeson 发表于 2011-11-2 09:40:32

昨天,问朋友接了一个高阻耳机。在DAC输出的引脚接上,发现极大的噪音依旧,排除了IV 和LRF的电路的问题。是不是正如楼主所说这种I2S接法CS系列的DAC就正常,接PCM的就有噪音。楼主你的1793到底又是如何成功的。有没有DAC或者MEGA48部分的电路给参考一下

yeson 发表于 2011-11-4 01:12:13

我终于发现为何使用PCM1794有如此大噪音了。原因在于I2S PCM1794 的I2S是只支持24bit而mega48配合产生的时序是24bit 后面没有数据填充。所以导致噪音,PCM1793却支持I2S 16BIT 自动检测,至于CS系列可能有自动兼容模式

yeson 发表于 2011-11-4 17:10:47

楼主,我发现你这个模拟I2S数据有很大问题。虽然我不知道为什么你的CS4334能正常发声,但我知道你的PCM1742有很大噪音的原因。一个LRCK周期有一个高电平和低电平。各输出左右声道个一个,半个LRCK周期代表一个声道。就一个声道来说。对应是32个周期的BCLK 一个BCLK周期对应一位数据。如果DAC是16bit数据的话,后面剩下的16个BCLK就填充0 如果是24bitDAC 后面的剩余8个填充0.现在完整32bit数据的DAC还不多但现在楼主的I2S 一个声道是24bit数据所以导致PC1794产生错误的误读。导致噪声出现!

amen 发表于 2011-11-23 10:12:22

MARK

sunicecream 发表于 2011-11-23 23:47:56

先记号一下,以后学习

ytpdq 发表于 2011-12-13 09:54:31

MARK,

rayluo 发表于 2011-12-27 14:50:30

回复【楼主位】314forever
-----------------------------------------------------------------------

mark!正想着这方面资料

longriver05 发表于 2012-4-5 16:38:05

参考一下,也想用单片机模拟i2s

shin555 发表于 2012-4-5 16:53:24

硬件平台搭的好漂亮~~~

ylbxxq 发表于 2012-11-15 12:23:40

mark.....................

somwin 发表于 2012-12-6 21:34:18

Mark!!      

loomo 发表于 2014-5-15 16:17:40

真好,能继续讨论下去就好了,菜鸟需要模拟I2S的知识

lncwangfeilnc 发表于 2014-5-17 18:12:33

mark               

lncwangfeilnc 发表于 2014-5-17 18:13:44

mark               

闷鱼 发表于 2017-5-4 17:29:29

杜邦线的问题
页: [1]
查看完整版本: 一种使用SPI连接I2S接口的音频DAC的方法