AD9851 は Arduino で一度動かしてみましたが、LPC1114/mbed な環境でも動かしてみました。


DDS モジュールの定格は5Vですが、3.3Vで動かしてみています。振幅は当然減りますが、ちゃんと70MHzぐらいまでは波形が確認できました。

コード

Arduino のコードとほぼ一緒です。というか殆ど正規表現で置換しただけで動かすことができました。GPIO の操作だけなので本当に頭を一切使わずに移植できました。

GCC かつ -std=c++14 な環境なため mbed のオンラインコンパイラではコンパイルできないと思います (すこし修正すればいけるはずですが C++14 が使えない環境に興味がないので……)

また、なんとなくシリアル経由で周波数を変えるインターフェイスにしてみました。mbed のライブラリに CircularBuffer があるので簡単です。C++ の STL に circular buffer / ring buffer 相当のものがないのが不思議なんですが、いつか入る予定はあるんでしょうかね?

#include "mbed.h"
#include <CircularBuffer.h>
#include <cstdlib>
#include <string>

template <uint32_t CLKIN, bool MULTIPLIER>
class AD9851 {
	static constexpr double PHASE_FACTOR = 0x100000000 / (double)(CLKIN * (MULTIPLIER ? 6 : 1));

	DigitalOut PIN_DATA;
	DigitalOut PIN_FQ_UD;
	DigitalOut PIN_W_CLK;
	DigitalOut PIN_RESET;

	void serial_write(uint32_t freq, uint8_t phase, bool powerdown) {
		// freq (delta phase)
		for (int i = 0; i < 32; i++) {
			PIN_DATA = (freq>>i & 1);
			PIN_W_CLK = 1; wait_us(4);
			PIN_W_CLK = 0; wait_us(4);
		}

		// control bits
		PIN_DATA = MULTIPLIER ? 1 : 0;
		PIN_W_CLK = 1; wait_us(4);
		PIN_W_CLK = 0; wait_us(4);
		PIN_DATA = 0;
		PIN_W_CLK = 1; wait_us(4);
		PIN_W_CLK = 0; wait_us(4);

		// powerdown
		PIN_DATA = powerdown ? 1 : 0;
		PIN_W_CLK = 1; wait_us(4);
		PIN_W_CLK = 0; wait_us(4);

		// phase
		for (int i = 0; i < 5; i++) {
			PIN_DATA = (phase>>i & 1);
			PIN_W_CLK = 1; wait_us(4);
			PIN_W_CLK = 0; wait_us(4);
		}

		PIN_FQ_UD = 1; wait_us(4);
		PIN_FQ_UD = 0; wait_us(4);
	}

public:
	AD9851(
			PinName data,
			PinName fq_ud,
			PinName w_clk,
			PinName reset
		) :
			PIN_DATA(DigitalOut(data)),
			PIN_FQ_UD(DigitalOut(fq_ud)),
			PIN_W_CLK(DigitalOut(w_clk)),
			PIN_RESET(DigitalOut(reset))
	{
		PIN_DATA = 0;
		PIN_FQ_UD = 0;
		PIN_W_CLK = 0;
		PIN_RESET = 0;
	}

	/**
	 * W0 ... W31  -> Freq (LSB first)
	 * W32, W33    -> Control (for factory test)
	 * W34         -> Power-Down
	 * W35 ... W39 -> Phase (LSB first)
	 */

	void reset() {
		// ensure low
		PIN_DATA = 0;
		PIN_FQ_UD = 0;
		PIN_W_CLK = 0;

		// reset
		PIN_RESET = 1; wait(1);
		PIN_RESET = 0; wait(1);

		// reset to serial mode
		// Pins of D0, D1 = 1, D2 = 0 for serial mode
		PIN_W_CLK = 1; wait_us(4);
		PIN_W_CLK = 0; wait_us(4);

		PIN_FQ_UD = 1; wait_us(4);
		PIN_FQ_UD = 0; wait_us(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);
	}
};

AD9851<30000000, true> ad9851(/*data*/dp28, /*fq_ud*/dp26, /*w_clk*/dp25, /*reset*/dp1);

//AnalogIn adc1(dp9);
//AnalogIn adc2(dp10);
//AnalogIn adc3(dp11);
//AnalogIn adc4(dp13);

Serial serial(USBTX, USBRX);

CircularBuffer<char, 80> serial_buffer;

int main() {
	serial.baud(115200);
	serial.printf("init\n");

	ad9851.reset();
	ad9851.set_frequency(10e6);

	for (;;) {
		if (serial.readable()) {
			char c = serial.getc();
			if (c == 0x0D) continue; // ignore CR
			if (c == 0x0A) { // treat LF as line end
				std::string line(80, '\0');
				line.clear();

				char c;
				while (serial_buffer.pop(c)) {
					line += c;
				}
				serial_buffer.reset();

				serial.printf("GOT: %s\n", line.c_str());

				uint32_t new_freq = std::atoi(line.c_str()) * 1e6;
				ad9851.set_frequency(new_freq);
				continue;
			}

			serial_buffer.push(c);
		}
	}
	return 0;
}

メモ: mbed 移植正規表現

S/digitalWrite\(([^,]+), ([^)]+)\)/\1 = \2/
s/delayMicroseconds/wait_us/g
s/delay/wait/g
  1. トップ
  2. tech
  3. AD9851 DDS モジュールを LPC1114/mbed と
▲ この日のエントリ