
写真1 AD9833 DDS MSOP 0.5ピッチ 変換基板に乗せる
それはさておき、
このチップは10ピンのMSOPで、写真にようにピンセットの先ほどの大きさです。
変換基板に取り付けましたが、ピンのピッチは0.5なので、半田付けにはちょっと技術が必要です。
まずチップをゲルタイプの瞬間接着剤で正確な位置に仮止めしておきます。
フラックスをほんのわずか塗って、すべてのピンにわざとまたがるくらい半田を盛ります。
半田吸い取り線で、余分な半田を吸い取って、出来上がり。
慣れれば簡単ですが、最初は数個パーにする覚悟がいります(笑)。
このDDSは、マスタクロック(MCLK)周波数は最高25MHzで、その場合最高発振周波数(ナイキスト周波数)は12.5MHzとなり、分解能は0.1Hzです。
今回は手持ち部品の関係で、20MHzのクリスタルを使用したので、10MHzまでのプログラマブルオシレータとして、実験してみました。この場合の分解能は約0.075Hzです。
PSoC3 AD9833 DDSによる波形発生
投稿日 2012/05/31
AD9833は、サイン波、三角波、方形波を発振できるDDSです。
2011年夏にチップワンストップで1個 587円で購入したものですが、現在(2012年5月)では872円になっています。他のチップも調べてみたら上がっているようです。

写真1 AD9833 DDS MSOP 0.5ピッチ 変換基板に乗せる
それはさておき、
このチップは10ピンのMSOPで、写真にようにピンセットの先ほどの大きさです。
変換基板に取り付けましたが、ピンのピッチは0.5なので、半田付けにはちょっと技術が必要です。
まずチップをゲルタイプの瞬間接着剤で正確な位置に仮止めしておきます。
フラックスをほんのわずか塗って、すべてのピンにわざとまたがるくらい半田を盛ります。
半田吸い取り線で、余分な半田を吸い取って、出来上がり。
慣れれば簡単ですが、最初は数個パーにする覚悟がいります(笑)。
このDDSは、マスタクロック(MCLK)周波数は最高25MHzで、その場合最高発振周波数(ナイキスト周波数)は12.5MHzとなり、分解能は0.1Hzです。
今回は手持ち部品の関係で、20MHzのクリスタルを使用したので、10MHzまでのプログラマブルオシレータとして、実験してみました。この場合の分解能は約0.075Hzです。

写真2 PSoC3にAD9833 DDSを接続して波形発生の実験 ロータリーエンコーダで周波数を変更する
インターフェースはSPIなので、マイコンで簡単にコントロールできます。
SPIのクロックは、40MHzまで対応しているので、スイーパーにもできそうです。
方形波だけでよいなら、内部のADコンバータを止めて省エネできます。
周波数レジスタ(28ビット)と位相レジスタを2組み持っており、位相の異なる2つの周波数を瞬時に切り替えることができます。無線機やFSK変調などに便利ですね。周波数の変更は、使っていない方のレジスタに行い、レジスタを切り替える方法で行うのが正しいやり方のようですが、今回はFREQ0レジスタのみを変更しています。
ほとんど外付け回路を必要としませんが、出力周波数が高くなるとサイン波とはほど遠い波形になるので、フィルターを通してやる必要があります。今回はフィルターを通さず、発生波形をそのまま観測することにしました。
PSoC3のコンポーネントについてですが、
設定周波数の表示にI2C LCDを使用したので、I2Cコンポーネントを使用ています。
周波数は1000KHzから上の桁をロータリーエンコーダで設定できるようにしました。このためのデジタル入力ピンコンポーネントを2つ使用しました。
赤ボタンで変更する桁を指定できます。変更可能な桁はカーソルが表示されます。
青ボタンで、サイン波、三角波、方形波を指定できます。
これらのボタン用にデジタル入力ピンを2つ使用しました。
ロータリーエンコーダ用に1msのクロック割り込みを使用します。
AD9833のコントロールにSPIですので、SPIコンポーネントを使用します。
【schematic】

