Raspberry Piで外付けI2SのADCを動かせるのか


Pi基板に外付けの単機能のADCをつなげられないかと検討してみた。
ネットで調べて見るとADC/DAC のWM8731を使ったPROTO audio codec board基板を使って再生録音できたとい記載がある。

関係するソースを見てみると、
PROTO board with WM8731
    snd_soc_wm8731 wm8731.c 
    snd_soc_rpi_proto  rpi-proto.c
.dai_fmt = SND_SOC_DAIFMT_I2S
| SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBM_CFM,
これに対して、昔のDACのTDA1541aの設定を見てみると、
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS,

となっており、発振子付きのPROTO audio codec board基板のWM8731がマスターとして(Piはスレーブで)動く設定になっているようだ。


****

さて、手持ちのPiのオーディオのIN/OUTの状況を見てみると、
pi@raspberrypi ~ $ pactl list short sources
  0   alsa_output.usb-C-Media_Electronics_Inc._USB_PnP_Sound_Device-00-Device.analog-stereo.monitor   module-alsa-card.c  s16le 2ch 44100Hz  SUSPENDED
  1   alsa_input.usb-C-Media_Electronics_Inc._USB_PnP_Sound_Device-00-Device.analog-mono   module-alsa-card.c  s16le 1ch 44100Hz       SUSPENDED
  2   alsa_output.platform-bcm2835_AUD0.0.analog-stereo.monitor       module-alsa-card.c      s16le 2ch 44100Hz   SUSPENDED
  3   alsa_output.platform-snd-hifiberry-dac.0.analog-stereo.monitor  module-alsa-card.c      s16le 2ch 44100Hz   SUSPENDED

となっており、I2Sに相当するalsa_input.platform-snd****は存在しない。当たり前のことだが、I2S用のモジュールがないとI2SのADCは動かせないことに気づく。 今回の話題には関係ないが、2番目のalsa_input.usb-は、USB-MICである。

カーネルイメージの 2014-01-07-wheezy-raspbianを使うと、2種類のI2S DAC基板用のモジュール
  HifiBerry DAC ----- hifiberry_dac.c / pcm5102a.c  ICの内部にPLLがありマスタークロックが不要。
    RPi-DAC       ----- rpi-dac.c /pcm1794a.c   PCM_CLK(BCK)が64fsの固定になっている。 マスタークロックが必要。
がデフォルトで入っている。

とりあえず、手っ取り早い方法として、RPi-DAC用のpcm1794a.c rpi-dac.cをADC用に一部変更して、様子を見てみることにした。
RPi-DAC用の モジュール変更のため、カーネルの再構築(コンパイル)を行う。自分の環境(8GのSDカード)だと、約10時間ほどかかる。新しくつくったモジュールとカーネルのイメージをインストールしておく。
cd /usr/src/linux/
sudo make modules_install
sudo cp /usr/src/linux/arch/arm/boot/zImage /boot/kernel.img
リブートして、新しいカーネルが動くことを確認する。


次にRPi-DAC用のモジュールの変更を行う。 
/usr/src/linux/soundsoc/codecs/pcm1794a.c の中のplaybackをcaptureに変更、
/usr/src/linux/soundsoc/bcm/rpi-dac.c の中で
        return snd_soc_dai_set_bclk_ratio(cpu_dai,  32*2);  <--- bck=64fs 固定。そのままにしてみる。これを32に変更するとbck=32fsになった。
に変更して、モジュールのコンパイルを行う。
cd /usr/src/linux/
sudo nohup make modules&

nohup.outのログの中身を見てエラーがなければ、
sudo make modules_install
でモジュールの(全部の)インストールを行う。

/etc/modules の中身は以下のように変更してある。
snd-bcm2835
i2c-dev
snd_soc_bcm2708       <--- 実際にはこれは存在していない。lsmod しても出てこない。
snd_soc_bcm2708_i2s
bcm2708_dmaengine

snd_soc_pcm5102a
snd_soc_hifiberry_dac

snd-soc-pcm1794a <--- playback を capture に変更したもの。
snd-soc-rpi-dac <--- bclkのレートを変更したもの。

ここで、オーディオのIN/OUTの状況を見てみると

pi@raspberrypi ~ $ pactl list short sources
0       alsa_output.platform-bcm2835_AUD0.0.analog-stereo.monitor       module-alsa-card.c      s16le 2ch 44100Hz       IDLE
1       alsa_output.platform-snd-hifiberry-dac.0.analog-stereo.monitor  module-alsa-card.c      s16le 2ch 44100Hz       IDLE
2       alsa_input.platform-snd-rpi-dac.0.analog-stereo module-alsa-card.c      s16le 2ch 44100Hz       IDLE

