Volumio は I2S 出力が可能なわけで、I2S 信号を観察してみました。オシロを繋いでこんな感じで
ピンアサインが分かりにくいんですが、SDカード側がある側の、外側、P1コネクタに近い側が1番ピンです。3番PinがBitCLK、4番PinがLRCLKですね。
上のCH.1がLRCLK、下のCH.2がBitCLKです。そして、この中のLRCLKの立下り部分を拡大すると、こんな信号が観測されます。
CLKなのに、信号が2重に見えます。つまり、クロックの幅が一定になっていないということですね。ズレた線が薄いところをみると、クロック幅がずれた信号が、少数ですが混ざってるということです。これって、ジッタそのものですよね。
なんでこんなことが起こるのかというと、オーディオモジュールのクロック源が 500MHz の PLL だから。PLLが出力するクロックを分周して欲しいクロック信号を作りだすというのは、デジタル回路の基本中の基本ですね。そして、分周なんだから、元クロックの整数割りしかできません。
つまり、500MHz から、44.1kHz を作ろうとすると、44.103kHzか、44.099kHzしか作れません・・・・・・・いや、別にそれでいいだろう?って気は激しくしますが。
そこで、BCM2835 のクロック生成回路は、単位時間内のクロックパルスのうち、いくつかの長さを短くすることで、単位時間当たりのクロック数を正確にする。という機能をもっています。
つまり、クロック幅の正確さを犠牲にすることで、周波数の正確さを獲てるわけですね。オシロでみたクロックの波形が2重になって見えるのは、その短くなったクロックを観測してしまっているため。
そいじゃ、クロック数の正確さを犠牲にして、パルス幅の正確性をとったらどうなる?
ちうわけで、ジッタを除去してみました。
方法は、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% ほど早くなります。
コメントする