ESP32 で波形信号発生モジュール AD9833 を制御して サイン波 を発生させてみる

記事公開日:2017年9月10日
最終修正日:2017年9月24日

スポンサーリンク

こんばんは。

いきなり、前回の記事の補足をします。
ESP-WROOM-32 ( ESP32 )のGPIO から方形波(パルス波)を出して、市販の電波時計を合わせてみましたが、ちょっとした情報が入ってきました。

実は、こちらの記事のコメント欄で Kat-Kai さんから有益な情報をいただき、ESP32 の CPUクロック数からμ秒オーダーのパルス長時間調整の方法を教えていただきました。
以下のブログでも紹介されていますので、合わせてご参照ください。
格段に安定した出力ができて、お勧めですヨ!

ESP8266/ESP32でのサブマイクロ秒の時間調整

さて、本題に戻りまして、前回の記事では電波時計の疑似標準電波 ( JJY )は方形波(パルス波)だったため、高調波ノイズを放出していました。
そのため、受信できる電波時計と受信できないものがあったり、時計を置く場所が微妙に難しかったりと、受信感度はあまり良くありませんでした。

そこで、今回は 40kHz のできるだけ純粋なサイン波(正弦波)をESP-WROOM-32 ( ESP32 )を使って出力してみたいと思います。
ただし、アナログデバイセズの AD9833 というプログラマブル波形発生器を搭載したモジュールを使用します。
要するに、Wave Generator ですね。

これ、使って見るとなかなか優れものです。
ESP-WROOM-32 ( ESP32 )で SPI通信で制御するのですが、ピッタリ 40kHz の驚くほどキレイなサイン波(正弦波)が出力できますし、周波数も Arduino IDE プログラミングで意外と簡単に変えられるんです。
こんなことだったら初めから使っておけば良かったと後悔しました。

これを使えば、無線電波の搬送波を作ることもできますし、オーディオ測定用信号発生器も作れそうですね。
シンセサイザーも作れそうです。

では、これの使い方を説明します。

準備するもの

AD9833 プログラマブル信号発生器モジュール

アナログデバイセズ社のプログラマブル波形発生器AD9833 を使ったモジュールです。
私は以下の物を使いました。

これは中国の販売店で、到着するまでに15日くらいかかりました。
格安なので仕方ないところです。
日本の販売店ではなかなかこのモジュールを見つけることが出来ませんでした。

秋月電子通商さんなどでも探したのですが、なかなか安価なサイン波発生モジュールは見当たりませんでした。

実際に購入した写真はこんな感じです。
ピンヘッダ(2.54mmピッチ)は付属していました。
25MHz 外部発信器がありますね。

ESP32_AD9833_01

裏側はこんな感じです。

ESP32_AD9833_02

上の部分の空白基板は任意にカットできるようですが、これはワザとそうしているのか、あるいはコスト削減のためなのかは分かりません。

ESP-WROOM-32 ( ESP32 )開発ボード

スイッチサイエンスさんの ESPr Developer 32 は保護機能が充実していてお勧めです。
ピンヘッダは別売りです。

ESPr® Developer 32

これの使い方は以下のページを参照してください。

ESPr Developer 32 ( スイッチサイエンス製 ) を使ってみました

その他、Amazon.co.jpさんでは ESP32-DevKitC があります。

ブレッドボード

サンハヤトさんの SAD-101 がお勧めです。

その他、超小型ブレッドボードもお勧めです。
SAD-101 と合体できます。

積層セラミックコンデンサ

●0.1μF ×1個
● 2200pF ×1個

AD9833 モジュールにもバイパスコンデンサが組み込まれていますが、新たにコンデンサを追加したことによって、私の場合は特性が良くなりました。

100MHz 級のオシロスコープ

40 kHz サイン波が純粋かどうかを測定するには、100MHz  sampling / sec 程度のオシロスコープが必要です。
私はこれを使っています。

これは簡易 FFT測定もできるので便利です。
プローブは別売りです。

ジャンパーワイヤー、パソコン、USBケーブル等

Arduino core for ESP32 の設定

事前に Arduino IDE の設定を済ませておきます。

Arduino IDE は 1.8.3 以上を使用してください。

Arduino core for ESP32 は最新版をインストールしてください。
インストール方法は以下のページを参照してください。

Arduino core for the ESP32 のインストール方法

接続する

では、AD9833 モジュールにピンヘッダをハンダ付けして、ブレッドボード上で下図を参照して接続してみてください。
( ESP32-DevKitC で説明してます )
バイパスコンデンサは任意で接続してみてください。
オシロスコープのノイズが少なくなれば良いです。
因みに、Arduino – IDE の SPIライブラリの HSPI 接続を使います。
HSPI については以下の記事を参照してください。

