6
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Arduino 上の ESP32 I2S のバグ??

Posted at

ESP32 を I2S経由で外部DAC とつなぎ、Arduino IDEで書いたコードで思い通りの音が出ない(汚い音が出る)状況だったので調べてみた。

Arudino IDE上で ESP32を使う

Arduino IDE : 1.8.15
ESP32 platform: 1.0.6
と、現時点では最新のはず。

ESP32 をI2S経由で外部DACとつなぐ

ESP32 からI2Sインターフェース (BCLK, DOUT, LRCK またの名を SCLK, SD, WS)を 外付けDAC (PCM5102) につなぐ。16bit以上の解像度で鳴らしたかったのだ。ESP32内蔵DACは解像度8bit しかないからである。

フルスイングの正弦波の音がひずむ

16bit分、すなわち-32768~+32767 (0x08000~0x07fff; I2Sはsigned intで表現する) 目いっぱい振っている 正弦波を生成させたのだが、音が汚い。PCM5102なのに?
出力レベルが高くて、頭と足が切れたのかもしれなかったので、簡易オシロで見てみると、下のようになっていた。
dist_sine.jpg
この波形はそういう歪み方ではない。unsigned/signed を間違えたか?とも思ったがそうでもなかった。左右のチャネルの音が違っていて、他方からは別の高調波みたいなのが聞こえている。これは伝送データを取りこぼしているのかもしれない。

本当は↓のような波形を期待しているのに。
clean_sine.jpg

I2Sの信号がどうなってるかロジックアナライザで確認する。

確認のために左チャンネルに1 (0x0001)、右チャンネルに2 (0x0002)を出力させてみた。
使ったコードは下記。GPIO 25, 26, 27 番ピンを外付けDACのDIN, LRCK, BCLKにつなぐ。

# include <driver/i2s.h>
# define I2S_BCLK  27 
# define I2S_LRCK  26
# define I2S_DOUT  25
# define I2S_SAMPLE_RATE     44100
uint16_t wave[2] ;
static const i2s_port_t i2s_num = I2S_NUM_0 ; // i2s port number
static const i2s_pin_config_t pin_config = {
    .bck_io_num   = I2S_BCLK,
    .ws_io_num    = I2S_LRCK,
    .data_out_num = I2S_DOUT,
    .data_in_num  = I2S_PIN_NO_CHANGE
};
static const i2s_config_t i2s_config = {
    .mode                 = (i2s_mode_t) (I2S_MODE_MASTER | I2S_MODE_TX),
    .sample_rate          = I2S_SAMPLE_RATE,
    .bits_per_sample      = I2S_BITS_PER_SAMPLE_16BIT,
    .channel_format       = I2S_CHANNEL_FMT_RIGHT_LEFT,
    .communication_format = I2S_COMM_FORMAT_I2S_MSB,
    .intr_alloc_flags     = ESP_INTR_FLAG_LEVEL1,
    .dma_buf_count        = 4,
    .dma_buf_len          = 1024,
    .use_apll             = false,
    .tx_desc_auto_clear   = true
};
void setup() {
  i2s_driver_install(i2s_num, &i2s_config, 0, NULL);
  i2s_set_pin(i2s_num, &pin_config);
  i2s_zero_dma_buffer(i2s_num);
  wave[0] = 0x0001 ; // Lch 
  wave[1] = 0x0002 ; // Rch 
}

void loop() {
  size_t written ;
  i2s_write(I2S_NUM_0, wave, sizeof(wave), &written, portMAX_DELAY) ;
}

wave[]が出力する値だ。この場合、定数値を出し続けるので「波」にはならず音は鳴らないが I2S上はどこでキャプチャしても同じ値が取れるはず。

ESP_I2S_issue.png

左チャンネル、右チャンネルとも値が2倍になっている。LSBの位置がおかしいように見える。
本来の I2Sの規格ならもう1クロック右にLSB が来るはず。例えば、左チャンネルのLSBはLRCKの立ち上がりエッジの次のBCLKで出力されなければならない。

I2S Timing.svg
By wdwd - <span class="int-own-work" lang="en">Own work</span>, CC BY 3.0, Link

(WIKIPEDIAより引用)

結論

MSBも本来の位置より1クロック左に出力されていた。DOUT (SD) は全体的に 1clock 早いのだ。言い換えると LRCK (WS) が 1 clock 遅いのだ。

バグ?

ESP32 の Errata にそれらしいことは書いてないので、ハードウェアではなくライブラリに問題があるのかもしれない。
ESP32-IDF は使わないのでわからないが、Arduino IDE の i2s.h ("C:\Users%USER%\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\tools\sdk\include\driver\driver\i2s.h") を見ると2016年とかになっているので、もしかすると Arduino の ESP32 SDK環境だけは古いのかもしれない。

6
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?