概要
ADAU1401/ADAU1701 DSPmini 学習ボードで遊ぶための環境整備を行った。
背景と目的
以前から、ディジタルクロスオーバーネットワークで帯域分割して自作のスピーカーをマルチアンプ駆動したいと考えている。そのためには、DSPを用いて信号処理を行う必要がある。いろいろ検討した結果、市販品を使う手もあるがどうせならディジタルクロスオーバーネットワーク自体を自作してみようと思った。
今回、手始めにAnalog Devices製のDSP ADAU1401/ADAU1701が搭載された DSPmini 学習ボードを使ってみる。
詳細
1. ボードの調達
Analog Devices製のDSP ADAU1401/ADAU1701が搭載された DSPmini 学習ボードは、以下のようなものである。
AmazonやAliExpressで3000円程度と安価に購入できる。
Analog Devices社純正のUSBiエミュレータと呼ばれるUSB接続のデバイスを使ってボードとPCと接続し、SigmaStudioという専用ソフトウェアで簡単にディジタルフィルタの設計と設定値の送信が可能である。
ステレオのアナログ入力と4ch出力ができるようなので、ひとまず2wayのクロスオーバーネットワークを組むことができそうだ。
なお、ボードは四隅にネジ穴がないので、3Dプリンターでボードを支えるフレームを作成し、スペーサが取り付けられるようにした。

2. 環境の構想
今回は、都合によりUSBiエミュレータが入手できなかったので、専用ソフトウェアであるSigmaStudioも用いず強引に自前でI2C通信により設定を行えるように、環境を整えていく。手持ちの部材で簡単にできそうな手段として思いついたのが、
- ESP32 DevKit-CをPCと接続し、シリアルをI2Cに変換するソフトウェアを構成してPCからシリアル経由でDSPボードを制御する
という方法。要するに、USBiエミュレータがやっているようなことをやってしまおうということ。PC側は、当然SigmaStudio相当のアプリケーションが必要になってくるが、上記の接続が確立してしまえばある意味自由に作れるので、そちらも自前で作ってしまえばよいと考えている。
ということで、今回まずはESP32 DevKit-CのソフトウェアとDSPボードとの接続を行う。
3. 接続
DSPボードと、ESP32 DevKit-Cの接続は以下とした。
- GPIO21 <--> SCL 2.2kΩで3.3Vにプルアップ
- GPIO22 <--> SDA 2.2kΩで3.3Vにプルアップ
- 5V <--> 5V
- GND <--> GND
なお、調べたところ、DSPボードのSCL、SDAは何もつながない状態で3.3Vとなっていたので3.3V系の信号ラインとなっている。そのため、プルアップ抵抗も3.3V系へ接続した。
3. シリアル-I2C ブリッジのソフトウェア
ひとまず、I2Cのレジスタ値読み取りができればよいので、Arduino IDE上でシリアルからデータを送信し、DSPから読み出した値がシリアルで返ってくるようにしてみた。
3.1 ADAU1701.h
ADAU1701のI2C通信を抽象化したクラスを作成。なお、今回は書き込み部は未実装。あとで追加予定。
#include <Wire.h> class ADAU1701 { public: ADAU1701() { } /* 初期化 */ void begin(uint8_t i2c_addr, uint8_t sda_pin, uint8_t scl_pin, int i2c_freq) { _i2c_addr = i2c_addr; Wire.begin(sda_pin, scl_pin); Wire.setClock(i2c_freq); } /* 書き込み */ uint8_t write(uint16_t reg_addr, uint8_t data_len, uint8_t* buf) { // 未実装 } /* 読み取り Returns: 0x00: 正常 0xfe: データ長さエラー 上記以外: 送受信エラー */ uint8_t read(uint16_t reg_addr, uint8_t data_len, uint8_t* buf) { uint8_t reg_high = reg_addr / 256; uint8_t reg_low = reg_addr % 256; Wire.beginTransmission(_i2c_addr); Wire.write(reg_high); Wire.write(reg_low); uint8_t err = Wire.endTransmission(false); if (err != 0) { return err; } uint8_t bytesReceived = Wire.requestFrom(_i2c_addr, data_len); if (bytesReceived == data_len) { int i = 0; while (Wire.available()) { buf[i] = Wire.read(); i++; } } else { return 0xfe; } return 0x00; } private: uint8_t _i2c_addr = 0x34; };
3.2 メインプログラム
Arduinoのメインプログラム。ADAU1701クラスを用いて作成する。 シリアルからのコマンド書式は、1バイトごとに16進文字列をスペースで区切った文字列で最後に改行コード。例: "0F 12 A4 FF 01 80" また、コマンド文字列であることを示す独自ヘッダ(AA 55)をの冒頭に2バイト分つけている。
#include "ADAU1701.h" #define I2C_ADDR 0x34 #define SDA_PIN 21 #define SCL_PIN 22 #define I2C_FREQ 100000 #define HEADER_0 0xAA #define HEADER_1 0x55 const uint8_t CMD_WRITE = 0x00; const uint8_t CMD_READ = 0x01; ADAU1701 adau1701 = ADAU1701(); // 16進文字列をbyte arrayに変換 // 例: "0F 12 A4 FF 01 80" uint8_t parse_bytes(String hexStr, uint8_t* buf, size_t buf_len) { int startPos = 0; size_t count = 0; while (startPos < hexStr.length() && count < buf_len) { int spacePos = hexStr.indexOf(' ', startPos); if (spacePos == -1) { spacePos = hexStr.length(); // 最後の要素 } String sub = hexStr.substring(startPos, spacePos); if (sub.length() > 0) { buf[count++] = (uint8_t)strtol(sub.c_str(), NULL, 16); } startPos = spacePos + 1; // スペースの次の文字へ } return count; } void setup() { Serial.begin(115200); adau1701.begin(I2C_ADDR, SDA_PIN, SCL_PIN, I2C_FREQ); } void loop() { if (Serial.available()) { String input = Serial.readStringUntil('\n'); uint8_t cmd_buf[16]; uint8_t cmd_len = parse_bytes(input, cmd_buf, 16); if (cmd_len < 6) { Serial.printf("ERROR: COMMAND TOO SHORT\n"); return; } if ((cmd_buf[0] != HEADER_0) || (cmd_buf[1] != HEADER_1)) { Serial.printf("ERROR: INVALID HEADER\n"); return; } if (cmd_buf[2] == 0) { // 書き込み } else { // 読み込み uint8_t reg_high = cmd_buf[3]; uint8_t reg_low = cmd_buf[4]; uint8_t data_len = cmd_buf[5]; uint8_t buf[16]; uint16_t reg_addr = reg_high * 256 + reg_low; uint8_t err = adau1701.read(reg_addr, data_len, buf); if (err != 0x00) { Serial.printf("ERROR: READ,%02x\n", err); } else { for (int i = 0; i < data_len; i++) { Serial.printf("%02x", buf[i]); if (i < data_len - 1) Serial.printf(" "); } Serial.printf("\n"); } } } }
4. 動作確認
Arduino IDEのシリアルモニタ上で、
AA 55 01 08 1E 02
と入力したところ、
08 00
と返ってきた。このレジスタは、
https://www.analog.com/media/en/technical-documentation/data-sheets/ADAU1701.pdf
によれば、SERIAL OUTPUT CONTROL REGISTERでI2Sの出力フォーマットやクロックの設定用レジスタの値である。