ESP32 の SPI_MODE が修正。HSPI , VSPI , 複数SPIデバイス制御 , SPI高速化などについて

ESP32_AD9833_10

写真ではこんな感じになります。

ESP32_AD9833_11

スケッチの入力

まず、アナログデバイセズ社のサイトにある、AD9833 のデータシートを参照してみてください。
以下のリンクにあります。
日本語なので有り難いです。

http://www.analog.com/media/jp/technical-documentation/data-sheets/AD9833_JP.pdf

これを読んでみて、その通りにプログラムを作ってもなぜかうまくいきません。

まず、疑問は図3のSPI通信のタイミングチャートです。
FSYNC が SPI通信の CS ( Chip Select )信号に当たります。
SDATA は MOSI ( Master Output Slave Input )信号です。

ESP32_AD9833_12

この図をパッと見る限り、SPI_MODE1 に見えますね。
(SPI_MODE については以下の記事を参照してください)
ESP8266 ( ESP-WROOM-02 ) SPI 通信高速化、その2 ( 複数デバイス、Mode、Watchdog Timer 問題 )

実はよく見ると、セットアップタイムとして、SCLKの HIGH が最低5ns 経過させることが必要で、次にLOW にした時点で SDATA のビットを読み込むというようになっています。
つまり、SCLK の最初は HIGH のままで良いということになるので、SPI_MODE2 で良いということになります。
これには随分悩まされました。
みなさん、気を付けてください。

そしてもう一つ。
次の計算式が意味不明でした。

ESP32_AD9833_13

この通りにプログラムを組んでも動かず、悩みに悩みました。

そしたら、edy さんや、JF1VRR さんの以下の記事に解決方法が掲載されていました。

JF1VRR さんの記事
PSoC3 AD9833 DDSによる波形発生

edy さんの記事
AD9833 DDSモジュールを試す(1)

なんか、データシートの計算式と違うような気もするし、私の読み間違いかもしれません。
データシートだけ読んでも、なかなか正しい計算式を導き出せませんでした。

でも、JF1VRRさんやedyさんのソースコードを拝見して、それでちゃんと動いたので今回はヨシとします。
JF1VRR さん、edy さん、ありがとうございました。
m(_ _)m

ということで、私なりに解釈し易いようにアレンジした以下のスケッチを入力してみてください。

#include <SPI.h>

const uint8_t SCLK_OLED =  14; //SCLK
const uint8_t MOSI_OLED =  13; //MOSI (Master Output Slave Input)
const uint8_t Fsync_PIN = 17; //CS (Chip Select)

const int SINE = 0b0010000000000000; //0x2000
const int TRIANGLE = 0b0010000000000010; //0x2002
const int SQUARE = 0b0010000000100000; //0x2020
const int SQUARE_half = 0b0010000000101000;

const float refFreq = 25000000.0;

SPIClass spi(HSPI);

void setup() {
  Serial.begin(115200);

  spi.begin(SCLK_OLED, 12, MOSI_OLED, Fsync_PIN);
  spi.setFrequency(40000000);
  spi.setDataMode(SPI_MODE2);

  pinMode(Fsync_PIN, OUTPUT);
  digitalWrite(Fsync_PIN, HIGH);

  Control_Resister_Write(0b0000000100000000); //Reset
  delay(50);
}

void loop() {
  AD9833_SetFrequency(10000, SINE);
  delay(3000);
  AD9833_SetFrequency(40000, SINE);
  delay(3000);
  AD9833_SetFrequency(20000, TRIANGLE);
  delay(3000);
  AD9833_SetFrequency(40000, TRIANGLE);
  delay(3000);
  AD9833_SetFrequency(20000, SQUARE);
  delay(3000);
  AD9833_SetFrequency(20000, SQUARE_half);
  delay(3000);
  AD9833_SetFrequency(50000, SQUARE);
  delay(3000);
  AD9833_SetFrequency(50000, SQUARE_half);
  delay(3000);
}

void AD9833_SetFrequency(uint32_t frequency, int Waveform) {
  uint32_t FreqWord = (frequency * pow(2, 28)) / refFreq;

  uint16_t MSB = (uint16_t)((FreqWord & 0xFFFC000) >> 14);
  uint16_t LSB = (uint16_t)(FreqWord & 0x3FFF);

  LSB |= 0b0100000000000000; //=0x4000
  MSB |= 0b0100000000000000; //=0x4000

  Control_Resister_Write(0b0010000000000000); //制御ワード書き込み
  Control_Resister_Write(LSB);
  Control_Resister_Write(MSB);

  Control_Resister_Write(0b1100000000000000); //位相シフトはゼロ
  Control_Resister_Write(Waveform);
}

