ebay で800円ぐらいで買ったものです。
この手のモジュールにはAD9851(源クロック6倍周波数逓倍器付き)のものとAD9850のものがあり、さらに基板のタイプが2つあります。AD9850/AD9851は制御方法も含めてほとんど互換なので、源クロックとチップだけ違うものが出回っているみたいです。
試してみたのはおそらく古いタイプのもので、ブレッドボードには直接挿すことができないので、ちょっと面倒くさいタイプです。
周波数の設定・パワーダウンモードへの移行・設定位相(2台以上のDDSでsin/cos作る場合に使う)を40bitレジスタにまとめて突っ込む形になっています。
この40bitレジスタはパラレルモードとシリアルモードで設定でき、ググると大抵の例でシリアルモードを使ってるみたいです。
ただ、リセット直後はパラレルモードで起動するので、シリアルモードに変えてやる必要があります。といっても、D0=1 D1=1 D2=0 にした状態で、W_CLK パルスを送り、すぐ FQ_UD パルスを送るとシリアルモードに入るということになっています。
このモジュールの場合、ジャンパでD0=1 D1=1 D2=0 を設定できるようになっており、デフォルトでジャンパしてあるので、W_CLK と FQ_UD パルスをマイコンから送るだけで初期化できます。
コード
ライブラリみたいにしてあるのもありましたが、結局自分で書きました。
入手したモジュールは125MHzが源クロックでした。
#include <Arduino.h>
#include <Wire.h>
template <uint32_t CLKIN>
class AD9850 {
static constexpr double PHASE_FACTOR = 0x100000000 / (double)CLKIN;
const uint16_t PIN_DATA;
const uint16_t PIN_FQ_UD;
const uint16_t PIN_W_CLK;
const uint16_t PIN_RESET;
void serial_write(uint32_t freq, uint8_t phase, bool powerdown) {
// freq (delta phase)
for (int i = 0; i < 32; i++) {
digitalWrite(PIN_DATA, (freq>>i) & 1);
digitalWrite(PIN_W_CLK, HIGH); delayMicroseconds(4);
digitalWrite(PIN_W_CLK, LOW); delayMicroseconds(4);
}
// control bits
digitalWrite(PIN_DATA, LOW);
digitalWrite(PIN_W_CLK, HIGH); delayMicroseconds(4);
digitalWrite(PIN_W_CLK, LOW); delayMicroseconds(4);
digitalWrite(PIN_W_CLK, HIGH); delayMicroseconds(4);
digitalWrite(PIN_W_CLK, LOW); delayMicroseconds(4);
// powerdown
digitalWrite(PIN_DATA, powerdown ? HIGH : LOW);
digitalWrite(PIN_W_CLK, HIGH); delayMicroseconds(4);
digitalWrite(PIN_W_CLK, LOW); delayMicroseconds(4);
// phase
for (int i = 0; i < 5; i++) {
digitalWrite(PIN_DATA, (phase>>i) & 1);
digitalWrite(PIN_W_CLK, HIGH); delayMicroseconds(4);
digitalWrite(PIN_W_CLK, LOW); delayMicroseconds(4);
}
digitalWrite(PIN_FQ_UD, HIGH); delayMicroseconds(4);
digitalWrite(PIN_FQ_UD, LOW); delayMicroseconds(4);
}
public:
AD9850(
uint16_t data,
uint16_t fq_ud,
uint16_t w_clk,
uint16_t reset
) :
PIN_DATA(data),
PIN_FQ_UD(fq_ud),
PIN_W_CLK(w_clk),
PIN_RESET(reset)
{
pinMode(PIN_DATA, OUTPUT);
pinMode(PIN_FQ_UD, OUTPUT);
pinMode(PIN_W_CLK, OUTPUT);
pinMode(PIN_RESET, OUTPUT);
}
/**
* W0 ... W31 -> Freq (LSB first)
* W32, W33 -> Control (for factory test)
* W34 -> Power-Down
* W35 ... W39 -> Phase (LSB first)
*/
void reset() {
// ensure low
digitalWrite(PIN_DATA, LOW);
digitalWrite(PIN_FQ_UD, LOW);
digitalWrite(PIN_W_CLK, LOW);
// reset
digitalWrite(PIN_RESET, HIGH); delay(1);
digitalWrite(PIN_RESET, LOW); delay(1);
// reset to serial mode
// Pins of D0, D1 = HIGH, D2 = LOW for serial mode
digitalWrite(PIN_W_CLK, HIGH); delayMicroseconds(4);
digitalWrite(PIN_W_CLK, LOW); delayMicroseconds(4);
digitalWrite(PIN_FQ_UD, HIGH); delayMicroseconds(4);
digitalWrite(PIN_FQ_UD, LOW); delayMicroseconds(4);
}
void set_frequency(uint32_t frequency) {
set_frequency(frequency, 0);
}
void set_frequency(uint32_t frequency, uint8_t phase) {
uint32_t deltaPhase = PHASE_FACTOR * frequency;
serial_write(deltaPhase, phase, 0);
}
void powerdown() {
serial_write(0, 0, 1);
}
};
AD9850<125000000> ad9850(9, 10, 11, 12);
void setup() {
Serial.begin(9600);
ad9850.reset();
ad9850.set_frequency(10e6);
}
void loop() {
}
出力
商品説明だと40MHz まで出せると書いてありました。たしかに出せることは出せるようです。
このモジュールの出力には7次のローパスフィルタがついています。これはAD9851のデータシート通りの定数のフィルタのようで、70MHzぐらいにカットオフ周波数ががあるみたいです。
なおローパスフィルタの後の出力インピーダンスは200Ωになっているみたいです。
AD9850自体の出力は電流出力で、12ピンについている抵抗でフルスケールの出力電流が決まることになっています。このモジュールでは3.9kΩが実装されており、10mA フルスケールの出力に設定されています。200Ωで10mW(10dBm)。実際使う場合バッファして50Ω出力とする必要はありそうです。
片方だけにローパスフィルタが入っており、もう片方の出力は200Ωで電圧変換されて直接ピンヘッダに出ています。ということで差動出力には使えません。