概要
プログラマブル波形発生器IC AD9833 をESP-WROOM-32(ESP32)で動かし、波形を発生させてみた。
背景と目的
先日、デスクトップ型オシロスコープを買ったのだが、デスクトップ型オシロには信号発生器が付いていない。従来使用していたUSBオシロスコープPicoScopeには信号発生器が付いていた。なので、手元に信号発生器がなくなってしまい、少し不便に感じている。そこで、最近あまりやっていなかった電子工作を再開するにあたり、信号発生器を作ろうかと考えている。そこで、信号発生器のコアとなるプログラマブル波形発生器ICの動作を試す。
詳細
1. 部品調達
いろいろ検討した結果、価格と機能等を考慮して、AD9833というICを使う。そして、2.54mmピッチのピンヘッダでアクセスできる以下のモジュールが便利なので、これを購入。価格は約900円。
https://www.amazon.co.jp/gp/product/B0B5KV8XZF/ref=ppx_yo_dt_b_asin_title_o01_s04?ie=UTF8&psc=1www.amazon.co.jp
ちなみに、マスタークロックに応じて、周波数の分解能が変わるらしいが、マスタークロックの値が販売ページに書かれていない。なので、動かしながら確認する。
2. ESP32と接続
AD9833はSPI接続。ESP-WROOM-32には3系統のSPIバス VSPI, FSPI, HSPIがあるが、FSPIは内部フラッシュと接続され、VSPIの端子はI2Cと重複する。そこで、HSPIを使う。
信号名 | ピン番号 | AD9833 | 説明 |
---|---|---|---|
HSPI_SCK | IO14 | SCLK | |
HSPI_MISO | 接続なし | - | |
HSPI_MOSI | IO13 | SDATA | |
HSPI_SS | IO15 | FSYNC | |
3V3 | 3V3 | VCC | |
GND | GND | DGND | |
GND | GND | AGND |
なお、GNDとVCCの間には47uFの電解コンデンサをつけた。付けなくても動いたが。。。
3. Arduinoプログラムを作成
1kHz正弦波を出力することにする。
3.1 コントロールレジスタの設定
データシートをよく読み、値を決める。周波数を設定するレジスタは、28ビットモードを使用することにする。なので、B28=1。波形種類を正弦波にするので、OPBITEN=0, MODE=0とする。
3.2 FREQ0レジスタ値
データシートによると、出力したい周波数に応じてFREQ0レジスタ値を
という値にする。、とすると、
となる。10737を14ビットで分割すると、下位14ビット14LSBsが 、上位14ビット14MSBsは 。これらの値を、さらに8ビットで区切り、
- 14LSBs上位6ビット: 10737 / 64 = 0b101001
- 14LSBs下位8ビット: 10737 mod 64 = 0b11110001
- 14MSBs上位6ビット: 0 / 256 = 0b000000
- 14MSBs下位8ビット: 0 mod 256 = 0b00000000
となる。最後に、上位6ビットの上位2ビットに、FREQ0を選択するため0b01をつける。
3.3 ソースコード全体
#include <SPI.h> // 送信データ // 正弦波 1kHz byte data[6] = { // コントロール・レジスタ上位 // 各ビット: 0, 0, B28, HLB, FSELECT, PSELECT, 0, RESET // B28=1: 周波数レジスタ28ビット // HLB=0: B28=1なので無視 // FSELECT=0: 使用する位相アキュームレータ=FREQ0 // PSELECT=0: 位相アキュームレータ出力への加算用レジスタ=PHASE0 // RESET=0: リセットなし 0b00100000, // コントロール・レジスタ下位 // 各ビット: SLEEP1, SLEEP12, OPBITEN, 0, DIV2, 0, MODE, 0 // SLEEP1=0, SLEEP12=0: パワーダウンなし // OPBITEN=0, MODE=0, DIV2=X: サイン波出力 0b00000000, // FREQ0 14LSBs 0b01101001, 0b11110001, // FREQ0 14MSBs 0b01000000, 0b00000000 }; SPIClass hspi(HSPI); void setup() { // HSPI_SS設定 pinMode(15, OUTPUT); digitalWrite(15, HIGH); // 初期化 hspi.begin(14, -1, 13, 15); // 送信 digitalWrite(15, LOW); hspi.writeBytes(data, 6); digitalWrite(15, HIGH); } void loop() { }
追記
FREQ0レジスタ値4バイト分を算出する関数を作成
// f_target: 目標周波数[Hz] // FREQX: FREQ0, FREQ1の選択 void get_FREQX_register(double f_target, uint8_t FREQX, uint8_t FREQ28[]) { uint8_t FREQX_select; if (FREQX == 0) { FREQX_select = 0x40; // 0100 0000 } else { FREQX_select = 0x80; // 1000 0000 } unsigned long f_MSCK = 25 * 1000 * 1000; unsigned long LSB = (unsigned long) (0x10000000 * f_target / f_MSCK); unsigned long LSBs14 = LSB % 0x4000; unsigned long MSBs14 = LSB / 0x4000; FREQ28[0] = (LSBs14 / 0x0100) | FREQX_select; FREQ28[1] = LSBs14 % 0x0100; FREQ28[2] = (MSBs14 / 0x0100) | FREQX_select; FREQ28[3] = MSBs14 % 0x0100; }
4. 動作確認
以下の通り、所定の波形が出力されていることが確認できた。これ以外の波形・周波数についても、試し問題ないことを確認。波形の振幅は、約0.6Vppである。また、マスタークロックは25MHzという仮定の下FREQ0の値を算出して、その通りの周波数の信号が出力されたので、結果的にマスタークロックは、25MHzで合っていた。
参考
まとめと今後の課題
プログラマブル波形発生器IC AD9833 をESP-WROOM-32(ESP32)で動かし、波形を発生させてみた。信号発生器自作に向けて、作業を進めていく。