となり、 変更したものは3番目の alsa_input.platform-snd-rpi-dac となって入力デバイスとして表示されている。


arecordを起動させると、PCM_FSとPCM_CLK端子のDC?電圧を測ると 約1.6Vになっているので、何らかの信号が出力されているようだ。ADCはスレーブ動作となっている。

通常、現在のADCはデルタシグマでオーバーサンプリングしているため、マスタークロック(システムクロック)が必要だ。例えば、256fsなど。
ADCとPiの間に、SRC(サンプリングコンバーター)のICを挟むことも考えてはみたが、・・・・

****

結局、WM8731の例にならって、 ADCがマスターとして(Piはスレーブで)動くように変更してみることにした。
/usr/src/linux/soundsoc/bcm/rpi-dac.c の中で
      .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
                    SND_SOC_DAIFMT_CBM_CFM,    <--- マスターに変更。

水晶発振で48kHzの512倍の周波数 24.576MHz(=48KHz x 512 = 96KHz x 256)をADCに供給して、PCM_FS,PCM_CLK(=64fs)をADCからPi側へ供給する。サンプリングレートは48KHz固定になる。

(ADCをマスターにしてPiに接続する回路図)

ADC


サンプリングレート48KHzで録音ができることは確認できたが、Piのヘッドフォンジャックで再生すると、やらたノイズ感が多い。
しかし、録音したWAVファイルをUSBメモリーで取り込んでPCで再生すると、それほどでもない。もしかしたら サンプリングレート48KHzだと、Piのヘッドフォン出力の方に何か悪いところがあるのかもしれないね!?


Raspberry Pi I2Sをスレーブ設定にして外部クロック同期でDACを再生



(Linux上のコマンドのメモ)
arecord -vD hw:2,0 -c 2 -r 48000 -f S16_LE  name.wav  name.wavファイルを指定して I2S 入力から録音する。
Recording WAVE 'name.wav' : Signed 16 bit Little Endian, Rate 48000 Hz, Stereo
Hardware PCM card 2 'snd_rpi_rpi_dac' device 0 subdevice 0
Its setup is:
  stream       : CAPTURE
  access       : RW_INTERLEAVED
  format       : S16_LE
  subformat    : STD
  channels     : 2
  rate         : 48000
  exact rate   : 48000 (48000/1)
  msbits       : 16
  buffer_size  : 24000
  period_size  : 6000
  period_time  : 125000
  tstamp_mode  : NONE
  period_step  : 1
  avail_min    : 6000
  period_event : 0
  start_threshold  : 1
  stop_threshold   : 24000
  silence_threshold: 0
  silence_size : 0
  boundary     : 1572864000
  appl_ptr     : 0
  hw_ptr       : 0

arecord -l    接続されているサウンドカードが表示される。 
**** List of CAPTURE Hardware Devices ****
card 2: sndrpirpidac [snd_rpi_rpi_dac], device 0: HifiBerry Mini HiFi pcm1794a-hifi-0 []   <--- playback を capture に変更したもの。
  Subdevices: 1/1
  Subdevice #0: subdevice #0


amixer cset numid=3 1 音声出力をオーディオ出力端子に設定する。  
amixer cset numid=1 77%   ボリュームを調整する。
amixer set Capture 100%   録音レベルの設定。
amixer sset Mic 16  MIC入力レベルの最大にする。
alsamixer       F*キーを使ってデバイスを選んで調整できる。



■致命的な問題
@ALSAが上手く起動できない。 amixerを何度か起動させる。 aplay *.wav で何かを再生させて応答が得られるか試してみる。 何度か試みていると、そのうちに応答するようになる?(応答しない場合は ctrl-cで強制終了させている。)

Aarecordが上手く起動できない。 audio open error: Device or resource busyが表示される。 
⇒ 途中で中断したつもりでも、裏ではまだ動作しているためにおきる。 起動時、前回の設定でまだドライバーが動いていると停止動作が入るようなので、数回起動すればできるようになるのかな?



■参考になる資料


■ 警告
PI基板をつかって接続する場合は、電気的なことをよく理解した上でお 使いください。そうしないと、PI基板と接続した相手などを破壊する危険があります。

■免責
(1)回路図やプログラムやデータの使用により、使用者に損失が生じたとしても、その責任 を負いません。
(2)回路図やプログラムやデータにバグや欠陥があったとしても、修正や改良の義務を負い ません。