2019年10月21日月曜日

Rapsberry-pi 搭載CPUのI2Sのdatasheetを読んでみる

AK4495でDSD再生をしたいと思っている.

しかしラズパイが出力するDSD仕様とAK4495が受信するDSD仕様には違いがあり、こちらでその違いについて検討した.
何らかの方法でその違いを吸収しなければならない.上のリンクではハードウエアで違いを吸収しようかなと結論した.
吸収するべき違いはこの3つである.
 1) Fsに応じて、master clockの切り替え、およびLRCK/BCK生成
 2) DSDかPCMかの監視
 3) LRchがインターリーブされたDATAを、DSDL/DSDRの2本線に分ける

その後、PLDで3つの機能を組んでみたのだが、XC9572XLのような最底辺PLDでは容量不足だと判明した.XC95144XLが必要だった.な~んかかったるい.100pin TQFPなんか半田づけしたくねぇよ.

100pin TQFPを回避して、ラズパイのI2Sデバドラを自分で改造するやり方も考えてみるか、、、というわけで、ごにょごにょと調べているというのが現状である.

今回は、Raspberry pi 3B+に載っているCPUチップ BCM2837 のI2S仕様がどうなっているのかを調べてみた.

なお、以降ではI2Sについては細かく述べないので、軽く触れておくとこんな4本線のシリアルバスでステレオ音声の伝送に使われるのがI2Sだ.
 BCK               64fsだったり32fsだったりする
 LRCK             fs
 DATAOUT       DACへ行く音声データのシリアライズされた信号
 DATAIN          ADC用途なのでここでは使わないので無視


------
ラズパイ3のCPUチップはBCM2837であるが、datasheetが見つからない.
BCM2835というラズパイ2に載っているCPUチップのdatasheetならネットに在った.これを読んでみる.ペリフェラルはBCM2837と同じだと思う.
https://www.raspberrypi.org/app/uploads/2012/02/BCM2835-ARM-Peripherals.pdf


I2S IFのブロック図
FIFOがある.PCM dataを一定テンポで入出力してくれるように見受けられる.
外部ピンはPCM_CLK/PCM_FS/PCM_DIN/PCM_DOUTの4本である.
以下ではこれらをBCK/LRCK/DATAIN/DATAOUTと呼ぶ.DATAOUTは単にDATAとも呼ぶ.


I2Sピンアサインを変えられるか?
ラズパイのI2S ピンとしてよく見かけるのは、GPIO18~21にアサインされたこの絵である.これらを任意のピンに移動できるのだろうか?

残念ながらI2Sピンアサインの自由度はほとんどない.

GPIOのピンアサインは6種類(ALT0~ALT5)のいずれか、すなわち一括変更しかできないのだ.そしてこの6種類の中で、I2Sピンが存在するのはALT0とALT2だけ.その結果、I2Sピンはこの二者択一ということになる.
 ALT0   GPIO18~21    通常はこちら
 ALT5   GPIO28~31


I2S信号はどんだけプログラマブルか?
 ・DATAは常にMSB firstでserial出力される
 ・LRCKの位置と長さは任意に設定できる
 ・DATAは8~32bit幅で任意に設定できる
 ・BCKとLRCKはそれぞれ独立にin/out、slave/masterを設定できる
 ・通常は、DATAとLRCKはBCKの立ち上がりedgeで変化する
 ・BCKの極性を反転できる


I2S IF内部仕様
 ・FIFOは64段x32bitで、TX/RX独立にある
 ・FIFO稼働中にregisterを変えちゃいかん(EN、TXONは例外)
 ・ENはpowersave、TXONで出力オン
 ・送信FIFOが空になると、TXERRエラーフラグが立つが、停まりはしない
 ・TXFIFOが空になるとゼロが出力される
 ・FIFOデータは右揃えゼロ埋めで書くこと
 ・LchとRchで別個にFIFOに積むこと
 ・レジスタアドレスは、0x7E203000 から開始される
 ・32bitレジスタが9ヶある
  Offset
  0x0    CS_A     PCM Control and Status
  0x4    FIFO_A   PCM FIFO Data
  0x8    MODE_A   PCM Mode
  0xc    RXC_A    PCM Receive Configuration
  0x10   TXC_A    PCM Transmit Configuration
  0x14   DREQ_A   PCM DMA Request Level
  0x18   INTEN_A  PCM Interrupt Enables
  0x1c   INTSTC_A PCM Interrupt Status & Clear
  0x20   GRAY     PCM Gray Mode Control


