有关DSP2812与SPI接口DA芯片的通信(AD5640,AD5682)

使用DSP2812控制SPI接口DA芯片总结:

本文只针对SPI接口的DA芯片,通常用到的DA芯片有精度位16位/14位/12位的。我在这次过程中用到的都是14位的,刚开始使用的是AD5640的DA芯片,其精度为14位,移位寄存器为16位,前2位是工作模式位(一般选正常工作模式就行),后14位是数据,刚刚好,DSP2812的数据输出寄存器(SPITXBUF)也是16位,只需要设置SPICCR寄存器数据位为16位即可,由于AD5640是要求下降沿数据输入,因此DSP2812配置为上升沿输出,具体看SPI接口时序图。在配置完数据输出字符长度和极性(DSP数据上升沿输出,下降沿输入),接下来再配置DSP为主模式,设置时钟相位(选正常的SPI时钟),配置波特率(根据DSP低速外设时钟设置,AD5640可达30MHz),复位SPI模块,设置为自由运行模式,这样,DSP2812与AD5640的SPI接口已配置完毕,接下来对AD5640的操作就很简单了,只需要通过SPITXBUF发送数据就可以,相关源代码如下:

#include "DSP281x_Device.h"
#include "DSP281x_Examples.h"   
#include "math.h"

void InitSpii(void); //SPI初始化

extern Uint16 RamfuncsLoadStart;
extern Uint16 RamfuncsLoadEnd;
extern Uint16 RamfuncsRunStart;

