2015年2月アーカイブ

Volumio は I2S 出力が可能なわけで、I2S 信号を観察してみました。オシロを繋いでこんな感じで

DSCN4572.JPGピンアサインが分かりにくいんですが、SDカード側がある側の、外側、P1コネクタに近い側が1番ピンです。3番PinがBitCLK、4番PinがLRCLKですね。

DSCN4574.JPG上のCH.1がLRCLK、下のCH.2がBitCLKです。そして、この中のLRCLKの立下り部分を拡大すると、こんな信号が観測されます。

DSCN4573.JPGCLKなのに、信号が2重に見えます。つまり、クロックの幅が一定になっていないということですね。ズレた線が薄いところをみると、クロック幅がずれた信号が、少数ですが混ざってるということです。これって、ジッタそのものですよね。

なんでこんなことが起こるのかというと、オーディオモジュールのクロック源が 500MHz の PLL だから。PLLが出力するクロックを分周して欲しいクロック信号を作りだすというのは、デジタル回路の基本中の基本ですね。そして、分周なんだから、元クロックの整数割りしかできません。

つまり、500MHz から、44.1kHz を作ろうとすると、44.103kHzか、44.099kHzしか作れません・・・・・・・いや、別にそれでいいだろう?って気は激しくしますが。

そこで、BCM2835 のクロック生成回路は、単位時間内のクロックパルスのうち、いくつかの長さを短くすることで、単位時間当たりのクロック数を正確にする。という機能をもっています。

つまり、クロック幅の正確さを犠牲にすることで、周波数の正確さを獲てるわけですね。オシロでみたクロックの波形が2重になって見えるのは、その短くなったクロックを観測してしまっているため。

そいじゃ、クロック数の正確さを犠牲にして、パルス幅の正確性をとったらどうなる?

DSCN4575.JPGこうなりますww

ちうわけで、ジッタを除去してみました。

方法は、linux/sound/soc/bcm/bcm2708-i2s.c の 485行目あたり

        if (!dev->bclk_ratio) {
            /*
             * Overwrite bclk_ratio, because the
             * above trick is not needed or can
             * not be used.
             */
            bclk_ratio = 2 * data_length;
        }

        target_frequency = sampling_rate * bclk_ratio;

        clk_src = BCM2708_CLK_SRC_PLLD;
//      mash = BCM2708_CLK_MASH_1;

        dividend = bcm2708_clk_freq[clk_src];
        dividend <<= BCM2708_CLK_SHIFT;

        do_div(dividend, target_frequency);
        divi = dividend >> BCM2708_CLK_SHIFT;
        divf = dividend & BCM2708_CLK_DIVF_MASK;

こんな風に、mash 値を上書きしてる処理をコメントアウトするだけ。

そして、これをコンパイルして起動可能なSDカードにしたものがこちらです。(三分クッキング風に)
※300KByteくらいあります。展開すると2GByteくらいになります

0.06%のジッターを聞き比べてください。なお、この変更で曲の再生がほんのすこし、0.008% ほど早くなります。

Volumioの構造

Volumioをいじるためには、まずシステム構造を知らないと、お話にならないわけです。あれこれ弄って分かったことをまとめておきましょう。

volumio.png主要なモジュールを並べるとこんな感じ。大きくわけて、2つのモジュール相関があります。

  • Webブラウザに制御画面を表示して、ユーザからの指示に従って再生、停止などを制御する流れ
  • NASやストレージ装置から音楽ファイルを読み出し、オーディオ信号として出力する流れ

重要なのは、当然ながらオーディオ信号の流れでしょう。ポイントは、mpdという音楽再生デーモンと、デバイスドライバに制御されるCPU内部のオーディオモジュールですね。

Volumioをハックするには、これを把握しておかないと手も足も出ません

Volumio という音楽再生サーバがあるのです。Rasperry PI でUSBメモリーとか、NASに入ってる音楽データを、Web GUIで操作して、音楽を再生しようっていうもので、Linux Kernel を含むOSイメージとして配布されています。

