/*********************************************************************** * DDS_AD9834_Test * * Strawberry Linux社の「AD9834 小型 DDS モジュールキット」を試す。 * * LCD unlook busy : not switch direction (write fixed) * * CPU PIC24FJ64GA002 * * Condition: * 8MHz Internal RC oscillator, 4x PLL (8MHzx4= 32MHz) * Fcy=32MHz/2=16MHz, Tcy=62.5ns * * 2015/1/16(コメント整理の6MHzでの最終版) * 作成:N.Ishii ***********************************************************************/ #include "p24FJ64GA002.h" #include "LCD_Lib3.h" // Set Configuration Word 1 _CONFIG1 ( JTAGEN_OFF & // JTAG Port: OFF GCP_OFF & // Code Protect: OFF GWRP_OFF & // Write Protect:OFF BKBUG_OFF & // Background Debug: OFF COE_OFF & // Clip On Emulation: OFF ICS_PGx1 & // Select ICD Pin: EMUC/EMUD-> PGC1/PGD1 For Common Use FWDTEN_OFF // WDT: OFF ) // Set Configuration Word 2 _CONFIG2 ( IESO_OFF & // 2 Speed Start Up: OFF FNOSC_FRCPLL & // 8MHz Internal RC oscillator, 4x PLL-> 8MHzx4=32MHz FCKSM_CSDCMD & // Change Clock Control: OFF Clock Monitor: OFF OSCIOFNC_ON & // OSCO/RA3 function: Used RA3(外部OSCを使う時は、OSCIOFNC_OFFと記述) IOL1WAY_OFF & // RP Register Protection: Unlimited Writes To RP Registers I2C1SEL_PRI & // I2C1 pins Select: Use Primary I2C1 pins POSCMOD_NONE // Oscillator Selection: Primary disabled ) /// DDSコントロールポート定義 #define DDS_FSYNC LATBbits.LATB4 // AD9834 sync #define DDS_SCLK LATAbits.LATA4 // AD9834 clock #define DDS_SDATA LATBbits.LATB5 // AD9834 data char FSW; char SQ= 0; // 設定シーケンスNo. char OldTemp; // 1つ前の、FSWの値 /// 関数プロトタイプ宣言 void dds_dataset(unsigned long data, unsigned int bt); void freq_to_serial(float f); void FrqRegSet(void); void AD9834_PowerUp(void); /***************** * メイン関数 ******************/ int main(void) { CLKDIV= 0; // クロック分周 1:1 AD1PCFG= 0xFFFF; // 全ポートをディジタルに指定 /// ポートの入出力モード設定 TRISA= 0xFFE6; // RA4:SCLK OUT, RA3:赤LED, RA2-1:NOT USED IN, RA0:SCLK_OUT 141224 TRISB= 0x03CF; // RB15-12:D7-4_OUT, RB11:RS_OUT, RB10:STB_OUT, // RB9-6:FSW-8,4,2,1_IN, RB5:SDATA_OUT, RB4:FSYNC_OUT, RB3-2:NOT USED IN, RB1-0:SW2、SW1 /// LED消灯 LATAbits.LATA3= 1; // 赤 /// 内部プルアップ設定 CNPU1= 0x0003; // RB1(CN4):SW1, RB0(CN5):SW2 CNPU2= 0x01E0; // RB6(CN24):FSW-1,RB7(CN23):FSW-2,RB8(CN22):FSW-4,RB9(CN21):FSW-8 /// オープンドレイン出力設定 ODCA= 0x0010; // RA4:SCLK 131224 ODCB= 0x0030; // RB4:FSYNC, RB5:SDATA /// DDS初期化の前に、MCLKが安定するまでの待機時間を追加 delay_ms(100); /// DDS制御信号レベル初期化と、DDSリセットコマンド転送 DDS_FSYNC= 1; // FSYNC(CS)は、アクティブローなので、待機時は、'1' DDS_SCLK= 1; // AD9834は、立下りエッジ読込みなので、待機時は、'1' DDS_SDATA= 0; // DATAは、'0'待機 /// AD9834 Power Up AD9834_PowerUp(); /// 開始メッセージ出力 lcd_init(); // LCD初期化 lcd_clear(); // 全消去 lcd_str("DDS AD9834 Test"); // タイトル1行目表示 /// Main Loop while(1) { FSW= (~PORTB & 0x03C0) >> 6; // Read Decimal Dip SW(出力周波数選択ディップSW読込み) switch(SQ){ case 0: //// 電源投入後、1回目の、Fレジ設定転送 OldTemp= FSW; FrqRegSet(); SQ= 1; break; case 1: //// 2回目以降の、Fレジ設定転送 if(FSW != OldTemp){ // FSWの設定を変えた時のみ、Fレジ更新 OldTemp= FSW; AD9834_PowerUp(); // 設定を変更した場合もパワーアップが必要。これがないと更新しない時がある。 FrqRegSet(); } break; default:; break; } } } /************************************************************************** * serial data send (MSB first) * 16ビット(bt=16で指定)SPI転送 * AD9834は、SCLKの立下りエッジでデータを読込む (SCLK≒約4MHz) ****************************************************************************/ void dds_dataset(unsigned long data, unsigned int bt) { unsigned int i; DDS_FSYNC = 0; for(i = bt; i > 0 ; i--) { DDS_SDATA = (data >> (i - 1)) & 0x00000001; asm("clrwdt"); //Td=125nS(62.5nS x 2) この遅延を入れないと誤動作する。 DDS_SCLK = 0; asm("clrwdt"); //Td=125nS(62.5nS x 2) クロックのデューティを50%に確保するために入れた。 DDS_SCLK = 1; } DDS_FSYNC = 1; } /***************************************************************** * AD9834 DDS control (frequency to serial code) * 希望の出力周波数から、シリアルコードを算出し、シリアル転送する。 ******************************************************************/ void freq_to_serial(float f) { unsigned long msb, lsb; unsigned long data; data = (unsigned long)(f * 44.7392426); // 小数点計算の結果を、32bit整数型へキャストしてみた。 msb = (data >> 14) + 0x4000; // 上位14bit送信データ+4000H(周波数レジスタアドレス指定(b15=0.b14=1):FREQ0レジ)を、msbにセット lsb = (data & 0x00003fff) + 0x4000;// 下位14bit送信データ+4000H(周波数レジスタアドレス指定(b15=0.b14=1):FREQ0レジ)を、lsbにセット dds_dataset(0x2028, 16); //// 制御レジへの書込み // bit13:B28='1':2つの連続した16bit転送で完全なコントロールワードをロード // bit9:PIN/SW= '0',bit8:RESET= '0':リセットビットをリセット(RESET OFF) // bit5:OPBITEN= '1':SB-OUTピン有効 // bit4:SIGNPIB= '0',bit3:DIV2= '1':SB-OUTに出力(サイン出力と同じ周波数で出力) // bit1:MODEビット= '0':サイン波出力 // dds_dataset(0x2020, 16); // bit4:SIGNPIB= '0',bit3:DIV2= '0':SB-OUTに出力(サイン出力の、1/2周波数で出力) // dds_dataset(0x2038, 16); // bit4:SIGNPIB= '1',bit3:DIV2= '1':コンパレータ方形波をSB-OUTに出力 // dds_dataset(0x2000, 16); // サイン波のみの出力 dds_dataset(lsb, 16); // lsb転送(下位14ビットの周波数レジスタ0のデータを、b15,14のコントロールビットと共に転送) dds_dataset(msb, 16); // msb転送(上位14ビットの周波数レジスタ0のデータを、b15,14のコントロールビットと共に転送) dds_dataset(0xC000, 16); // 位相レジスタ初期化:0 } /****************************************************************************** * AD9834_PowerUp * デバイスをRESETし、周波数レジスタと位相レジスタに、初期値として、0を書込む。 * その後、RESETを解除する。 *******************************************************************************/ void AD9834_PowerUp(void) { dds_dataset(0x2100, 16); // 制御レジへの書込み:bit13:B28ビット= '1':2つの連続した16bit転送で完全なコントロールワードをロード // bit9:PIN/SW= '0',bit8:RESET= '1':リセットビットをセットし、DDS RESETを掛ける // bit5:OPBITENビット= '0':デジタル出力禁止、bit1:MODEビット= '0':サイン波出力 dds_dataset(0x4000, 16); // lsb転送(下位14ビットの周波数レジスタ0のデータを、b15,14のコントロールビットと共に転送) dds_dataset(0x4000, 16); // msb転送(上位14ビットの周波数レジスタ0のデータを、b15,14のコントロールビットと共に転送) dds_dataset(0xC000, 16); // 位相レジスタ初期化:0 dds_dataset(0x2000, 16); // DDS RESETを解除する。 } /*************************************************** * FSW読込み値に従い、Fレジを設定転送する ****************************************************/ void FrqRegSet(void) { switch(FSW){ case 0: freq_to_serial(10); // 10Hz lcd_cmd(0xC0); // 2行目の先頭に移動 lcd_str(" Frq= 10Hz"); break; case 1: freq_to_serial(100); // 100Hz lcd_cmd(0xC0); // 2行目の先頭に移動 lcd_str(" Frq= 100Hz"); break; case 2: freq_to_serial(1000); // 1kHz lcd_cmd(0xC0); // 2行目の先頭に移動 lcd_str(" Frq= 1000Hz"); break; case 3: freq_to_serial(10000); // 10kHz lcd_cmd(0xC0); // 2行目の先頭に移動 lcd_str(" Frq= 10000Hz"); break; case 4: freq_to_serial(100000); // 100kHz lcd_cmd(0xC0); // 2行目の先頭に移動 lcd_str(" Frq= 100000Hz"); break; case 5: freq_to_serial(200000); // 200kHz lcd_cmd(0xC0); // 2行目の先頭に移動 lcd_str(" Frq= 200000Hz"); break; case 6: freq_to_serial(300000); // 300kHz lcd_cmd(0xC0); // 2行目の先頭に移動 lcd_str(" Frq= 300000Hz"); break; case 7: freq_to_serial(400000); // 400kHz lcd_cmd(0xC0); // 2行目の先頭に移動 lcd_str(" Frq= 400000Hz"); break; case 8: freq_to_serial(500000); // 500kHz lcd_cmd(0xC0); // 2行目の先頭に移動 lcd_str(" Frq= 500000Hz"); break; case 9: freq_to_serial(1000000); // 1MHz lcd_cmd(0xC0); // 2行目の先頭に移動 lcd_str(" Frq= 1000000Hz"); break; default:; break; } }