void Control_Resister_Write(uint16_t b){
  digitalWrite(Fsync_PIN, LOW);
  spi.transfer16(b);
  digitalWrite(Fsync_PIN, HIGH);
}

【解説】

●1行目:
Arduino core for ESP32 標準の SPI ライブラリのインクルードです。

●3-5行:
HSPIインターフェース用に GPIO を設定します。

●7-10行:
ここで、サイン波、三角波、方形波を出力するためのレジスタ値を定義します。
16bit で初期化します。
16進数の方が文字数を減らすことが出来るのですが、データシートと照合しやすいように2進数表記しています。

●12行:
外部クロックの周波数を設定します。
ここでは発信器が 25MHz なので、その通りにします。

●14行:
Arduino core for ESP32 の HSPI接続を宣言して、クラス名を spi とします。
HSPI については以下の記事を参照してください。

ESP32 の SPI_MODE が修正。HSPI , VSPI , 複数SPIデバイス制御 , SPI高速化などについて

●19-21行:
SPIライブラリの初期化です。
GPIO #12 は実際使いませんが、HSPI接続のMISOなので、とりあえず12番としました。
AD9833 のSPI信号最高周波数は 40MHz までのようなので、一応最高周波数としました。
SPI MODE は先にも述べた通り、SPI_MODE2 とします。

●23-24行:
SPIライブラリを使う場合、ハードウェア CS ピンを使うと高速で処理してくれるのですが、それを使ってしまうと、他のSPI機器のハードウェアピンが使えなくなってしまうので、ここでは digitalWrite を使います。

●26行:
ここで、AD9833 をリセットします。

●31-46行:
メインループで波形や周波数を3秒毎に変えています。

●49-70行:
ここで周波数や位相、波形レジスタを書き込んで、OUT 端子から出力させています。
50行の計算式はデータシートを見ただけではなかなかこの計算式を導きだせません。
でも、これでちゃんと動作します。
52-56行はデータシートに記載されている通りの計算で、28ビットを14ビットづつ分割しています。
位相シフトは今回不要なのでゼロとしています。
63行目で波形レジスタをセットすると、サイン波、三角波、パルス波と選択できます。

●66-70行:
SPIライブラリの標準の16bitレジスタ出力方法です。

コンパイル書き込み実行

では、Arduino IDEでコンパイル書き込みをして、実行させてみてください。

AD9833 モジュールの OUT端子にオシロスコープのプローブを接続して波形を見ると、3秒毎にこんな感じに表示されると思います。

ESP32_AD9833_20

ESP32_AD9833_21

ESP32_AD9833_22

ESP32_AD9833_23

ESP32_AD9833_24

ESP32_AD9833_25

ESP32_AD9833_26

ESP32_AD9833_27

図のように、サイン波と三角波のピーク電圧値は0.65V 程度ですが、パルス波になると 3.3V 付近まで振れてくれます。
パルス波はハーフサイズのレジスタ値があるので、いろいろと使い道があるかもしれません。
サイン波はデジタルにしては意外とキレイな正弦波が出ていますね。
これは電波の搬送波として十分使えますよ。

まとめ

いかがでしたでしょうか?

これをトランジスタや FET で増幅すれば、電波の搬送波として十分使えます。
もう実験済みですが、電波時計の JJY 電波を出すことにも成功し、ガッツリと電波時計が合わせられるようになりました。
これは次回に紹介したいと思います。

これはオーディオ測定信号としても使えるし、シンセサイザーの VCO としても使えそうですね。
SPI通信で周波数をスイープさせるということもできます。
いろいろと使い道が考えられて、幅が広がりますね。

以上、今回はここまでです。

ではまた・・・。

mgo-tec電子工作 関連コンテンツ ( 広告含む )

スポンサーリンク

Amazon.co.jp 当ブログのおすすめ








投稿者:

mgo-tec

Arduino , ESP32 ( ESP-WROOM-32 ) , ESP8266 ( ESP-WROOM-02 )等を使って、主にスマホと連携した電子工作やプログラミング記事を書いてます。ライブラリも作ったりしてます。趣味、独学でやってますので、動作保証はしません。 電子回路やプログラミングの専門家ではありません。 畑違いの仕事をしてます。 でも、少しだけ電気の知識が必要な仕事なので、電気工事士や工事担任者等の資格は持ってます。

コメントを残す

メールアドレスが公開されることはありません。

*画像の文字を入力してください。(スパム防止の為)