工作と競馬2

電子工作、プログラミング、木工といった工作の記録記事、競馬に関する考察記事を掲載するブログ

プログラマブル波形発生器IC AD9833 をESP-WROOM-32で動かす

概要

プログラマブル波形発生器IC AD9833 をESP-WROOM-32(ESP32)で動かし、波形を発生させてみた。




背景と目的

dekuo-03.hatenablog.jp

先日、デスクトップ型オシロスコープを買ったのだが、デスクトップ型オシロには信号発生器が付いていない。従来使用していた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レジスタ

データシートによると、出力したい周波数 f_{target}に応じてFREQ0レジスタ値を

 \displaystyle
FREQ0 = \frac{f_{target}}{f_{MCLK}}  * 2^{28}

という値にする。 f_{target}=1kHz f_{MCLK}=25MHzとすると、

 \displaystyle
FREQ0 = \frac{1000}{25 * 10^6}  * 2^{28}=10737

となる。10737を14ビットで分割すると、下位14ビット14LSBsが  10737 mod 16384 = 10737 、上位14ビット14MSBsは  10737 / 16384=0。これらの値を、さらに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である。また、マスタークロック f_{MCLK}は25MHzという仮定の下FREQ0の値を算出して、その通りの周波数の信号が出力されたので、結果的にマスタークロック f_{MCLK}は、25MHzで合っていた。


参考


まとめと今後の課題

プログラマブル波形発生器IC AD9833 をESP-WROOM-32(ESP32)で動かし、波形を発生させてみた。信号発生器自作に向けて、作業を進めていく。