int main(void) {

InitSysCtrl();  //初始化系统控制寄存器、Pll、看门狗和时钟

 MemCopy(&RamfuncsLoadStart, &RamfuncsLoadEnd, &RamfuncsRunStart);
 InitFlash();

 InitGpio();        //GPIO初始化

 DINT; //禁止和清除所有CPU中断向量表
 InitPieCtrl();//初始化PIE控制寄存器
 IER = 0x0000;//禁止CPU中断
 IFR = 0x0000;//清除CPU中断标志
 InitPieVectTable();//初始化中断向量表

 InitPeripherals();         //模块初始化

EINT;          // Enable Global interrupt INTM   //使能所有CPU中断向量表
// ERTM;          // Enable Global realtime interrupt DBGM   使能DEBUG中断
while(1)
{
SpiaRegs.SPITXBUF=6000;  
}

void InitSpii(void)
{
//AD5640

// Initialize SPIA:
SpiaRegs.SPICCR.all=0x004F;//复位、下降沿有效、16位数据
SpiaRegs.SPICTL.all=0x0006;//主模式、使能发送、禁止中断
SpiaRegs.SPIBRR=0x007E;         //SPICLK
SpiaRegs.SPICCR.all=0x008F;     //退出复位、SPI CHAR 16bit
SpiaRegs.SPIPRI.bit.FREE=1;     //设置为自由运行模式

// Initialize SPIA-FIFO:
SpiaRegs.SPIFFTX.all=0xE040;
SpiaRegs.SPIFFRX.all=0x205F;
SpiaRegs.SPIFFCT.all=0x0000;

SpiaRegs.SPITXBUF=4800;        


//
}

///

在我实现了DSP与AD5640的通信以后,一切使用都很正常,可是在生产过程中,硬件工程师这边总是反馈到这个芯片不正常工作,后来注意到这个芯片的焊接温度不是很高,小批量生产都是生产人员焊接的,没有注意到这一点,硬件工程师提出更换DA芯片,在供应商的推荐下,选择了后面要说到的AD5682R这款芯片,说是封装一样,精度一样,可以替换。后来就换了,后来发现通信不对,我查看了数据手册,原来它的移位寄存器是24位,分控制命令和数据输入命令。


上面这张表就是介绍它的命令:

命令一:无任何操作;

命令二:将数据写入输入寄存器;

命令三:将输入寄存器中的数据跟新到DAC寄存器,也就是让其生效,实现数模转换;

命令四:将数据写入到输入寄存器的同时跟新到DAC寄存器,同时完成命令二和命令三的操作;

命令五:写控制寄存器,配置寄存器的相关参数;

命令六:读回输入寄存器的值;

一般操作,只使用命令四和命令五,在SPI接口初始化完成后,在进入大循环之前,使用命令五完成DA5682R的相关参数的配置,在大循环里只需要用到命令四实现DA转换。命令二,命令三,命令四中,高四位是命令位,接着的14位是数据位,后面的低六位是无效位。命令五的高四位是命令位,接着六位是配置控制寄存器位,后面的低14位全为0。使用过程严格按照数据格式使用。



上面这张表就是命令五,即配置控制寄存器的配置位,需要根据自己的实际使用情况来配置。下面介绍这些位的配置:


Reset:

这个复位位在使用发送数据前,复位一次,置1复位DA,复位后自动清0;


工作模式选择:

一般选择正常工作模式,后面几种都是设置为掉电模式,一般在考虑到功耗的时候会用到。


REF设置:

即参考电压设置,置0,是默认的,选择为内部参考;

置1,设置外部参考电压;


Gain:

gain的设置,是选择输出电压的范围,置0,是默认的,输出电压是以参考电压为准,(0V—VREF);

置1,输出电压是0V-2*VREF;


DCEN:

设置此位为0,就是在输入的数据写满移位寄存器,即24位就进行处理;

置该位为1,就可以输入任意长度的数据,但是只去最后的24位,丢掉高位;



经过以上的配置,即完成了控制寄存器的配置,发送数据使用命令四即可。


由于AD5682R的移位寄存器是24位,而2812可以设置发送的数据位为1-16位;(1)因此可以设置为16位数据位,但是要将DCEN设置为1。连续输入两次,要将有效位放在低24位。(2)可以将设置位12位数据位,连续输入二次,也不需要DCEN置1,;(3)可以将数据位设为8位,连续输入三次;怎么方便怎么来;

我使用的命令如下:

控制命令:0x480000;//命令五,配置控制寄存器,复位,其他全置0;

数据命令:0x312c00;//命令四,4位命令位后的14位为数据,低6位无效;

//

那么问题来了,在我将数据位设置为8位,连续发三次,或者数据位设置为12位,连续发两次,通信都不正常,很郁闷,又看了手册,SPI接口的极性,相位,波特率都没问题,还是不行。

我在程序里是这么写的:

配置为12位:

控制:SpiaRegs.SPITXBUF = 0x480;

 SpiaRegs.SPITXBUF = 0x000;

数据输入:假设数据为12c0

SpiaRegs.SPITXBUF = 0x312;

SpiaRegs.SPITXBUF = 0xc00;

配置为8位:

控制:SpiaRegs.SPITXBUF = 0x48;

 SpiaRegs.SPITXBUF = 0x00;

SpiaRegs.SPITXBUF = 0x00;

数据输入:假设数据为12c0

SpiaRegs.SPITXBUF = 0x31;

SpiaRegs.SPITXBUF = 0x2c;

SpiaRegs.SPITXBUF = 0x00;

拿过示波器,四个通道分别检测片选,时钟,输入,输出;

片选正常,时钟正常,输入的数据好像不太对,没有输出;


最后通过示波器发现一个问题,一直忘了,只顾着发送的数据位,忘了SPITXBUF是16位,很关键,SPITXBUF是16位,SPITXBUF是16位,SPITXBUF是16位,重要的事说三遍;

比如:设置为8位数据位:SpiaRegs.SPITXBUF = 0x48;就相当于是SpiaRegs.SPITXBUF = 0x0048;,发过去的是高8位;

设置为12位数据位:SpiaRegs.SPITXBUF = 0x480;就相当于是SpiaRegs.SPITXBUF = 0x0480;,发过去的是高12位;

发过去的和我想要发过去的完全不一样;

这样就很清楚了,设置SPI通信的数据位跟SPITXBUF是两回事,设置数据位为16位,那么SPITXBUF所有位有效;设置数据位为12位,那么SPITXBUF高12位有效;

设置数据位为8位,那么SPITXBUF高8位有效;这样,就找到问题的根源了。

不使用24位移位寄存器发现不了这样的问题。

DSP2812与AD5682R的SPI通信代码如下:



#include "DSP281x_Device.h"
#include "DSP281x_Examples.h"   
#include "math.h"

void InitSpii(void); //SPI初始化
unsigned int Spi_TxReady(void);//SPI发送数据判别
void spiakz(void);//  AD5683R --SPI发送控制指令
void spia_xmit(Uint16 a);//AD5683R -- SPI数据发送

extern Uint16 RamfuncsLoadStart;
extern Uint16 RamfuncsLoadEnd;
extern Uint16 RamfuncsRunStart;

int main(void) {

InitSysCtrl();  //初始化系统控制寄存器、Pll、看门狗和时钟

MemCopy(&RamfuncsLoadStart, &RamfuncsLoadEnd, &RamfuncsRunStart);
InitFlash();

InitGpio();       //GPIO初始化

DINT; //禁止和清除所有CPU中断向量表
InitPieCtrl(); //初始化PIE控制寄存器
IER = 0x0000; //禁止CPU中断
IFR = 0x0000; //清除CPU中断标志
InitPieVectTable(); //初始化中断向量表

InitPeripherals();         //模块初始化

EINT;          // Enable Global interrupt INTM   //使能所有CPU中断向量表
// ERTM;          // Enable Global realtime interrupt DBGM   使能DEBUG中断
spiakz();
spia_xmit(4800);
while(1)
{
spia_xmit(6000);
}

void InitSpii(void)
{

//AD5682R

// Initialize SPIA:
SpiaRegs.SPICCR.all=0x000b; //复位、下降沿有效、8位数据
SpiaRegs.SPICTL.all=0x0006; //主模式、使能发送、禁止中断
SpiaRegs.SPIBRR=0x007E;         //SPICLK
SpiaRegs.SPICCR.all=0x008b;     //退出复位、SPI CHAR 8bit
SpiaRegs.SPIPRI.bit.FREE=1;     //设置为自由运行模式

SpiaRegs.SPIFFTX.all=0xE040;
SpiaRegs.SPIFFRX.all=0x205F;
SpiaRegs.SPIFFCT.all=0x0000;

}
void spiakz(void)
{
SpiaRegs.SPITXBUF = 0x4800;
while(Spi_TxReady() != 1){}
SpiaRegs.SPITXBUF = 0x0000;
DELAY_US(100);
}

unsigned int Spi_TxReady(void)
{
unsigned int i;
if(SpiaRegs.SPISTS.bit.BUFFULL_FLAG == 1)
{
i = 0;
}
else
{
i = 1;
}
return i;
}

void spia_xmit(Uint16 a)
{

SpiaRegs.SPITXBUF = (0x3000 | (a >> 2));
while(Spi_TxReady() != 1){}
SpiaRegs.SPITXBUF = (a << 10);
DELAY_US(100);
}

总结:通过对这两个DA芯片的使用,认识到了移位寄存器和发送数据寄存器位数不一致如何使用。


你可能感兴趣的:(嵌入式)