高音質ラズパイ用DACの設計と製作
概要
ラズパイ用の高音質DAC(msBerryDAC)を開発しました。対応機種は次のとおりです。
- Raspberry Piシリーズ
- Raspberry Pi Zeroでの動作報告もあります。
購入は取扱店からお願いします。
「ラズパイでデジタルサイネージ的なもの作れない?」と依頼されたので構築したときのメモ。Xを入れずにコンソール(CUI)のみで作りましたが、結構手間取りました……。
※omxplayerは開発終了(deprecated)しているので使用しません。
Raspbian や Volumio などの設定済システムを、なるべく小さくディスクイメージ化するメモ。
# fdisk -l /dev/mmcblk0 Device Boot Start End Sectors Size Id Type /dev/mmcblk0p1 8192 532479 524288 256M c W95 FAT32 (LBA) /dev/mmcblk0p2 532480 15554559 15022080 7.2G 83 Linux
8GB SD に Raspbian を入れた場合こんんな感じになります。下のパーティションが root ファイルシステムです。これを縮小します。
オンラインだと面倒なので、Linuxマシンを別に用意し、そこにラズパイ用のSDを入れて編集します。
# e2fsck -f /dev/sdb2 # resize2fs -P /dev/sdb2 resize2fs 1.44.5 (15-Dec-2018) Estimated minimum size of the filesystem: 470543
ブロックサイズは4KBですので、470543ブロック×4KB=1.9GB程度まで縮小できることがわかりました。キリの良いところで2GBに縮小します。resize2fsでは限界まで縮小できないので、余裕を持って縮小後サイズを設定する必要はありません。
# resize2fs -p /dev/sdb2 2G resize2fs 1.44.5 (15-Dec-2018) Resizing the filesystem on /dev/sdd2 to 524288 (4k) blocks. The filesystem on /dev/sdd2 is now 524288 (4k) blocks long.
resize2fs は 1.5G といった指定はできません。1536Mと指定する必要があります。
ファイルシステムを縮小したらパーティションを縮小します。fdiskでパーティションを削除してから、スタートブロックを揃えてパーティションを再生成します。
# fdisk /dev/sdd Command (m for help): d Partition number (1,2, default 2): 2 Command (m for help): n Select (default p): p Partition number (2-4, default 2): 2 First sector (2048-15554559, default 2048): 532480 Last sector, +/-sectors or +/-size{K,M,G,T,P}: +2G Created a new partition 2 of type 'Linux' and of size 2 GiB. Partition #2 contains a ext4 signature. Do you want to remove the signature? [Y]es/[N]o: n Command (m for help): p Device Boot Start End Sectors Size Id Type /dev/sdd1 8192 532479 524288 256M c W95 FAT32 (LBA) /dev/sdd2 532480 4726783 4194304 2G 83 Linux
1セクタは512byteですので、「512×4194304 = 2147483648」と resize2fs の結果「524288×4096 = 2147483648」が等しいことを確認します。確認して問題なければ、最後に書き込んで終了です。
Command (m for help): w
これで縮小されたシステムがSDに構築されました。
最後にこのSDイメージ化すれば完成です。このときは、2つめのパーティションのEndの値「4726783」に注目します。先頭からこのセクタまで保存すれば良いので、「(4726783+1)×512 = 2308MB」を保存します。
dd if=/dev/sdd of=./img.file bs=1M count=2308 status=progress
これでイメージが完成しました。
お手軽で良いのですが、ひとつ問題点がありまして、この手順では極限まで小さくしたイメージを作ることができません。出来上がったらイメージからRaspberry Piを起動するとこうなります。
$ df -h Filesystem Size Used Avail Use% Mounted on /dev/root 2.0G 1.3G 644M 66% / /dev/mmcblk0p1 253M 52M 201M 21% /boot
このように800MBほど空いている領域があるわけです。またパーティションのスタートブロックも、8192から2048に減らすことで容量を削減できます。
mkdosfs -F32 -nBOOT /dev/sdd1 mkfs -t ext4 /dev/sdd2
「-nBOOT」はディスクラベルをBOOTにする設定です。DOS領域(vfat)のラベル名をBOOTにしないとラズパイが起動しません。後から変更する場合は、dosfslabelコマンドを使用します。
dosfslabel /dev/sdd1 BOOT
これで作業完了です。SDラズパイに挿入して起動することを確認します。問題なければ、上と同様の手順でイメージ化します。
DOS領域のディスクラベルを「BOOT」にすることと、「Disk identifier」の値を保つことです。
fstabやカーネル起動オプションでは「PARTUUID」によってデバイスを指定しています。PARTUUIDはファイルシステムのUUIDではなく、パーティションにつけられたUUIDです。DOSパーティションテーブル(MBR)には存在せず、gptパーティションテーブルが持つものです。
DOSパーティションにはPARTUUIDの概念はないのですが、「(Disk identifier)-(パーティション番号)」をPARTUUIDの代わりとして使用するようになっています。ですから「Disk identifier」を維持する必要があります。
/boot領域(Windowsから見える領域)の「cmdline.txt」に「init=/usr/lib/raspi-config/init_resize.sh」をつけることで、初回起動時のパーティションの拡張を実行できます。
しかしこれだけだと、パーティションは拡張されますが、ファイルシステムは未拡張のままです。ファイルシステムの拡張は /etc/init.d/resize2fs_once というファイルで行われています。
#!/bin/sh ### BEGIN INIT INFO # Provides: resize2fs_once # Required-Start: # Required-Stop: # Default-Start: 3 # Default-Stop: # Short-Description: Resize the root filesystem to fill partition # Description: ### END INIT INFO . /lib/lsb/init-functions case "$1" in start) log_daemon_msg "Starting resize2fs_once" ROOT_DEV=$(findmnt / -o source -n) && resize2fs $ROOT_DEV && update-rc.d resize2fs_once remove && rm /etc/init.d/resize2fs_once && log_end_msg $? ;; *) echo "Usage: $0 start" >&2 exit 3 ;; esac
このファイルを作成し、実行権限をつけます。そして /etc/rc3.d/S01resize2fs_once からリンクを貼ります。
vi /etc/init.d/resize2fs_once chmod +x /etc/init.d/resize2fs_once cd /etc/rc3.d/ ln -s ../init.d/resize2fs_once S01resize2fs_once
これで初回起動時のパーティション&ファイルシステム自動拡張が有効になります。
/bootは、SDをWindowsから開いたときに見える中身と同一。
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev update_config=1 country=JP network={ ssid="SSID" psk="PASSWORD" }
apt-get install git cmake libjpeg-dev imagemagick git clone https://github.com/jacksonliam/mjpg-streamer.git cd mjpg-streamer/mjpg-streamer-experimental make sudo make install mjpg_streamer -o "output_http.so -w ./www" -i "input_raspicam.so -fps 60"
さていつものラズパイ用DACですが、最新のVolumio2をちょっと入れて試してみました。
昔(といっても2年ぐらい前)は、オーディオ用ディストリビューションと言ってもVolumioぐらいしか認知されてなくて、事実上他に選択肢はありませんでした。
まあ色々と使いにくい点もあったのですが、カスタマイズして使っているうちにちょうどよくなってそのまま使い続けたという。
他のディストリビューションはどうにも肌に合わず、当時Volumio2のβ版は使い勝手が悪くて結局そのままという状況でしたので、一念発起して使ってみることにしました。*1
入れてみるとさすがに完成度が高く、これなら完全に乗り換えても良いですね。
msBerryDACはHiFiBerry DAC+ PRO互換ですが、このPRO付きとPROなしはドライバが共通になっています。
HiFiBerry DAC+ | 外部クロックなし |
HiFiBerry DAC+ PRO | 外部クロックあり |
この判別はドライバ側で行っていて、音が鳴っていても外部クロックが正しく使われているかはソフトからでは分かりません。ドライバ側で認識方法が狂っていたりすると、外部クロックが使われずに音が再生されたり、狂ったクロック(速度)で音が再生されてしまいます。
これを確実に確認するには、発振器(やクロック)の端子にテスター等を当ててクロックがきちんと動作しているか確認するしかありません。
というわけで、最新のVolumio2で外部クロックの動作を確認しました。ついでに分かったことですが、リサンプリングをオフにしておいても、リサンプルされて48k系列のクロックで再生されているようです。
β版当時には存在しなかったアップサンプリングを設定して、384KHz/32bitで再生できているのか確認しました。
まずは96KHz/32bit再生から。
BCLK(ビットクロック)端子を観測しています。BCLKとは音楽データを1bit送るためのクロック信号です。96KHz/32bit再生では、
96KHz × 32bit × 2ch(L/R) = 6.144Mbit/sec
つまり 6.144MHz のBCLKが必要になります。オシロの観測画像を見ると6.144MHzの信号が出ているので、きちんと96KHz/32bitで動作していることが分かります。
続いて192KHz/32bit。
192KHz × 32bit × 2ch(L/R) = 12.288Mbit/sec
そして384KHz/32bit。
192KHz × 32bit × 2ch(L/R) = 24.576Mbit/sec
ということで、24.576MHzのBCLKが出ています。
Volumio Ver1では、msBerryDACで384再生はソフトに手を入れない限り無理だったので確認していなかったのですが、Volumio2により無事384KHz/32bit再生されていることを確認できました。
Volumio2のアップサンプリングって「768KHz再生」も設定できるのです。興味そそられますよね!
もちろん試して見しまたが、無理でした(笑)。設定自体はできるし、その状態で再生もできるのですが、768KHzに設定してもBCLK=24.576MHzだったので384/32で再生されてるだけでした。
よく考えたら、載ってるクロックが24.576MHzなのでこれ以上のBCLKはどうやっても無理に決まってた(笑)*2
ちなみに、波形が鈍っているのはプローブの設定間違えたせい……。
ラズパイ用の高音質DAC(msBerryDAC)を開発しました。対応機種は次のとおりです。
購入は取扱店からお願いします。
※この記事で扱っているVolumio(Ver1)は古いものです。音質云々以外の、設定情報などすべて古い情報になります。
Raspberry Pi用I2S DACを買ってみました。
外部クロック動作のオリジナル設計ラズパイ用DAC頒布中です。音質に拘った設計になっています。HiFiBerry DAC+ PROよりよっぽども音質良いです。
I2SとはDACチップを動作させるための通信規格でラズパイにはI2Sを直接出力する機能が存在します。ラズパイ用のI2S DACは色々発売されいて、国内でも既にいくつかでていますが、そのほとんどが水晶クロックを搭載していません。
というのも「ラズパイのI2S出力」はシステムクロック(SCLK)と呼ばれる「22.5792MHz」や「24.576MHz」のクロックを出力する機能がありません。ほとんどのラズパイ用DACは、BCLKと呼ばれる1bitごとのデータ出力クロックからシステムクロックを生成しています。
PCM51xxのような特殊なDACチップを使用したボードは存在するのに、PCM179xといったよく使われるDACチップを使用したボードが存在しないのはそのためです。
またこのBCLKについても、クロックタイミングが一定ではないことが知られています。再生速度が狂う代わりに、このクロックタイミングを一定にするというパッチも同じサイトで公開されていますが、それはそれで(音が高くなったり低くなったりする)問題があります。
あまり知られていないことですが、ラズパイのI2Sには外部クロックに同期してデータを出力するモードが存在します。説明すると大変なので詳しくはSND_SOC_DAIFMT_CBM_CFMでググってもらうとして、要するに「ラズパイにSCLKを与えるのではなく、ラズパイにBCLKやLRCLKを与えそれに同期してデータを出力してもらう」ことで、完全に正しいクロックでI2Sデータを出力することができます。
そのような機能を持つ製品として「HiFiberry DAC+ PRO」というものが存在します。
公式サイトからカートに入れて、日本国内の住所を普通に(ローマ字で)入力するだけで手に入れることができます。送料も「たった$8」ですので、6000円ぐらいで購入できました。
注文から1週間ぐらいで届きました。
このDACはラズパイのモデルB用です。手持ちのRaspberry Pi2 BにVolumio 1.55をインストールして早速使用してみました。
「HiFiBerry +」を選択して早速音を再生。
……
…………
……………………なにこれ、超気持ち悪い!
音質がどうのとかそういうの以前に、揺らいでるのか、歪んでるのか、とにかく気持ち悪くてしょうがない。これはおそらくラズパイの歪んだI2Sクロックが原因です。実はHiFiberry DAC+ PROを「Volumio Ver1.55」などで使用した場合、外部クロックは有効にならないのです(参照)。*1
2016年2月時点でラズパイ用DACで外部クロックを使用しているものなんてほぼ流通してませんから、今現在ネットにあがってるラズパイ用DACの感想は、ほとんどがこの狂ったI2Sによる再生によるもので……。
よくこんなのありがたく聞けますね!(笑)
やー、ほんと、音が狂ってるせいでリアルに吐き気してきました……。こんなん聞くならPCM2704で音質のいいDACのほうが100倍も良いです。
※注意:Volumio2等の最近のディストリビューションははじめから対応しています。この項目の情報は古くなっています。
VolumioというかHiFiBerry DAC+のドライバを更新すると、HiFiBerry DAC+ PRO対応になり、外部クロック再生ができるようになります。
Volumioが起動中のラズパイにsshで接続します。
ID: root
Pass: volumio
この後コンソールでカーネルのアップデートを実行します。
# rpi-update
なお、RaspbianやRaspbianベースの他のイメージでも、rootからrpi-updateで対応ドライバをインストールできるかと思います。
この項は直接関係ないので、あとで別記事に移す予定。
Volumioを転送した状態では、SDカードの空き容量が無駄になっていますので、この部分を使えるようにします。
# raspi-config
コマンドを実行して「1 Expand Filesystem」を選択すれば、勝手に拡張してくれる……はずなのですが
Your partition layout is not currently supported by this tool. You are probably using NOOBS, in which case your root filesystem is already expanded anyway.
と怒られてしまいます。Volumioのパーティションの切り方をRasbianと変更してあるらしく、うまく行きません。
/usr/bin/raspi-config を編集します。
if [ "$PART_NUM" -ne 2 ]; then whiptail --msgbox "Your partition layout is not (略)" 20 60 2 return 0 fi
「-ne 2」の部分を「-ne 3」に書き換えてから「raspi-config」を実行してください。うまく行きます。
まず、sources.listのdeb-srcが狂ってるので修正します。修正しなくてもあまり問題はないのですが気持ち悪いので。
# vi /etc/apt/sources.list deb http://mirrordirector.raspbian.org/raspbian/ jessie main deb-src http://mirrordirector.raspbian.org/raspbian/ jessie main
そのままシステムをアップグレードします。20分ぐらいかかります。
apt-get update apt-get upgrade apt-get dist-upgrade
config.txtに以下を設定。
hdmi_drive=1
/boot/cmdline.txt に以下を設定。
consoleblank=0
apt-get upgradeしないなら /etc/kbd/config も修正。確認は以下。
cat /sys/module/kernel/parameters/consoleblank
apt-get install rng-tools
mkdir /lib/firmware/brcm/ cd /lib/firmware/brcm/ wget https://github.com/RPi-Distro/firmware-nonfree/raw/master/brcm80211/brcm/brcmfmac43430-sdio.bin wget https://github.com/RPi-Distro/firmware-nonfree/raw/master/brcm80211/brcm/brcmfmac43430-sdio.txt reboot ifconfig wlan0
APモードで動作させる場合、チャンネルを6に設定しないと安定しないようです。
hoatapd.conf
interface=wlan0 driver=nl80211 hw_mode=g ssid=SSID # for Realtek 8192 (USB/rtl8192cu) #channel=1 # for Raspberry Pi 3 WiFi (BCM43430) channel=6
Linux 4.4.15-v7+現在、ドライバが未成熟なのか不安定。しっかりとした電源を用意しないと安定しない模様。
「rpi-update」後に再起動してもう一度再生してみます。今度はきちんと外部クロックを使用した再生ができました。
さっきまでの音が嘘のように、とても綺麗な音です。
基板上の役割は以下のようになっています。
主要部分の回路接続は以下のとおりです。
HiFiBerry DAC+には、通常の「HiFiBerry DAC+」と「HiFiBerry DAC+ PRO」が存在しますが、その判別は次の方法で行っています。
この3つの条件をすべて満たしたとき、HiFiBerry DAC+ PROボードとみなし、外部クロックを使用するようになります。