如何把单片机/CPLD/FPGA的1个数字IO口变成DAC输出(非PWM方式)
warmonkey2013/04/23电子技术 IP:湖南
前言
此方法可以将1个数字IO口,转化成1路模拟量输出,分辨率>14bit,信噪比>30dB
这样的指标,已经超过了一些古老的8位DAC例如DAC0832,也大大超过了PWM能实现的性能。
而且,这个方法对IO只有两个要求:
1. 至少要有几百k速度,一般单片机都有
2. 几个mA的推挽输出能力(没有则加上缓冲级)
端口数量不限,比如你可以把一个CPLD的几十个脚,统统变成DAC输出

2012-11-03_19-28-23_265.jpg
使用此法通过IO口回放1kHz 8bit 录音,并使用示波器进行频谱分析

dsdemo2.gif
输出波形和频谱

实现方法
构建一个一阶Delta-sigma调制器,伪代码如下,可选汇编或者verilog实现
int acc;
int output;
while(1)
{
acc += output;
GPIO = bit_C;//单片机ALU的溢出位
while(!timeout);
}
不断把输出期望值累加到一个寄存器中,如果加法发生溢出,则设IO为高,否则设为低。
模拟电路部分,需要给输出脚加个RC无源滤波,一阶或二阶都可以
IO---R---C---R---C---OUT
              |______|_____GND

实际代码
Verilog Code for Cypress PSOC3

// Generated on 08/27/2012 at 00:03
// Component: DSDDAC
module dac(clk,nrst,data,dout);

