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