HelioボードからSound Blasterで音が鳴るようにする
はじめに
今回は、Sound Blaster Play!をHelioボードに接続して音が鳴るようにしてみます。 大まかな作業としては、サウンドドライバを有効にしたカーネルをビルドして、SDカードにあるカーネルとDevice Tree Blobファイルの更新です。 中々うまくいかず試行錯誤しました。 今回の内容はFPGAとは関係無いですが、将来的に、FPGAで生成した信号を再生するのに活用しようと考えています。
準備
以下を用意します。
- Sound Blaster Play!
- USB変換ケーブル
- Linuxネイティブマシン (SDカード書き込み&カーネルなどのビルド用)
- Linuxが起動するSDカード
Sound Blasterは最新のものではなく、Linuxでの動作実績がある古めのものを使うことにしました。IntelのEdisonボードで接続できた方がいるので、たぶん大丈夫だろうと考えました。
HelioのUSBポートがMini Bタイプなので、そのままではSound Blaster Play!が接続できません。 そこで、USB変換ケーブルを使って接続できるようにします。(間違ってMicro Bタイプの変換ケーブルを買ってしまい失敗しました。注意してください。また、最近はMicroタイプが主流のようで、家電量販店では見つかりませんでしたのでAmazonで購入しました。)
SDカードの読み書きがUbuntuの仮想マシンからだと厳しそうなので、ネイティブマシンを用意します。 ビルド環境としてサポートされている、Ubuntu 12.04をセットアップします。
SDカードにはHelioでLinuxが起動するようにしたイメージを書き込んでおきます。以前、Linuxをブートできるようにした時のものを使用します。
カーネルのビルド
Helioの標準カーネルでは、Sound Blasterを動作させるデバイスドライバがカーネルに組み込まれていません。 ですので、カーネルのビルドが必要です。 また、これからC言語でSound Blasterを操作したいため、カーネルにOpen Sound System APIを組み込みます。
GSRD v13.1 - Using Yocto Source Packageに書かれている手順に従ってビルド環境を作ります。
$ sudo apt-get update $ sudo apt-get upgrade $ sudo apt-get install sed wget cvs subversion git-core coreutils unzip texi2html texinfo libsdl1.2-dev docbook-utils gawk python-pysqlite2 diffstat help2man make gcc build-essential g++ desktop-file-utils chrpath libgl1-mesa-dev libglu1-mesa-dev mercurial autoconf automake groff libtool xterm $ wget http://releases.rocketboards.org/release/2013.11/gsrd/src/linux-socfpga-gsrd-13.1-src.bsx $ chmod +x linux-socfpga-gsrd-13.1-src.bsx $ sudo ./linux-socfpga-gsrd-13.1-src.bsx $ source ~/yocto/altera-init ~/yocto/build
カーネルのオプション設定を変更するため、以下を実行します。すると、新しい端末が起動し、変更メニューの画面が表示されます。
$ bitbake -c menuconfig -f virtual/kernel
以下を選択して、カーネルに組み込みます。
Device Drivers <*> Sound card suppor <*> Advanced Linux Sound Architecture <*> OSS Mixer API <*> OSS PCM (digital audio) API [*] OSS PCM (digital audio) API - Include plugin system
設定を保存したら、カーネルをビルドします。
$ bitbake virtual/kernel
ビルドが完了すると、~/yocto/build/tmp/deploy/images以下にカーネル(zImage)が生成されます。 他にもファイルが色々ありますが、今回使うのはzImageだけです。
$ ls -l ~/yocto/build/tmp/deploy/images [...] -rw-r--r-- 1 fixme fixme 3351368 1月 18 11:04 zImage-1.0-r1-socfpga_cyclone5-20150118015746.bin
ビルドしたカーネルがサウンドドライバを組み込んでいるかざっくりした方法ですが確認してみます。zImageの方ではなく、圧縮していないカーネル(vmlinux)に対してstringsをかけてみます。カーネルのオプションを変更しないでビルドしたものと比較しても、明らかな違いが見られます。(vmlinux-1.0-r1-socfpga_cyclone5-20150118011738はカーネルのオプションを変更せずにビルドしたものです)
$ strings vmlinux-1.0-r1-socfpga_cyclone5-20150118015746 | grep snd | head -10 snd.cards_limit snd.major snd_disconnect_release snd.slots snd_timer.timer_tstamp_monotonic snd_timer.timer_limit snd_pcm_update_hw_ptr0 snd_pcm.maximum_substreams snd_pcm.preallocate_dma snd_rawmidi.amidi_map
$ strings vmlinux-1.0-r1-socfpga_cyclone5-20150118011738 | grep snd msgsnd msgsnd msgsnd Td 3TCP: snd_cwnd is nul, please report this bug.
SDカードへのzImageの上書き
SDカードをマウントします。使用したマシンでは、以下のようにパーティションを認識してました。GSRD v13.1 - SD Cardの「SD Card Layout」の説明にある3つのパーティションが、mmcblk0p1~mmcblk0p3に対応します。
$ cat /proc/partitions major minor #blocks name 8 0 312571224 sda 8 1 308653056 sda1 8 2 1 sda2 8 5 3915776 sda5 11 0 1048575 sr0 179 0 7761920 mmcblk0 179 1 512000 mmcblk0p1 179 2 1536000 mmcblk0p2 179 3 10240 mmcblk0p3
また、以下のようにマウントされています。
$ df -h Filesystem Size Used Avail Use% Mounted on /dev/sda1 290G 11G 265G 4% / udev 1.9G 4.0K 1.9G 1% /dev tmpfs 376M 904K 375M 1% /run none 5.0M 0 5.0M 0% /run/lock none 1.9G 7.8M 1.9G 1% /run/shm /dev/mmcblk0p1 500M 3.5M 497M 1% /media/4628-37EE /dev/mmcblk0p2 1.5G 162M 1.3G 12% /media/6e7ece6c-7d4f-43c3-89bc-4f9e228befce
ビルドしたzImageをSDカードに上書きします。試した環境では、zImageはSDカードの1つ目のパーティション(/dev/mmcblk0p1)にあるので、/dev/mmcblk0p1のマウント先である/media/4628-37EE/にzImageが存在します。GSRD v13.1 - SD Cardの「Updating Individual Elements on the SD card」が参考になりました。
$ cp ~/yocto/build/tmp/deploy/images/zImage-1.0-r1-socfpga_cyclone5-20150118015746.bin /media/4628-37EE/zImage
SDカードへのDevice Tree Blobの上書き
zImageの上書きだけでは、実はカーネルが起動しません。(ここで何度も試行錯誤してようやく答えにたどり着きました) Helio Prebuild Imagesで提供されているhelio.dtbで上書きする必要があります。SDカードに書き込まれている既存のdtbファイルのファイル名はsocfpga.dtbなので、helio.dtbをそのまま書き込むとうまくいかないことに注意します。
$ ls -l /media/4628-37EE/ 合計 3160 -rw-r--r-- 1 fixme fixme 20584 9月 4 16:27 socfpga.dtb -rw-r--r-- 1 fixme fixme 125 9月 4 16:27 u-boot.scr -rw-r--r-- 1 fixme fixme 3202824 1月 18 10:27 zImage
以下の通り、dtbファイルを上書きします。
$ wget http://www.rocketboards.org/pub/Projects/HelioPrebuildImages/helio.dtb $ cp helio.dtb /media/4628-37EE/socfpga.dtb
アンマウントしてからSDカードを取り出します。
$ sudo umount /dev/mmcblk0p1 $ sudo umount /dev/mmcblk0p2
なぜDevice Tree Blobの上書きが必要なのか (2015/01/24 追記)
考え方としては、以下でおそらく間違っていないと思います。
これを試した時は、Linux Kernel 3.13のSDカードイメージを使用していました。 一方、yoctoで自前でビルドしたカーネルのバージョンは3.9。 そして、Helio Prebuild Imagesは3.9向け。 なので、自前でビルドしたカーネルを動作させるには、カーネルと同一バージョンで作成されたDevice Tree Blobが必要になります。
Linuxの起動
SDカードをHelioに挿入して、電源を入れます。そうすると、Linuxが起動します。確認すると、uname -aの結果がビルドした日時になっていて、確かに自前でビルドしたカーネルで起動できています。
root@socfpga:~# uname -a Linux socfpga 3.9.0 #2 SMP Sun Jan 18 10:58:42 JST 2015 armv7l GNU/Linux
Sound Blaster Live!の接続
用意しておいたUSB変換ケーブルを使って、HelioのUSB 2.0 OTG Port (J6)にSound Blaster Live!を接続します。
Linuxを起動した状態で接続しても認識しないようなので再起動してみます。
Linuxの再起動後、以下のコマンドを実行すると、Sound Blasterが認識されていることを確認できました。
root@socfpga:~# lsusb Bus 001 Device 002: ID 041e:30d3 Creative Technology, Ltd Sound Blaster Play! Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
動作確認
カーネルのオプションの設定で「OSS PCM (digital audio) API」を有効にしました。 なので、/dev/dsp経由で音が鳴るようになっています。
試しに、適当なデータを/dev/dspに書き込んでみます。すると、「ビ!」っというような音が鳴ります。他にも適当なバイナリファイルを/dev/dspに書き込むと激しいノイズ音が流れます。
root@socfpga:~# echo aaaaaaaaa > /dev/dsp root@socfpga:~# cat some.binary.file > /dev/dsp
動作確認としては、これで終わりです。あとは、/dev/dspに対して適切にオーディオデータを書き込んで楽しむのみです。
おわりに
うまくいくか不安でしたが、無事Sound Blasterを認識させて音を鳴らすことができました。 今後は、FPGAで生成した信号を鳴らしてみたいです。 Helioで音を鳴らしたい方の参考になれば幸いです。