Study of I2C commands for HiFiberry Digi+ on RPi3

#Raspberry Piが出力する HiFiBerry Digi+ の制御コマンドを調べてみた

使用した DAC ボードは HiFiBerry Digi+ (の模造品だと思ふ...) です。Raspberry Pi から SPDIF (光ファイバ/同軸)で出力できるアドオンボードです。ボード上には Wolfson のWM8804 というLSIが載っています。I2S→SPDIF に変換します。

The target DAC board is (I guess a copy of) HiFiBerry Digi+, which can output optical/coaxial SPDIF on Raspberry Pi. Wolfson WM8804 is installed on this board, which converts from I2S to SPDIF.

Data Sheet: [WM8804 Datasheet V4.5](https://statics.cirrus.com/pubs/proDatasheet/WM8804_v4.5.pdf)

![hifiberry_digi.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513938/9cf9767a-83a0-ba16-4b5b-27ef454d8764.jpeg)

## そのまま I2S の線をつなぐだけでは動かない

__注:このボードに I2Sの信号線をつなぐだけでは SPDIFの信号に変更してくれません。__
__NOTE: You cannot obtain SPDIF signals when I2S signals are simply connected to this board.__

WM8804 には、ハードウェア制御モードとソフトウェアモード(2-wire, 3-wire)の電源オン(リセット回復)時の入力ピンの状態に応じてどちらの制御モードで動作するかが決定されます。このボードは 2-Wire (I2C) のソフトウェア制御モードで動作するように回路が作られています。つまり、電源オン後に外部からI2C (I2Sではない) で設定を与える必要があります。ラズパイのピンヘッダの 3番, 5番ピンが I2C の信号 (SDA, SCL) になっています。

WM8804 has two operation modes: hardware control mode and software control mode (2-wire & 3-wire). WM8804 decides the mode by state of input signals in power-on or reset.  This board, HiFiBerry DiGi+, is made run in the software control mode by 2-wire (I2C). So, you need to give configurations to WM8804 by I2C (not I2S) after power-on. RPi has I2C control signals on pin #3 and #5, SDA and SCL respectively.

Board configuration:

|SCLK   |SWIFMODE/GP0|HWMODE/SDIN|GPO2/SDOUT|CSB/GPO1|Note |
|:-:    |:-:         |:-:        |:-:       |:-:     |:-   |
|pull-up| pull-down  |pull-up    |pull-up   |pull-up |2-wire software control mode. I2C address=0x76|

# ロジアナで I2C 信号を観察する
今回はこの pin3, 5をロジアナにつないで、ラズパイ3 上で aplay コマンドで各種WAVファイルを再生したときに、どのようなI2C信号が出ているのか、そのやり取りを観察してみました。なお、このボードの I2Cアドレスは 0x3B (R/Wビットを含めると0x76/0x77)で、RPiから出る I2C のクロック(SCL)は 100kHz でした。ボード上のXTALは27MHzで、そのままWM8804のXin/Xout端子に直結しています。　

In this study, I observed the I2C signal behaviors when aplay command is invoked on RPi3, connecting pin #3 & #5 to the logic analyzer. In addition, I2C address of DiGi+ is 0x3B (0x76/0x77 including R/W bit), and I2C clock frequency (SCL) that comes from RPi3 is about 100KHz. XTAL on this board is 27MHz, which is connected to Xin/Xout of WM8804 directly.

See also: [Pin headers on Raspberry Pi] (https://www.raspberrypi-spy.co.uk/2012/06/simple-guide-to-the-rpi-gpio-header-and-pins/)

![hifiberry_i2c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513938/6ddeaa3f-922e-0197-9956-95c10f7b236d.png)


## kernel boot 時
OSが起動したときに特定の信号が出ます。どのボードが接続されているかを調査しているように見えます。RPiのI2CはACK/NACK信号の判定をしないらしいので観測時に注意が必要です。

When OS is booting up, the specific I2C signals appear below. I guess that RPi will try to obtain what board is connected. I2C interface on RPi seems to ignore ACK/NACK status.

|R/W|DevID|Adrs|Write Data|Read Data|#Reg|Note|
|:-:|:-:  |:-: |:-: |:-: |:-:   |:-|
| R |0x77 |0x00| -  |0x05|DEVID1|Constant by Fab. to identify WM8804|
| R |0x77 |0x01| -  |0x88|DEVID2|Constant by Fab. to identify WM8804|
| R |0x77 |0x02| -  |0x04|DEVREV|Revision E|
| W |0x76 |0x00|0x00| -  |RST   |Reset chip|
|   |     |    |    |    |      |interval 182 us.|
| W |0x76 |0x1E|0x0F| -  |PWRDN | See *1 |
|   |     |    |    |    |      |interval in 2.4 us.|
| W |0x76 |0x1C|0x46| -  |AIFRX | See *2 |
NOTE: After DevID's bit shifting, I2C address to write = 0x76, to read = 0x77 because LSB is appended as R/W mode.

(*1) PWRDN (0x1E) = 0x0F

|Item       |Status    |
|:-         |:-        |
|PLL        |Power down|
|SPDIF-Rx   |Power down|
|SPDIF-Tx   |Power down|
|Oscillator |Power down|
|I2S I/F    |Power up  |
|All outputs|Tri-stated|

(*2) AIFRX (0x1C) = 0x46

|Item         |Status |
|:-           |:-     |
|I2S Rx format|I2S mode  |
|I2S Rx length|20bits    |
|I2S Rx BCLK  |Not inverted|
|I2S Rx LRCLK |Not inverted|
|I2S Rx mode  |Master mode|
|I2S Rx sync  |LRCLK/BCLK are not output|

## aplay コマンド実行時
各種周波数・ビット長に応じた情報をまとめておきます。上から順に発行され、周波数やビット長によって書き込むデータが変わります。意外だったのは AIF (=I2S) は slave ではなく master で動作させていることでした。各設定値の詳細はWM8804 のデータシートを参照してください。

Here is summary table for each sampling frequency or bit length.  I2C commands are issued from the top to the bottom, and data to write are changed corresponding to frequency and bit length.  Unexpectedly, RPi runs AIF Rx (=I2S Rx) as master mode (not slave). Refer to WM8804 datasheet above for detail of each configuration.

|R/W|DevID|Adrs|#Reg  |44.1kHz,16b|48kHz,16b|Note|
|:-:|:-:  |:-: |:-:   |:-:   |:-:   |:- |
| W |0x76 |0x1E|PWRDN |0x07  |0x07  |See *3|
| W |0x76 |0x06|PLL4  |0x16  |0x17  |Set divider & PLL-N|
| W |0x76 |0x07|PLL5  |(0x16)|(0x16)|Cannot be output sometime|
| W |0x76 |0x03|PLL1  |0x25  |0xA6  |PLL-K|
| W |0x76 |0x04|PLL2  |0x2B  |0x08  |PLL-K|
| W |0x76 |0x05|PLL3  |0x2C  |0x12  |PLL-K|
| W |0x76 |0x1E|PWRDN |0x06  |0x06  |See *3|
| W |0x76 |0x15|SPDTX4|0x70  |0x72  |TXSRC=DAI |
| W |0x76 |0x1B|AIFTX |0x02  |0x02  |I2S mode, 16b|
| W |0x76 |0x1C|AIFRX |0x42  |0x42  |I2S master mode, 16b|
|   |     |    |      |      |      |Interval 176 us.|
| W |0x76 |0x1E|PWRDN |0x02  |0x02  |See *3|

In 24bit-length, command sequence is different a little.

|R/W|DevID|Adrs|#Reg  |96kHz,24b|192kHz,24b|Note|
|:-:|:-:  |:-: |:-:   |:-:   |:-:   |:- |
| W |0x76 |0x1E|PWRDN |0x17  |0x17  |See *3|
| W |0x76 |0x06|PLL4  |(0x07)|(0x07)|Cannot be observed|
| W |0x76 |0x07|PLL5  |0x15  |0x1C  |Set divider|
| W |0x76 |0x03|PLL1  |0xA6  |0xA6  |PLL-K|
| W |0x76 |0x04|PLL2  |0x08  |0x08  |PLL-K|
| W |0x76 |0x05|PLL3  |0x12  |0x12  |PLL-K|
| W |0x76 |0x1E|PWRDN |0x16  |0x16  |See *3|
| W |0x76 |0x15|SPDTX4|0x7A  |0x7E  |TXSRC=DAI|
| W |0x76 |0x1B|AIFTX |0x0A  |0x0A  |I2S mode, 24b|
| W |0x76 |0x1C|AIFRX |0x4A  |0x4A  |I2S master mode, 24b|
|   |     |    |      |      |      |interval 1000 us.|
| W |0x76 |0x1E|PWRDN |0x06  |0x06  |See *3|
| W |0x76 |0x1E|PWRDN |0x02  |0x02  |See *3|

From other perspective;

|OSC CLK|PRESCALE|CLKOUTDIV|MCLKDIV|FREQMODE|PLL-N|PLL-K|Note|
|:-:    |:-:|:-: |:-:|:-: |:-:|:-:     |:-            |
|27.0MHz| 1 |(01)|(0)|(10)| 6 |0x2c2b25|16bit, 44.1kHz|
|27.0MHz| 1 |(01)|(0)|(10)| 7 |0x1208A6|16bit, 48kHz  |
|27.0MHz|(0)| 01 | 0 | 01 | 7 |0x1208A6|24bit, 96kHz  |
|27.0MHz|(0)| 01 | 1 | 00 | 7 |0x1208A6|24bit, 192kHz |

## aplay コマンド完了後
下表のコマンドが出ている。SPDIFを停止しているようだ。
After aplay command is finished, the signals below is outputted. RPi seems to make SPDIF go down.

|R/W|DevID|Adrs|Write Data|Read Data|#Reg|Note|
|:-:|:-:  |:-: |:-: |:-: |:-:   |:-|
| W |0x76 |0x1E|0x06| -  |PWRDN| See *3 |
|   |     |    |    |    |     |Interval 100 us or more. |
| W |0x76 |0x1E|0x16| -  |PWRDN| See *3 |


(*3) PWRDN (0x1E) 

|Item       |Write 0x17 |Write 0x16 |Write 0x07 |Write 0x06 |Write 0x02 |Note |
|:-         |:-         |:-         |:-         |:-         |:-         |:- |
|PLL        |Power down |Power up   |Power down |Power up   | <-        ||
|SPDIF-Rx   |Power down | <-        | <-        | <-        | <-        |Always power-down|
|SPDIF-Tx   |Power down | <-        | <-        | <-        |Power up   ||
|Oscillator |Power up   | <-        | <-        | <-        | <-        |Always power-on|
|I2S I/F    |Power down | <-        |Power up   | <-        | <-        |Set when bit length change|
|All outputs|Tri-stated | <-        | <-        | <-        | <-        |Always tri-stated|

# おまけ / Appendix
Volumio2 上で このカードから音声を出力させることがなかなかできませんでした。過去何十回と設定を変えてますが2回しか成功してないですね...。aplay からは音が出るのでソフトウェア(Volumio2)側の問題だと思いますが。

今回、英文併記を試みていますが、文法などについて non-native からの指摘には応じませんので、ご了承ください。キリがないので。

As for me, I tried to make Digi+ output SPDIF so many times with some configuration changes on Volumio2 but I succeeded only twice.  I think it is a software (Volumio 2) issue, not hardware because I can make it by aplay command.