写真3 黄色ボタン、緑ボタンは今回使用していない
AD9833への周波数の設定のプログラミングは簡単です。
まず、周波数を設定するための数値を以下の式で計算します。
設定する数値 = 設定したい周波数 / (MCLK / 2**28)
今回MCLKは20MHz、2の28乗(周波数レジスタは28ビット長)は2,684,354,560ですから、分母は20,000,000 / 684,354,560 = 0.074505806と計算できます。これは固定値ですのであらかじめ計算しておきます。
例えば設定したい周波数が1MHzの場合は、1,000,000 / 0.074505806 = 13421773となり、16進では0xCCCCCCです。
この計算結果を、14ビットずつ2つに分けて、AD9833に送ります。
14ビットは右寄せです。
まず0xCCCCCCの下位14ビットを、取り出すと0xCCCです。これがLSBワードです。
上位14ビットを14回右シフトして取り出すと、0x333です。これがMSBワードです。
最後に、AD9833は周波数設定レジスタが2個(FREQ0, FREQ1レジスタ)あるので、そのどちらかを指定する2ビットを最上位に付けます。
FREQ0の場合は、01なので、0x4000と論理和をとって、16ビットとし、AD9834に送ります。
LSB 0xCCC | 0x4000 = 0x4CCC
MSB 0x333 | 0x4000 = 0x4333
LSBとMSBのどちらを先に送っても構いませんが、直前にコントロールワードを送って指示します。
コントロールワードでは、14ビット分割転送、LSB/MSB、FREQ0/1のどちらを出力するか、PHASE0/1いずれのフェーズレジスタを使用するかなどを指定します。
今回は14ビット2分割転送、出力はFREQ0、位相レジスタは使わないのでとりあえずPHASE0(PHASE0レジスタは0なので位相ずれなし)としたので、以下のようになります。
サイン波の場合、
0x1000 コントロールワード1 MSB指定
0x4333 MSB
0x0000 コントロールワード2 LSB指定
0x4CCC LSB
三角波、方形波はコントロールワードで指定します。
【観測波形】

写真3 100KHz サイン波

写真4 100KHz 三角波

写真5 100KHz 方形波

写真6 1MHz サイン波

写真7 1MHz 三角波

写真8 1MHz 方形波

写真9 10MHz サイン波

写真10 10MHz 三角波

写真11 10MHz 方形波
【program】
//main.c (部分:変数宣言、ロータリエンコーダ、I2C LCDの部分等は省略)
void set_freq(void){
sprintf(string, "%5u000", counter);
I2C_LCD_WriteString(5, 1, string);
setval = ((uint32)(counter) * 1000) / 0.074505806;
lsb = (uint16)(0x00003FFF & setval);
msb =(uint16)(setval >> 14) & 0x00003FFF;
SPIM_WriteTxData(0x1000 | mode_bit);
SPIM_WriteTxData(msb | 0x4000);
SPIM_WriteTxData(0x0000 | mode_bit);
SPIM_WriteTxData(lsb | 0x4000);
}
void main(){
CyGlobalIntEnable;
isr_Clock_1ms_StartEx(Clock_1ms_Interrupt);
I2C_Start();
I2C_LCD_Init();
I2C_LCD_WriteString(0, 0, "AD9833 DDS" );
I2C_LCD_WriteString(0, 1, "SIN: Hz" );
I2C_LCD_SetCursor(12, 1);
SPIM_Start();
Set_CursorPos(change_pos);
for( ;; ){
if(RED_SW_Read() == 0){
CyDelay(WAIT_MS);
if(RED_SW_Read() == 0) {
change_pos++;
if(change_pos == 8) change_pos = 3;
Set_CursorPos(change_pos);
}
}
if(BLUE_SW_Read() == 0){
CyDelay(WAIT_MS);
if(BLUE_SW_Read() == 0) {
mode++;
if(mode == 4) mode = 1;
Set_mode(mode);
}
}
if(change != 0){
if(change_pos == 3) counter = counter + (change * 1);
if(change_pos == 4) counter = counter + (change * 10);
if(change_pos == 5) counter = counter + (change * 100);
if(change_pos == 6) counter = counter + (change * 1000);
if(change_pos == 7) counter = counter + (change * 10000);
set_freq();
change = 0;
Set_CursorPos(change_pos);
}
CyDelay(100);
}
}
(JF1VRR)