`define wl 17
input clk,nrst;
input [`wl-2:0]data;
output dout;
reg [`wl-1:0]acc;
always @ (posedge clk or negedge nrst)
begin
if(!nrst)
begin
acc <= 0;
end
else
begin
acc <= acc[`wl-2:0] + data;
end
end
assign dout = acc[`wl-1];
endmodule

实物测试
无线音频传输装置,平台PSOC3,虚拟DAC时钟4M,SFDR > 30dB
attachment icon DSDDAC.7z 10.43KB 7Z 76次下载
Screenshot from 2013-04-23 02:10:40.png
电路原理图,DSD_DAC为一个GPIO口,没有模拟功能
2012-11-03_19-28-23_265.jpg
30dB是保守估计, 因为这里在1kHz附近的噪声,是录音音源和无线干扰引入的。
换成直接回放录音,SFDR可以轻松超过50dB。
此设计年代久远,未能留下最佳状态的数据,可惜了。
主观感觉,接耳机的时候,这东西音质类似AM收音机听本地强台的效果。底噪有点大,但是声音的还原还算不错

这个最主要优势是成本低,也没有PWM的基频泄漏,同时精度很高。
在这里输出级噪声和带宽的关系是“软”的,可以用更大噪声换取更大带宽。而PWM带宽受基波频率限制,提高基频频率之后,精度会严重降低。

原理
这个算法是如何工作的呢?为什么它在有高带宽的同时,又有高精度?
其实,我们将上面的计算程序,变换一下形式,就很明白了
float diff = 0, output = 0.3;//output = -1.0~1.0 //0-1扩展到-1~+1
while(1) {
//diff+=output;
if(acc < 0.0)  //diff = -acc
{   io =  1.0;  }
else
{   io = -1.0;  }
diff += io - output;
wait();
}
6860566889445.gif
diff是输出的误差,输出会不断的在+1和-1之间摆动,努力使得误差为0;
这就相当于,diff是一个积分器,它对输出和期望的偏差量io-output积分。
而if语句则相当于比较器,如果积分器输出为正,说明输出太高,需要输出-1,反之需要输出+1
这样就会在引脚上产生一个方波,它的频率和脉宽不断变化,但是方波电压的平均值,正好等于output输出波形见文章开头那幅图

进阶
如果采用更复杂的结构,例如使用4M的计数频率,3阶调制器,输出级采用对称恒流源结构(让IO口灌电流和拉电流的能力完全相同),理论上可以在4kHz内,达到80dB的信噪比。


从另外一个视角看上面的环路图:
量化噪声是在积分器之后,比较器(量化器)产生,输出端反馈回到积分器之前。
量化噪声通过负反馈环路,来到积分器之前。负反馈环路会抑制这个噪声。
积分器的存在,使得负反馈作用在低频段比较强,高频段比较弱(积分等效低通,引入一个极点,也就是20db/oct的滚降)
320px-DeltaSigmaNoise.svg.png
结果就是,在最后输出的信号频谱中,噪声主要集中在高频部分
如果改变环路的传递函数,就可以获得不同的噪声成形特性,比如说带通特性
这个过程叫做噪声成形 Noise shaping(上图),噪声传递函数很重要。。。


提高内部调制器阶数,改用更先进的环路,在同样的调制频率下,性能可以成倍提高,但是计算分析也更复杂。
好在有现成的matlab工具箱可以完成调制器的设计:
XXXXXXXXXXXXXXXXX/matlabcentral/fileexchange/19-delta-sigma-toolbox

反过来用
那就是Sigma-Delta ADC~~~~高精度必然是它了~~~~
上面的工具箱可以用于分析ADC

胡思乱想
如果把计数频率设计到1G、2G,甚至是10G、20G(很多FPGA的LVDS口已经有这个能力了),岂不是可以直接产生射频信号?

Screenshot from 2013-04-25 09:19:53.png
 
attachment icon REALIZATION OF A SIGMA-DELTA MODULATOR IN FPGA.pdf 561.43KB PDF 249次下载 预览

ADC做到这个频率,又会怎么样呢。。。

吐槽
digikey上面有不少24bit 96k音频DAC,信噪比超过100dB,还只要几块钱一个,它们就是这种原理做出来的。
相比之下传统的电阻阵列DAC,内部很复杂,成本很高,还只有极少数能做到16bit INL 1LSB误差,信噪比/谐波失真更是悲剧。
TI的器件页面上,16bit以上的DAC,全是D-S方式的。

废话
D-S调制理论被认为是近几十年来模拟电路理论的最大进步,它模糊了数字和模拟的界限。
有时候,更简单的实现,反而带来更好的效果。。。。


Ref
XXXXXXXXXXXXXXXXXXXXXXX/wiki/%CE%94%CE%A3%E8%AA%BF%E8%AE%8A

本坛大神Mitchell作品
XXXXXXXXXXXXXXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXml

闲来无事,搭了个简单的电路来验证Delta-Sigma DAC的性能。
滤波网络使用的最简单的无源2阶低通RC滤波器,DAC使用的100MHz时钟,Sigma累加器使用12bit分辨率:
37_6688_7b313298bf96f6f.jpg   

既然要来奇怪的波形,就来点更更更奇怪的波形吧,你看我Delta-Sigma DAC是怎么做得出来的,嘿嘿~
(1)奇怪阶梯。这相似度有没有99%?
37_6688_bba48252492f415.png

(2)既然要YY,那就YY得更彻底一点。这细节够丰富吧?
37_6688_51031f0cb407786.png

(3)挑战一下极限,XY显示。测试一下Delta-Sigma DAC的速度。
37_6688_a1968980fcbccd3.png

再来点别的:
(1)100KHz正弦信号输出
37_6688_1a406eea5f96c43.jpg

(2)Delta-Sigma信号波形。看仔细了,不是PWM。
  37_6688_c4246483902503d.png

(3)100KHz信号示波器截图。可以于LZ位的180Hz的正弦波做个对比。
   37_6688_0f069cc427e2d73.png

(4)最后是100KHz信号FFT,hanning窗。这信噪比没有60dB也至少有50dB了吧?单单这一项指标,就可以把加权电阻方案甩得不见踪影。
37_6688_d146db4766a9168.png

[修改于 8年0个月前 - 2017/01/17 23:52:03]

+200  科创币    拔刀斋    2013/04/23 把delta-sigma解释的非常清楚
+30  科创币    yanli12321    2013/04/23
+16  科创币    神之觉醒    2013/08/10 得好好研究下~~~
+1  科创币    张静茹    2014/06/13 终于能大概看懂点哪个代码了
+1  学术分    虎哥    2013/04/23 高质量发帖
来自:电子信息 / 电子技术
27
 
4
已屏蔽 原因:{{ notice.reason }}已屏蔽
{{notice.noticeContent}}
~~空空如也
拔刀斋
11年10个月前 IP:未同步
518798
回 楼主(warmonkey) 的帖子
赞猴子类似wiki的风格,这是N年来介绍delta-sigma原理最直观的文章,还有频谱图实测。

来自猫的意见 -
误差传函推导没有特别叙述,其实可以很简单的解释信号传函与误差传函的比较与区别。主要是前向通道的积分环节对量化噪声来说成为了反馈通道的一部分,对噪声来说反馈环路的低通化为对噪声信号的高通,即Noise Shaping。
另外似乎完全没有提过采样的理论意义,过采样展宽了Nyquist带宽,之后噪声整形发挥作用,这一部分可以讲得比较好。

另外通过输出滤波器分离整形的高频噪声与低通信号成分。

以上各环节都有各种数字与模拟的实现,因此成为各种Delta-Sigma AD/DA的架构部分。

补充 -
CPLD或A3P030之类的小规模FPGA可以做内存的触发器数量很有限,不足以把几十个脚全部变成输出。
这个方法很适合CPLD/FPGA做少量的模拟输出或者单片机做很多路的模拟输出用。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
minizerg
11年10个月前 IP:未同步
518812
很好的文章。。。。。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
art
11年10个月前 IP:未同步
518955
不错,有点意思
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
duanyz
11年10个月前 IP:未同步
518991
记号学习下
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
量子隧道
11年10个月前 IP:未同步
519004
楼主用IO串电阻的方式来模拟开关电流源,给电容充电,大信号线性肯定不会好(输出波形会有点像饱和失真的)。
另外数字CMOS IO的拉灌电流能力差别挺大,甚至有的器件拉灌能力会差1倍。为了抵消这种情况,势必要加大串阻,来使得IO拉灌能力的不平衡(以及非线性)影响减弱,那么高频响应就下去了。
所以发出的呻吟像AM收音机收强台的应该正常。
可以考虑用此IO驱动两个外挂电流源,再用电容把电流积分成电压,估计效果就好了。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
量子隧道
11年10个月前 IP:未同步
519016
刚仔细看了下楼主的verilog代码,打死我也不信这就是delta sigma DAC。
delta sigma DAC的数字部分是把输出值(取值1或-1)做积分,积分结果与输入数据(一般是并行的)做比较,根据比较结果决定是否反转输出值。
而从楼主这段代码看,没有看出这个意思:
“XXXXXways @ (posedge clk or negedge nrst)
XXXXXgin
12.    if(!nrst)
13.    begin
14.        acc <= 17'b0;
15.    end
16.    else
17.    begin
18.        acc <= acc[`wl-2:0] + data;
19.    end
20.end
XXXXXsign dout = acc[`wl-1];
22.endmodule

这段代码解读如下:
复位时,把累加器置零;
然后在每个时钟沿处做如下操作:
将输入数据累加到累加器里;
用累加器的溢出位作为输出信号。
这种做法,假设输入一个数值,输出只会是方波;且方波的频率随输入数值的增大而减小,因为每次累加的数越大,累加器的溢出就越频繁。
怀疑楼主把delta sigma dac理解错了。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
量子隧道
11年10个月前 IP:未同步
519058
不知道是我笨还是什么原因,我才搞明白。似乎楼主“原理”那节所说的东西,和前面verilog代码所展示的东西,不是一个玩意。verilog或伪代码展示的东西,其实就是把累加器的溢出频率变成了输出电压。而“原理”说的不是这个意思。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
warmonkey作者
11年10个月前 IP:未同步
519066
本质上是一样的 伪代码那段 是单电平的调制
当输出误差acc累计到32768的时候 将acc设置成32768-65536=-32768
并设置输出为1,否则输出为0
也就是把output=-32768~32767映射到了0-1.0
这个程序 工作起来是完全正常的 输出频谱也符合D-S的特征
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
拔刀斋
11年10个月前 IP:未同步
519193
回 6楼(量子隧道) 的帖子
如果累加器溢出后回零,输出是频率。但实际上累加器溢出后回绕而不是回零。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
bg2bhc
11年9个月前 IP:未同步
519278
好想法好科普!
输入数据最好做下插值滤波,否则混叠成分可能比较惨啊
+100
科创币
zzlzhang
2013-04-24
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
zzlzhang
11年9个月前 IP:未同步
519304
回 10楼(bg2bhc) 的帖子
确实是要插值的,在D-S的AD/DA芯片中,有硬件插值器,避免变成阶梯波输入。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
拔刀斋
11年9个月前 IP:未同步
519309
纯模拟版本(无时钟):用自激振荡产生介于D-S和PWM之间的调制波形,用于D类音频功率放大器。

attachment icon A Universal Grammar of Class D Amplification.pdf 2.85MB PDF 367次下载 预览

典型的PWM D类音频功率放大器(有时钟)
PWM.png
增加闭环反馈
loop.png

类似D-S的滞回比较器自激振荡方式
Hyst.png
类似D-S的相移自激振荡方式
Phase.png
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
blueness
11年9个月前 IP:未同步
519817
[s:274]
写的好,很有参考价值。其实这种方法有很多衍生的应用。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
cqb98
11年9个月前 IP:未同步
520116
这事情以前想过,没想到真的可以。但不知道开关电源是不是类似这个原理呢?(我只是个会单片机的学生……其他都还在学……)
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
拔刀斋
11年9个月前 IP:未同步
520381
回 14楼(cqb98) 的帖子
一般开关电源是典型的PWM,12楼第1张图的原理
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
尾巴弟弟
11年9个月前 IP:未同步
520520
未经许可,禁止转载啊[s:274]

发个当年用在游戏机里的线路,如有雷同纯属巧合啊:
tt.png
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
lqs0905
11年9个月前 IP:未同步
520626
PWM这东西如果对功耗要求过高的话可以用。如果是小信号对功耗要求不高PWM那个高频分量那就是自杀。就拿D类功放来说如果要还原20KHZPWM就至少要200KHZ就这还不怎么样这个东东对滤波器要求要高还T形电阻网络作DA好
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
mapleft
11年8个月前 IP:未同步
529324
这个与PWM 有什么不一样, 求教;
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
whd1982
11年8个月前 IP:未同步
533140
方法是不错,但太占资源了吧。。。。输出的时候没法干别的事了
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
神之觉醒
11年6个月前 IP:未同步
558169
回 18楼(mapleft) 的帖子
貌似模拟信号幅度和脉冲密度有关系~[s:274]   ADC是模拟信号幅度控制脉冲的密度,DAC是脉冲的密度大电压就高~脉冲密度低电压就低  感觉是吧
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
找自己
11年6个月前 IP:未同步
558214
回 16楼(尾巴弟弟) 的帖子
功率可以做的很大 很小巧简单啊
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
yanli12321
11年6个月前 IP:未同步
559329
突然想到.........如果用D-S调制方式控制正弦逆变器后级那可是极好的啊!
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
1006518834
11年6个月前 IP:未同步
559492
不错啊,这么厉害
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
warmonkey作者
11年3个月前 IP:未同步
652174
yanli12321 发表于 2013-8-12 11:54
突然想到.........如果用D-S调制方式控制正弦逆变器后级那可是极好的啊!


那就是T类功放,频率和占空比一起变
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
硝钾苦无
11年3个月前 IP:未同步
652379
滞环?
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
金坷居士
9年9个月前 IP:澳大利亚
765658
楼主的Verilog翻译成电路大概素这样子的:
ACC.png
这素个4位的例子 如果用作4位的话 Carry-In接地 Carry-out作为DS输出
电路可以级联 上一级的Carry-Out接到下一级的Carry-in 然后最后一级的Carry-In作为输出
级联可以获得8位 12位 甚至64位的(雾
拉低R可以异步强制复位
可配合单片机或者纯硬件(雾)使用
引用
评论
1
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论

想参与大家的讨论?现在就 登录 或者 注册

所属专业
上级专业
同级专业
warmonkey
学者 机友
文章
363
回复
8003
学术分
12
2008/10/11注册,2时30分前活动

Cubesat

主体类型:个人
所属领域:无
认证方式:手机号
IP归属地:未同步
插入公式
评论控制
加载中...
文号:{{pid}}
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

加载中...
详情
详情
推送到专栏从专栏移除
设为匿名取消匿名
查看作者
回复
只看作者
加入收藏取消收藏
收藏
取消收藏
折叠回复
置顶取消置顶
评学术分
鼓励
设为精选取消精选
管理提醒
编辑
通过审核
评论控制
退修或删除
历史版本
违规记录
投诉或举报
加入黑名单移除黑名单
查看IP
{{format('YYYY/MM/DD HH:mm:ss', toc)}}