2009年寒假前幾天,第一次用51單片機寫AD9954程序,仔細讀了一遍datasheet、并參考前面同學的示例程序之后,只簡單的實現了單頻輸出(Single-tone Mode)。
一開始調試,先要正確控制SYNC_CLK,因為這個輸出引腳就是內部DDS時鐘的4分頻(假設DDS時鐘最高為400MHz,那么SYNC_CLK此時應當輸出100MHz;反之,通常用SYNC_CLK來推測DDS系統時鐘)。前提是必須復位Control Function Register No.1(CFR1:0x00)中的bit1(SYNC_CLK Disable)。
然后根據輸入時鐘的頻率正確設置CFR2中的倍頻系數REFCLK Multiplier和VCO Range(0:100~250MHz;1:250~400MHz)。只要外部電路沒什么錯的地方,SYNC_CLK一般都OK了。
用了才發現,AD9954真的還不錯,400MHz的系統時鐘就先不說了,居然可以用控制字Amplitude Scale Factor (ASF:0x02)調節輸出信號的幅度,前提是打開CFR1中的OSK Enable。并且14bit的長度也能夠達到足夠高的幅度控制精度了。當時作信號源的時候,還用外接AD835+TLV5638控制幅度,現在想來真是憨啊。
還有就是,輸出信號的相位可調。控制字Phase Offset Word(POW0 0x05)中含有14bit的相位偏移控制字,因此相位調節的精度也是相當高的,可達360°/16384 = 0.022°,在大多數情況下肯定夠用,比AD9851的5bit控制字(360°/32 = 11.25°)強多了。具體見程序1。
然后想嘗試一下線性掃頻功能(Linear-sweeping Mode),調了一整天都沒出來,然后就放假回家了。
最近在搞畢業設計(頻率特性測試儀Frequency Response Analyzer)的同時,又把原來的AD9954測試板拿出來調試,Single-Tone Mode當然是沒問題的,這次主要是再一次研究Linear-Sweeping Mode。于是打開原來寫的程序,看了一會兒,調了一會兒,突然發現一個極其簡單的錯誤——控制字的一個字節位置寫錯了,改過來再測試,一切OK。具體見程序2。去年居然花了一整天去查都沒查出來,Wordless。
好了,現在該最后一關了——RAM模式。Datasheet有關章節再看了一遍,然后大概寫了一個程序試了一下,出來的波形一團糟。于是參考了AD官網的AD9954示例代碼(ASM的,具體見程序3),并和自己寫的一步一步對比,最后終于搞定了。是因為向RAM寫數據的時候,只需要在第一次送數據前送一次RAM指令字節(RAM:0x0b),具體見程序4。但是我沒注意到這一點,每次數據前都送一遍0x0b,結果就悲劇了。不過最后還是發現原因了,嘿嘿!
下圖是RAM Segment Address Ramp Rate設置為0x0400(1024)時的切換時間測量波形。兩個光標之間的時間大概是10.24us,因為10.24us = 1024×10ns,說明更新速率是10ns,即SYNC_CLK,和線性掃頻時的最快頻率更新速度一樣。
利用AD9954的RAM Mode可以很方便的實現對數掃頻,只需要計算出相應的對數頻率點并存儲進RAM即可。
除此之外,AD9954還可以實現高速調頻波。如果固定波表1000個點,那么調制波的頻率可以是100kHz,50kHz,33.33kHz……,即100/n kHz(n正整數)。如果采用不定波表500~999個點,則可以實現200kHz以內的,調制波的頻率步進不大于0.4%的調頻波。但實現起來有些麻煩,所以一般不用AD9954作調制波頻率連續可調的調頻波信號源。
現在AD9954的程序部分了解得差不多了,等畢業設計結束之后,有時間了就升級一下以前做的信號源。AD835,TLV5638直接去掉,再加入比較基礎的調頻/調幅功能,還有就是加入一個EEPROM用于幅度校準存儲。另外,硬件電路方面做一板PCB降降噪聲,同時功放輸出的功率也要提升到10Vpp@50歐負載。
下面是部分程序,與有興趣的朋友們一起分享(才起步,拙劣之處還請多多包涵):
公共程序段:
#include< reg51.h>
#include< absacc.h>
#include< intrins.h>
#define uchar unsigned char
sbit ioupdate = P1^0;
sbit sdio = P1^1;
sbit clk = P1^2;
sbit adcs = P1^3;
sbit adreset = P1^4;
sbit tlvcs = P1^5;
sbit ps0 = P1^6;
void send(uchar dat)
{
uchar i;
for(i=0;i< 8;i++)
{
clk = 0;
dat = _crol_(dat,1);
sdio = dat&0x01;
clk = 1;
}
}
程序1:(Single-Tone Mode)
void main()
{
P1 = 0xff;
adreset = 0;
adcs = 0;
send(0x00); //CFR1
send(0x02); //bit1 OSK Enable,bit0 Auto OSK Enable;
send(0x00);
send(0x00);
send(0x42); //bit6 comp PD,bit1 SYNC_clk Disable;SYNC_clk = DDSclk/4;
ioupdate = 0;
ioupdate = 1;
send(0x01); //CFR2
send(0x00); //not used;
send(0x08); //bit3 High Speed SYNC Enable;
send(0xa4); //bit7-bit3 REF clk Multiplier factor;bit2 VCO Range
//(0:100-250;1:250-400);bit1-bit0 Charge Pump;
send(0x02); //ASF,when OSK Enabled(CFR1 bit25);
send(0x3f);
send(0xff);
send(0x04); //FTW0 0x 00 a3 d7 0a=1MHz (0x ff ff ff ff ==> 400MHz)
send(0x00);
send(0xa3);
send(0xd7);
send(0x0a);
send(0x05); //POW0,Phase Initial
send(0x00);
send(0x00);
ioupdate = 0;
ioupdate = 1;
adcs = 1;
adcs = 0; //POW0.Phase shift 180 (0x 3f ff ==> 360)
send(0x05);
send(0x20);
send(0x00);
adcs = 1;
ioupdate = 0;
ioupdate = 1;
}
程序2:(Linear-Sweeping Mode)
void main()
{
P1 = 0xff;
adreset = 0;
adcs = 0;
send(0x00); //CFR1
send(0x00);
send(0x20); //bit5 Linear Sweeping Enable
send(0x00);
send(0x46); //bit2 Linear Sweeping No-Dwell
ioupdate = 0;
ioupdate = 1;
send(0x07); //NLSCW
send(0x10);
send(0x00);
send(0x00);
send(0x00);
send(0x10);
send(0x08); //PLSCW
send(0x10);
send(0x00);
send(0x00);
send(0x00);
send(0x10);
send(0x04); //FTW0 0x 00 a3 d7 0a ==1MHz (0x ff ff ff ff ==> 400MHz)
send(0x00);
send(0xa3);
send(0xd7);
send(0x0a);
send(0x06); //FTW1 0x 01 68 72 b0 ==2.2MHz (0x ff ff ff ff ==> 400MHz))
send(0x01);
send(0x68);
send(0x72);
send(0xb0);
adcs = 1;
ioupdate = 0;
ioupdate = 1;
ps0 = ~ps0; //Toggle ps0 to sweep;
ps0 = ~ps0;
}
程序3:(AD9954_ADIcode)
程序4:(RAM Mode)
void main()
{
P1 = 0xff;
ps0 = 0;
adreset = 0;
adcs = 0;
send(0x01); //CFR2
send(0x00); //not used;
send(0x00); //bit3 High Speed SYNC Enable;
send(0xa4); //bit7-bit3 REF clk Multiplier factor; bit1-bit0 Charge Pump;
send(0x04); //FTW0;
send(0x12);
send(0xf6);
send(0x84);
send(0xbe);
ioupdate = 0;
ioupdate = 1;
send(0x00); //CFR1
send(0x80); // bit7 RAM Enable;bit5-3 Internal Profile Control
send(0x00);
send(0x02); //bit1 SDIO Only;
send(0x00); //bit6 comp PD,bit1 SYNC_clk Disable;SYNC_clk = DDSclk/4;
send(0x02); //ASF,when OSK Enabled(CFR1 bit25);
send(0x3f);
send(0xff);
ioupdate = 0;
ioupdate = 1;
send(0x07); //RSCW0;ps0 = 0; ps1 = 0;
send(0xff); //RAM Segment Address Ramp Rate< 7:0>
send(0xff); //RAM Segment Address Ramp Rate< 15:8>
send(0x07);
send(0x00); //Segment0 Address:0x00000-0x00007
send(0x00); //RSCW0
send(0x08); //RSCW1;ps0 = 1; ps1 = 0;
send(0xff); //RAM Segment Address Ramp Rate< 7:0>
send(0xff); //RAM Segment Address Ramp Rate< 15:8>
send(0x00);
send(0x01); //Segment1 Address:0x00000-0x00001
send(0x04);
adcs = 1;
ioupdate = 0;
ioupdate = 1;
adcs = 0;
send(0x0b); //RAM
send(0x00); //stall freq into RAM from the final address to beginning address;
send(0xa3);
send(0xd7);
send(0x0a); //RAM0 1MHz
send(0x00);
send(0xf5);
send(0xc2);
send(0x8f); //RAM1 1.5MHz
send(0x01);
send(0x47);
send(0xae);
send(0x14); //RAM2 2MHz
send(0x01);
send(0x99);
send(0x99);
send(0x99); //RAM3 2.5MHz
send(0x01);
send(0xeb);
send(0x85);
send(0x1e); //RAM4 3MHz
send(0x02);
send(0x3d);
send(0x70);
send(0xa3); //RAM5 3.5MHz
send(0x02);
send(0x8f);
send(0x5c);
send(0x28); //RAM6 4MHz
send(0x02);
send(0xe1);
send(0x47);
send(0xae); //RAM7 4.5MHz
ps0 = 1;
send(0x0b); //RAM Instruction Again
send(0x03);
send(0x33);
send(0x33);
send(0x33); //RAM0 5MHz
ioupdate = 0;
ioupdate = 1;
send(0x07); //RSCW0;ps0 = 0; ps1 = 0;
send(0x00); //RAM Segment Address Ramp Rate< 7:0>
send(0x04); //RAM Segment Address Ramp Rate< 15:8>
send(0x07);
send(0x00);
send(0x60); //RAM Mode of Operation: Continuous Bidirectional Ramp
adcs = 1; //RSCW0
ioupdate = 0;
ioupdate = 1;
}

