使用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芯片的使用,认识到了移位寄存器和发送数据寄存器位数不一致如何使用。