AD9854是一款200MHz主频的DDS,支持AM.FSK,PSK调制的方式,
可以用串行和并行两种方式进行控制,推荐用并行控制,
由于DSP管脚驱动能力较弱,如果PCB布线时两个芯片距离较远,最好加入驱动芯片。
AD9854的驱动基本上三步走,
第一步,确定时钟;
第二步,确定频率控制字FTW;
第三步,初始化寄存器。
首先是时钟配置
#define CLK_Set 12
#define CRYSTAL 12800000
12.8MHz的晶振 12倍频
然后根据芯片手册中FTW的计算公式,由于是48位累加器,设置如下
const unsigned long Freq_mult_ulong = 1832519;
const double Freq_mult_doulle = 1832519.379626667;
然后是寄存器配置
//DDS寄存器设置
uint8 AD9854_Addr_PHA1_config[AD9854_Length_PHA1+1] = {AD9854_Addr_PHA1,0x00,0x00};
uint8 AD9854_Addr_PHA2_config[AD9854_Length_PHA2+1] = {AD9854_Addr_PHA2,0x00,0x00};
uint8 AD9854_Addr_FRE1_config[AD9854_Length_FRE1+1] = {AD9854_Addr_FRE1,0x0,0x5,0x1F,0x0,0x0,0x0};
uint8 AD9854_Addr_FRE2_config[AD9854_Length_FRE2+1] = {AD9854_Addr_FRE2,0x0,0x0,0x0,0x0,0x0,0x0};
uint8 AD9854_Addr_DELTA_config[AD9854_Length_DELTA+1] = {AD9854_Addr_DELTA,0x00,0x00,0x00,0x00,0x00,0x00};
uint8 AD9854_Addr_UPDATA_config[AD9854_Length_UPDATA+1] = {AD9854_Addr_UPDATA,0x00,0x00,0x00,0x00};
uint8 AD9854_Addr_RAMP_CLK_config[AD9854_Length_RAMP_CLK+1] = {AD9854_Addr_RAMP_CLK,0x00,0x00,0x00};
uint8 AD9854_Addr_CTR_REG_config[AD9854_Length_CTR_REG+1] = {AD9854_Addr_CTR_REG,0x00,CLK_Set,0x00,0x60};
uint8 AD9854_Addr_I_MUL_config[AD9854_Length_I_MUL+1] = {AD9854_Addr_I_MUL,0xff,0xff};
uint8 AD9854_Addr_Q_MUL_config[ AD9854_Length_Q_MUL+1] = {AD9854_Addr_Q_MUL,0xff,0xff};
uint8 AD9854_Addr_SHAPED_config[AD9854_Length_SHAPED+1] = {AD9854_Addr_SHAPED,0x00};
uint8 AD9854_Addr_Q_DAC_config[AD9854_Length_Q_DAC+1] = {AD9854_Addr_Q_DAC,0x00,0x00};
下面看配置函数
void ad9854_update(void)
{
UNCLOCK_HIGH;
GPIO_ALL.GPIO_SUM = GPIO_ALL.GPIO_SUM & 0x00ff;
GPIO_RSET(IODATA,(unsigned char)GPIO_ALL.GPIO_SUM); //更新AD9854输出
//delay(15);
asm(" nop ");
UNCLOCK_LOW;
GPIO_ALL.GPIO_SUM = GPIO_ALL.GPIO_SUM & 0x00ff;
GPIO_RSET(IODATA,(unsigned char)GPIO_ALL.GPIO_SUM);
}
//====================================================================================
//函数名称:void AD9854_WR_Byte(uchar addr,uchar dat)
//函数功能:AD9854并行口写入数据
//入口参数:addr 6位地址
// dat 写入的数据
//出口参数:无
//====================================================================================
void AD9854_WR_Byte(uint8 addr,uint8 dat)
{
unsigned int aport_data;
unsigned int addr_real,data_real;
GPIO_RSET(AGPIODIR,0xFFFF);
addr_real = addr;
data_real = dat;
/* 0<<13 1<<12 2<<11 3<<10*/
aport_data = 0x3FFF&(((addr_real & 0x1)<<13)|((addr_real & 0x2)<<11)|((addr_real & 0x4)<<9)|((addr_real & 0x8)<<7)|
/* 4<<9 5<<8 0<<7 1<<6*/
((addr_real & 0x10)<<5)|((addr_real & 0x20)<<3)|((data_real & 0x1)<<7)|((data_real & 0x02)<<5)|
/* 2<<5 3<<4 4>>3 5>>2*/
((data_real & 0x04)<<3)|((data_real & 0x8)<<1)|((data_real & 0x10)>>1)|((data_real & 0x20)>>3)
/* 6>>1 7>>0*/
|((data_real & 0x40)>>5)|((data_real & 0x80)>>7));
GPIO_RSET(AGPIODATA,aport_data);
asm(" nop ");
WR_EN;
GPIO_ALL.GPIO_SUM = GPIO_ALL.GPIO_SUM & 0x00ff;
GPIO_RSET(IODATA,(unsigned char)GPIO_ALL.GPIO_SUM);
asm(" nop ");
WR_DIS;
GPIO_ALL.GPIO_SUM = GPIO_ALL.GPIO_SUM & 0x00ff;
GPIO_RSET(IODATA,(unsigned char)GPIO_ALL.GPIO_SUM);
// delay(100);
}
//====================================================================================
//函数名称:uint8 AD9854_WR_Byte(uchar addr)
//函数功能:AD9854并行口读取数据
//入口参数:addr 6位地址
//
//出口参数:读到的数据 8位数据
//====================================================================================
uint8 AD9854_RD_Byte(uint8 addr)
{
unsigned int aport_data;
unsigned int realdata = 0;
unsigned int realaddr = 0;
GPIO_RSET(AGPIODIR,0x3F00);
/* 0<<13 1<<12 2<<11 3<<10*/
realaddr = ((addr & 0x1)<<13)|((addr & 0x2)<<11)|((addr & 0x4)<<9)|((addr & 0x8)<<7)|
/* 4<<9 5<<8*/
((addr & 0x10)<<5)|((addr & 0x20)<<3);
GPIO_RSET(AGPIODATA,realaddr);
RD_EN;
// GPIO_RSET(IODATA,GPIO_ALL.GPIO_SUM);
delay(100);
aport_data=GPIO_RGET(AGPIODATA) & 0xff;
/* 0<<7 1<<6 2<<5 3<<4*/
realdata = ((aport_data & 0x01)<<7) | ((aport_data & 0x02)<<5) | ((aport_data & 0x04)<<3) | ((aport_data & 0x08)<<1)|
/* 4>>3 5>>2 6>>1 7>>0*/
((aport_data & 0x10)>>1) | ((aport_data & 0x20)>>3) | ((aport_data & 0x40)>>5) | ((aport_data & 0x80)>>7);
RD_DIS;
// GPIO_RSET(IODATA,GPIO_ALL.GPIO_SUM);
return((uint8)realdata);
}
//====================================================================================
//函数名称:void Freq_doublt_convert(double Freq)
//函数功能:正弦信号频率数据转换
//入口参数:Freq 需要转换的频率,取值从0~SYSCLK/2
//出口参数:无 但是影响全局变量FreqWord[6]的值
//说明: 有公式FTW = (Desired Output Frequency × 2N)/SYSCLK得到该函数,
// 其中N=48,Desired Output Frequency 为所需要的频率,即Freq,SYSCLK
// 为可编程的系统时钟,FTW为48Bit的频率控制字,即FreqWord[6]
//注意: 该函数与上面函数的区别为该函数的入口参数为double,可使信号的频率更精确
// 建议在100HZ以下用本函数,在高于100HZ的情况下用函数void Freq_convert(long Freq)
//====================================================================================
void Freq_double_convert(double Freq)
{
unsigned long Low32;
unsigned int High16;
double Temp=Freq_mult_doulle; //2的48次方除以当前CLK频率(参考晶振乘以倍频)
Freq*=(double)(Temp);
// 1 0000 0000 0000 0000 0000 0000 0000 0000 = 4294967295
High16 =(int)(Freq/4294967295); //2^32 = 4294967295
Freq -= (double)High16*4294967295;
Low32 = (unsigned long)Freq;
AD9854_Addr_FRE1_config[1]=Low32;
AD9854_Addr_FRE1_config[2]=Low32>>8;
AD9854_Addr_FRE1_config[3]=Low32>>16;
AD9854_Addr_FRE1_config[4]=Low32>>24;
AD9854_Addr_FRE1_config[5]=High16;
AD9854_Addr_FRE1_config[6]=High16>>8;
}
采用的是DSP的GPIO口组控制命令信号,A组引脚控制地址和数据,以后有机会会放原理图,请留意后续文章。
之后是初始化和生成波形的程序
//====================================================================================
//函数名称:void Freq_doublt_convert(double Freq)
//函数功能:正弦信号频率数据转换
//入口参数:Freq 需要转换的频率,取值从0~SYSCLK/2
//出口参数:无 但是影响全局变量FreqWord[6]的值
//说明: 有公式FTW = (Desired Output Frequency × 2N)/SYSCLK得到该函数,
// 其中N=48,Desired Output Frequency 为所需要的频率,即Freq,SYSCLK
// 为可编程的系统时钟,FTW为48Bit的频率控制字,即FreqWord[6]
//注意: 该函数与上面函数的区别为该函数的入口参数为double,可使信号的频率更精确
// 建议在100HZ以下用本函数,在高于100HZ的情况下用函数void Freq_convert(long Freq)
//====================================================================================
void Freq_double_convert(double Freq)
{
unsigned long Low32;
unsigned int High16;
double Temp=Freq_mult_doulle; //2的48次方除以当前CLK频率(参考晶振乘以倍频)
Freq*=(double)(Temp);
// 1 0000 0000 0000 0000 0000 0000 0000 0000 = 4294967295
High16 =(int)(Freq/4294967295); //2^32 = 4294967295
Freq -= (double)High16*4294967295;
Low32 = (unsigned long)Freq;
AD9854_Addr_FRE1_config[1]=Low32;
AD9854_Addr_FRE1_config[2]=Low32>>8;
AD9854_Addr_FRE1_config[3]=Low32>>16;
AD9854_Addr_FRE1_config[4]=Low32>>24;
AD9854_Addr_FRE1_config[5]=High16;
AD9854_Addr_FRE1_config[6]=High16>>8;
}
void ad9854_int(void)
{
GPIO_RSET(AGPIOEN,0xFFFF); //A端口设置为GPIO
GPIO_RSET(AGPIODIR,0xFFFF); //全部输出
GPIO_RSET(IODIR,0xFF); //GPIO端口全部输出
RESET_LOW;
WR_DIS;
RD_DIS;
// CRYSTAL_ON;
UNCLOCK_LOW;
GPIO_ALL.GPIO_SUM = GPIO_ALL.GPIO_SUM & 0x00ff;
GPIO_RSET(IODATA,(unsigned char)GPIO_ALL.GPIO_SUM); //初始化
RESET_HIGH;
GPIO_ALL.GPIO_SUM = GPIO_ALL.GPIO_SUM & 0x00ff;
GPIO_RSET(IODATA,(unsigned char)GPIO_ALL.GPIO_SUM); //主复位
delay(15);
RESET_LOW;
GPIO_ALL.GPIO_SUM = GPIO_ALL.GPIO_SUM & 0x00ff;
GPIO_RSET(IODATA,(unsigned char)GPIO_ALL.GPIO_SUM);
// CRYSTAL_OFF;
// GPIO_RSET(IODATA,GPIO_ALL.GPIO_SUM); //关晶振
// delay(100);
// AD9854_WR_Byte(0x16,0xff);
// AD9854_WR_Byte(0x17,0xff);
// AD9854_WR_Byte(0x18,0xff);
AD9854_WR_Byte(0x19,0x40);
AD9854_WR_Byte(CTRL1_ADDRESS,0x14); //关闭比较器
AD9854_WR_Byte(CTRL2_ADDRESS,CLK_Set); //设置系统时钟倍频
AD9854_WR_Byte(CTRL3_ADDRESS,0x00); //设置系统为模式0,由外部更新
AD9854_WR_Byte(CTRL4_ADDRESS,0x60); //设置为可调节幅度,取消插值补偿
// AD9854_WR_Byte(OSK_RAMP_DATE_ADDRESS,0x00);
// CRYSTAL_ON;
// GPIO_RSET(IODATA,GPIO_ALL.GPIO_SUM);
delay(100);
ad9854_update(); //更新AD9854输出
}
//====================================================================================
//函数名称:void AD9854_SetSine_double(double Freq,uint Shape)
//函数功能:AD9854正弦波产生程序
//入口参数:Freq 频率设置,取值范围为0~1/2*SYSCLK
// Amp 幅度设置. 为12 Bit,取值范围为(0~4095)
//出口参数:无
//====================================================================================
void AD9854_SetSine_double(double Freq,uint16 Amp)
{
uint8 count=0;
uint8 Adress=FTW1_ADDRESS;
Freq_double_convert(Freq); //频率转换
for(count=0;count<6;count++) //写入6字节的频率控制字
{
AD9854_WR_Byte(Adress++,AD9854_Addr_FRE1_config[6-count]);
}
AD9854_WR_Byte(OSK_I1_ADDRESS,Amp>>8); //设置I通道幅度
AD9854_WR_Byte(OSK_I2_ADDRESS,(uint8)(Amp&0xff));
AD9854_WR_Byte(OSK_Q1_ADDRESS,Amp>>8); //设置Q通道幅度
AD9854_WR_Byte(OSK_Q2_ADDRESS,(uint8)(Amp&0xff));
ad9854_update();
}
然后调用如下两个函数即可
ad9854_int();
AD9854_SetSine_double(455000,4095);
头文件如下:
#ifndef DDS_H
#define DDS_H
#include "csl_gpio.h"
#define AD9854_Addr_PHA1 0 // 2 Bytes
#define AD9854_Addr_PHA2 1 // 2 Bytes
#define AD9854_Addr_FRE1 2 // 6 Bytes
#define AD9854_Addr_FRE2 3 // 6 Bytes
#define AD9854_Addr_DELTA 4 // 6 Bytes
#define AD9854_Addr_UPDATA 5 // 4 Bytes
#define AD9854_Addr_RAMP_CLK 6 // 3 Bytes
#define AD9854_Addr_CTR_REG 7 // 4 Bytes
#define AD9854_Addr_I_MUL 8 // 2 Bytes
#define AD9854_Addr_Q_MUL 9 // 2 Bytes
#define AD9854_Addr_SHAPED 10 // 1 Bytes
#define AD9854_Addr_Q_DAC 11 // 2 Bytes
#define AD9854_Length_PHA1 2 // 2 Bytes
#define AD9854_Length_PHA2 2 // 2 Bytes
#define AD9854_Length_FRE1 6 // 6 Bytes
#define AD9854_Length_FRE2 6 // 6 Bytes
#define AD9854_Length_DELTA 6 // 6 Bytes
#define AD9854_Length_UPDATA 4 // 4 Bytes
#define AD9854_Length_RAMP_CLK 3 // 3 Bytes
#define AD9854_Length_CTR_REG 4 // 4 Bytes
#define AD9854_Length_I_MUL 2 // 2 Bytes
#define AD9854_Length_Q_MUL 2 // 2 Bytes
#define AD9854_Length_SHAPED 1 // 1 Bytes
#define AD9854_Length_Q_DAC 2 // 2 Bytes
typedef unsigned char uint8;
typedef unsigned int uint16;
union
{
unsigned char GPIO_SUM;
struct
{
unsigned int RES2:8;
unsigned int GOIO_7:1;
unsigned int GOIO_6:1;
unsigned int RES1:1;
unsigned int GOIO_4:1;
unsigned int GOIO_3:1;
unsigned int GOIO_2:1;
unsigned int GOIO_1:1;
unsigned int GOIO_0:1;
}GPIO_8;
}GPIO_ALL;
//parallel define
#define RESET_HIGH (GPIO_ALL.GPIO_8.GOIO_4=1)
#define RESET_LOW (GPIO_ALL.GPIO_8.GOIO_4=0)
#define WR_DIS (GPIO_ALL.GPIO_8.GOIO_6=1)
#define WR_EN (GPIO_ALL.GPIO_8.GOIO_6=0)
#define RD_DIS asm(" SSBX XF ") //XF置1 RD_DIS
#define RD_EN asm(" RSBX XF ") //XF置0 RD_EN
//#define CRYSTAL_ON (GPIO_ALL.GPIO_8.GOIO_4=1)
//#define CRYSTAL_OFF (GPIO_ALL.GPIO_8.GOIO_4=0)
#define UNCLOCK_HIGH (GPIO_ALL.GPIO_8.GOIO_7=1)
#define UNCLOCK_LOW (GPIO_ALL.GPIO_8.GOIO_7=0)
//serial define
#define IO_RESET_HIGH_SER (GPIO_ALL.GPIO_8.GOIO_0=1)
#define IO_RESET_LOW_SER (GPIO_ALL.GPIO_8.GOIO_0=0)
#define RESET_HIGH_SER (GPIO_ALL.GPIO_8.GOIO_1=1)
#define RESET_LOW_SER (GPIO_ALL.GPIO_8.GOIO_1=0)
#define CRYSTAL_ON_SER (GPIO_ALL.GPIO_8.GOIO_2=1)
#define CRYSTAL_OFF_SER (GPIO_ALL.GPIO_8.GOIO_2=0)
#define UNCLOCK_HIGH_SER (GPIO_ALL.GPIO_8.GOIO_7=1)
#define UNCLOCK_LOW_SER (GPIO_ALL.GPIO_8.GOIO_7=0)
//parallel address
#define FTW1_ADDRESS 0x04
#define FTW2_ADDRESS 0x05
#define FTW3_ADDRESS 0x06
#define FTW4_ADDRESS 0x07
#define FTW5_ADDRESS 0x08
#define FTW6_ADDRESS 0x09
#define UNCLOCK1_ADDRESS 0x16
#define UNCLOCK2_ADDRESS 0x17
#define UNCLOCK3_ADDRESS 0x18
#define UNCLOCK4_ADDRESS 0x19
#define CTRL1_ADDRESS 0x1D
#define CTRL2_ADDRESS 0x1E
#define CTRL3_ADDRESS 0x1F
#define CTRL4_ADDRESS 0x20
#define OSK_I1_ADDRESS 0x21
#define OSK_I2_ADDRESS 0x22
#define OSK_Q1_ADDRESS 0x23
#define OSK_Q2_ADDRESS 0x24
#define OSK_RAMP_DATE_ADDRESS 0x25
extern char dds_flag;
#endif
这样会输出一个满幅值的455KHz的正弦波形,幅度大约为-7dBm左右。
下次再写如何调制。