ここまでで3つの機能をデバドラ改造で実現できるか?
 1) Fsに応じて、master clockの切り替え、LRCK/BCK生成
これはたぶんできるだろう.I2S IFにそういう機能があるからだ.

 2) DSDかPCMかの監視
source codeのどこかには、DSD再生を制御している部分があるはず.

 3) LRchがインターリーブされたDATAを、DSDL/DSDRの2本線に分ける
ざんねーん、これは絶対に不可能だとわかった.


volumioのsource codeからI2S制御してるやつを探す
sourceの入手やビルド環境については、こちらを参照のこと.

I2Sのsource codeはこれである.レジスタ制御なんかもこれに記されている.
/usr/src/rpi-linux/sound/soc/bcm/bcm2835-i2s.c

paramsという構造体がFsなどの情報を格納しているようだ.
struct snd_pcm_hw_params *params,
出来合いの関数を利用するとparamsから情報をGETできる.
  int fs = params_rate(params);        44.1kHzとか
  int bit = params_width(params);     24bitとか
  snd_pcm_format_t  fmt = params_format(paras);     数字の0~50ぐらい

ラズパイのGPIOから外部へFs/bit/fmtを知らせることができる.
外部回路としては、このような対応が可能だ.
 ・Fsがわかれば、LRCK周波数を決定できる
 ・bitがわかれば、BCK周波数を決定できる
 ・fmtがわかれば、DSDかPCMかを決定できる

GPIO制御などについては先達がいる.「やまちゃんのオーディオブログ」という人.
こちらの記事の、
ラズベリーパイのi2s外部クロック、その後8(2018年度版)
こちらのsource codeにわたしがやりたいようなことが書かれている.
https://audio-blog.jp/wp-content/uploads/2018/04/bcm2835-i2s.c


I2Sデバドラを改造してI2Sデバドラの内部状態を表示させた
printk()を使ってI2Sデバドラのfs/bit/fmtを表示させた.

44.1kHz 16bitのCDファイルを再生  →  fs=44100  bit=16  fmt=2
fsとbitは妥当な表示である.
fmtの2番は、SNDRV_PCM_FORMAT_S16_LE を意味している、妥当.

176kHz 24bitのHiResファイルを再生  →  fs=176400  bit=24  fmt=6
fmtの6番は、SNDRV_PCM_FORMAT_S24_LE を意味している.

352kHz 24bitのHiResファイルを再生  →  fs=192000  bit=24  fmt=6
ALSAの制限により352kHzを192kHzに下げているのがわかる.

さて、DSDを再生したらどうなるか?
DSD64 2.8MHz DSDファイルを再生  →  fs=176400  bit=24  fmt=6
うぅ、これはわからん.fmtは6番のままだ.これが50番ぐらいになってくれればDSDを捕捉できたことになるんだがなぁ.ただしDoPの仕様に従えば見かけ上は176k24bitで正しいのかもしれない.DoPについてはこちらを参照

DSD128 5.6MHz DSDファイルを再生  →  fs=192000  bit=24  format=6
これはダメだ.ALSAの制限でPCM192kに落とされている.


ここまでで3つの機能をデバドラ改造で実現できるか?
 1) Fsに応じて、master clockの切り替え、LRCK/BCK生成   → できそう
 2) DSDかPCMかの監視   → 不明、別のsourceを探す必要あり(MPD側かも)
 3) LRchがインターリーブされたDATAを、DSDL/DSDRの2本線に分ける   →  無理

どのみち3番目の機能にはFPGAが必要なので、デバドラを改造する意味が薄い.....

今宵はここまでにしとうございます.

かしこ

0 件のコメント:

コメントを投稿