ADI公司的ad5544一个四通道、16bit 精度的DAC芯片。本身硬件原理不复杂,所以软件控制也不复杂,但是优点就精度非常高,用于数字量转模拟量电流,比如用于信号仿真。假设输出是正弦波,因为有16bit 相当于有0xFFFF个档位变化,已经是非常高精度存在了。
因此我们在这个芯片上研究不少时间,文档和开发板都很简单,但是自写软件总是控制不了,走了很大的弯路,直到后面实测发现才发现这个文档有留了一个坑。
这款芯片一大特点就是用一个4线的SPI总线来输入一个特殊指令来控制输出电流的变化,相对于用IO脚来控制方法,大大节约了硬件管脚数量。
它的原理就是在有一个稳定的输入参考电压(VREFX),通过软件发送SPI指定参数可以动态在在输出端输出 模拟电压,跨度在0-7.5V 电压. 这个特性常用于硬件乘法器,信号发器等设计.
其中输入电压与输出电压的换算关系满足如下公式
这个公式中,-Vref 是输入电压,一般是桓定的5V, Vout为输出电压, 65536是一个常量,这个D就SPI输入换算系数. 65536即2的16次方,可以限定D的最大值不能超过16bit ,这就是由芯片硬件精度限制.
在这个公式里,开头-号表示输入和输出电压极性正好相反.即输入一个正电压,出来是负电压.
这里顺便是提一下ADI另一颗DAC芯片AD5554是14bit精度,这样公式就换算成
这里16384就是 2的14次方.
硬件解读这是硬件框图,
在面向上位机 ,有7个管脚,其中CS/SCLK/SCIN/SDO 这是SPI四个标准脚,但这里只需要软件输出即可,SCIN用于多块AD5544串连使用.因此ADI把这个又称为3 wire spi.
另外一个3个功能脚是 MSB 用于设定输出量程, 零代码状态(MSB = 0) 接地
或半量程状态(MSB = 1), MSB脚为0表示全量程,为1表示输出半量程,即参考电压一半(比如即5V输入, -2.5v输出)。这是输出是硬件执行,不需要软件干预,所以可以用于测试芯片硬件是否正常工作。在实际运行直接设为MSB=0
对RS复位管脚,低电平有效置0表示软件复位,相当于软件重启
LDAC管脚,低电平有效,功能加载DAC寄存器选通.相当于spi数据生效.
也就是说最低需要 ldac,cs,sclk,sdo 四个管脚就可以工作了。
为了验证这一过程,ADI提供发板 EVAL-AD5544为例来介绍如何控制AD5544,
按文档介绍,专门介绍两个实例
翻译过来就是
当输入电压为10v,输入数据为0x4000时,输入地址为0,即产生1/4量程电压,即在 VoutA上产生 -2.5v电压输出
当输入电压为10v,输入数据为0xC000时,输入地址为0,即在 VoutA上产生 -7.5v电压输出
测试下来,的确如此。
软件控制接口参考基功能框图,在其SDO端,软件要发来18bit的SPI控制数据
其中 18bit 的数据中,高2位是地址,低16bit 控制数据D
地址对应关系如下,用来指明向哪个通道输出电压
但是我们知道,无论单片机还是x86,arm 软件用下传输数据都是基于8对齐,也就是说我们通过spi发送18bit数据,必须要补齐至少24bit,也就是3个byte数据,软件才能操作。
那这多出来6bit补哪里呢?这里文档写明是按msb优先。我们理解成在SPI MSB模式下,首先传输bit17,bit16,自然多出位要补数字低位.但是测试下来芯片如终不为所动.
最后突然反应过来是否补错了?ADI公布很多芯片的驱动代码,但偏偏就少这款芯片的,后面反应过来,实际上补在数字高位也就是第一个byte低两位就是地址,高位没用。
然后再传输16bit的控制数据,正好2byte,至此所有代码一通百通。希望后来的兄弟少走弯路
void US_SPI_Write2Byte(u8 addr_TD, u16 ad5544_data)
{
u8 tempdata = 0;
AD5544_CS_HIGH();
if(addr_TD == 0) //通道0
{
AD5544_CS_LOW();
AD5544_ReadWriteByte(0);
}
else if(addr_TD == 1) //通道1
{
AD5544_CS_LOW();
AD5544_ReadWriteByte(1);
}
else if(addr_TD == 2) //通道2
{
AD5544_CS_LOW();
AD5544_ReadWriteByte(2);
}
else//通道3
{
AD5544_CS_LOW();
AD5544_ReadWriteByte(3);
}
tempdata = (ad5544_data >> 8); //发送高8位
AD5544_ReadWriteByte(tempdata);
tempdata = ad5544_data; //发送低8位
AD5544_ReadWriteByte(tempdata);
AD5544_CS_HIGH();
}