で、こんなのあるんなら、Kernel からいじって、音質改善みたいなことをやりたいなぁと思うわけですが、そーなるとまずは開発環境をつくらないといけない。Rasperry PI は全うに Linux 環境なので、実機上でコンパイルしても良いんですが、時間がどれだけかかるかわかったものじゃない。

というわけで、x86(64)マシン上にクロスコンパイル環境を作ってしまおう!というお話です。


クロスコンパイル環境を作る手順は、大まかにこんな感じ

  1. ホストとなるマシンにOSをインストールする
  2. ホストに開発環境に必要なパッケージをインストールする
  3. Linux KernelのSoruceセットを取ってくる
  4. クロスコンパイラをとってくる
  5. コンパイルする
  6. コンパイルしたバイナリを実機にコピーする

参考にしたサイトも並べておきましょう。私の二次記憶もぐてっくRaspberry Piのカーネルをクロスコンパイルするひまじめ


ホストOSとしては、おそらく Linux だったらなんでもいいんだと思います。たぶんw Raspberry PI の Linux は、Raspbian という名前のディストリビューションで、名前からも分かるとおり Debian 系です。たぶん、Debian をそのままホストにするほうがいいんじゃないかなぁ、と思いつつ、私は Ubuntu にしました。Ubuntu は、Desktop OSとしての色合いが強いのですが、どーせtelnet して使うんだから、Ubuntu Server にします。

OSをインストールしたら、これを入れなきゃ話にならない!っていうものからインストール

apt-get -y install tcsh
apt-get -y install telnetd xinetd
apt-get -y install nfs-client

次に、開発環境に必要なものをインストール

apt-get -y install git
apt-get -y install build-essential libncurses5-dev

いよいよ Linux のソースを取ってきます

git clone https://github.com/raspberrypi/linux.git
git clone https://github.com/raspberrypi/tools.git

Kernel Source と、クロスコンパイルツールを持ってきます。以上で、クロスコンパイルを実行するための準備は完了。


さぁ、コンパイルしましょう。一番気になるのが、クロスコンパイラの使い方。これは make コマンドが CROSS_COMPILE 環境変数を指定しておけば、make コマンドがいい具合に使ってくれるらしい。よって、こんな感じ

CCPREFIX=../tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/arm-linux-gnueabihf-
make ARCH=arm CROSS_COMPILE=${CCPREFIX}
make ARCH=arm CROSS_COMPILE=${CCPREFIX} modules

なおこれは、64bit 環境でやったから、こうなったもの。ホストの環境で arm-linux-gnueabihf-raspbian-x64 は各々の環境にあわせないといけない。

CCPREFIX は .cshrc あたりで環境変数として設定してあげたほうがいいんだろうな。ついメンドクサクなって、この環境変数を設定したShellを開きっぱなしでつかっちゃってるけど。


けっこーな時間がかかりますが、これでコンパイル完了です。バイナリーができました。あとはKernelファイルを実機にコピーして起動するだけ!!・・・・・・と思いきや、ここでLinuxであることが仇になります。いまどきのLinuxは、もはやモノリシックカーネルと言っていいのか?というレベルにKernel Moduleを使いまくる。

NetBSD だったら、Kernelというファイルを一個、実機にコピーすれば、それでKernelの入れ替えが完了するんですが、Linux の場合、.ko ファイルという、Kernel Moduleファイルを、どっさりと正しいディレクトリにコピーしないといけない。

ちうわけで、Kernel Moduleファイルを実機にコピーします

mkdir ../install
make ARCH=arm CROSS_COMPILE=${CCPREFIX} INSTALL_MOD_PATH=../install modules_install

これでコピーするべき .ko ファイルが、../install ディレクトリにあつまるわけです。あとは分かりますね?このディレクトリの構造を、そのまんま実機にコピーしてあげましょう。

いよいよ、本当に最後

arch/arm/boot/zImage

これが出来上がった Kernel ファイルです。このファイルを実機の

/boot/kernel.img

としてコピーしてあげれば、インストール完了。正常に起動することを祈りながら、再起動しましょう

このアーカイブについて

このページには、2015年2月に書かれたブログ記事が新しい順に公開されています。

前のアーカイブは2015年1月です。

次のアーカイブは2015年3月です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。