しかしラズパイが出力する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独立にある
・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.cparamsという構造体が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 件のコメント:
コメントを投稿