Arduino 上の ESP32 I2S のバグ??

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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513938/a0b22d9f-2012-9beb-8d60-0ce07d95caaf.jpeg)
この波形はそういう歪み方ではない。unsigned/signed を間違えたか？とも思ったがそうでもなかった。左右のチャネルの音が違っていて、他方からは別の高調波みたいなのが聞こえている。これは伝送データを取りこぼしているのかもしれない。

本当は↓のような波形を期待しているのに。
![clean_sine.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513938/c9494808-2d1d-1b2c-3ed5-af4aa98916c6.jpeg)


# 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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513938/cf1500bd-e347-9266-c1b0-7a164cd7cd4c.png)

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

<p><a href="https://commons.wikimedia.org/wiki/File:I2S_Timing.svg#/media/File:I2S_Timing.svg"><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/a/a7/I2S_Timing.svg/1200px-I2S_Timing.svg.png" alt="I2S Timing.svg"></a><br>By wdwd - &lt;span class="int-own-work" lang="en"&gt;Own work&lt;/span&gt;, <a href="https://creativecommons.org/licenses/by/3.0" title="Creative Commons Attribution 3.0">CC BY 3.0</a>, <a href="https://commons.wikimedia.org/w/index.php?curid=16579640">Link</a></p>
(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環境だけは古いのかもしれない。