前にこんな記事を書いて以来、aitendoのDDSモジュールも放置していたのですが、そろそろケースに入れたいのでまた触り始めました。
取り敢えず、SPIでいい加減動かさないと…ということでSPIから制御する話です。
使ったハードはArduino Duemilanoveなので(今となっては化石…)、Master側のSPI設定に困ることはないです。
1)ハード的な話
AD9850は、どうも2ピンがLow、3・4ピンがHighならばデフォルトでシリアル通信モードみたいです。aitendoにある回路図を見ると、2ピンに繋がっているJP1をジャンパしておけばGNDに落ちるみたいなので、パラレル→シリアルへの変換コマンドを送る必要はないみたいです。
出力ですが、IOUTが200ΩでGNDに落ちているので、そのまま出力インピーダンスも200Ωなのでしょうか…?評価キットの回路図では、IOUTBは25ΩでGNDに、IOUTは50ΩでGNDに落ちてますが…
2)ソフト的な話
AD9850のデータシートに書かれている、SPI通信のタイミングをみます。
AD9850 Data Sheet 英語 Rev H(http://www.analog.com/static/imported-files/data_sheets/AD9850.pdf)より転載 |
FQUP(FreQuency UPdate) → SS(10)
WCLK → SCLK(13)
D7 → MOSI(11)
SPI通信をするときには、幾つか設定しないといけない事がありますが、AD9850のデータシートを見る限りでは、以下の様になってるみたいです。
・動作モード
CLKの立ち上がりでデータをサンプリングするみたいです。又、通信していない時のCLKはLowなので、SPI_MODE0になります。
・データの送り方(BitOrder)
BitOrderは、データの送る順番がw0(LSB)から順にw1、w2、…、w31(MSB)なので、LSBFIRSTです。
・SS(FQUP)の制御
SPI通信では、先ず最初にSSを下げてから通信をしますが、どうも通信終わりのSS↑↓は自分でやらないといけないみたいです。
・AD9850のRESET信号
RESETを最初に落とすことになりますが、このRESETは正論理(!)なので、Resetしたい時に0にします。最初負論理だとてっきり思っていて、動かずに困りました…
・送るデータですが、EF_AD9850に依れば、
//Calculate the frequency of the HEX value x=4294967295/125;//Suitable for 125M Crystal frequence=frequence/1000000; frequence=frequence*x; y=frequence;らしいです。例えば40kHzであれば、0b00000000, 0b00010100, 0b11111000, 0b10110101になります。
最後のw32~39のControl Registerには、
bit[1:0] Control Serialならば00
bit2 Power Shutdown 0
bit[7:3] Phase
を書き込みます。
ということで、ArduinoのSPIを使うように改造しました。一応クラスにしてますが、8bitレジスタ5個分を送るだけの簡単なプログラムです。
class AD9850{ //7 reset //10 fqup //11 d7 //13 wclk private: public: AD9850(){}; ~AD9850(){}; //Initialize SPI & DDS(AD9850) void Init(){ //set pinMode(7, OUTPUT); //Send Reset signal digitalWrite(7, 0); digitalWrite(7, 1); digitalWrite(7, 0); //Init SPI SPI.begin(); SPI.setDataMode(SPI_MODE0); //Idle : clk low, rising edge. SPI.setBitOrder(LSBFIRST); }; //freq : Frequency[Hz] //w0 : Control Register Value void SetFrequency(const unsigned char w0, const double freq){ const double xtal_freq = 125; //125MHz Xtal const double x = (4294967295 / xtal_freq) / 1000000; long int y = (long int)(freq * x); SPI.transfer(y & 0xFF); SPI.transfer((y >> 8) & 0xFF); SPI.transfer((y >> 16) & 0xFF); SPI.transfer((y >> 24) & 0xFF); SPI.transfer(w0); //Control Register //FQUP digitalWrite(10, 1); digitalWrite(10, 0); }; };このプログラムを実機上で動かして、ロジック・アナライザで通信データを見てみたところ、下の写真のようになりました。
ロジアナで見たSPI通信 |
SPI.transfer()を1byteごとに呼んで送信しているため、1byteごとに何も通信していない部分(A2のMOSIが1になっているところ)がありますが、CLKもLowのままでサンプリングされてないので問題無いと思っています。
DigitalWrite()でSS(FQUP)を制御しているので、SPIの通信が終わってからSSが上がるまでに結構時間がかかっているみたいですが、まあ動いてるので大丈夫でしょう…
使い方は、前のライブラリ(EF_AD9850)とほぼ一緒。