目次: ROCK64/ROCKPro64
RK3288のGPLL系のクロック周波数が、49151999のようなおかしな値になってしまう問題も、追ってみたら意外と簡単だったのでパッチを作りました。取り込まれることを祈っておきましょう。
たぶん誰も興味が無いと思いますが、下記はRK3328 GPLL系のクロック周波数がおかしくなる問題の詳細です。
まずROCK64には24MHzの水晶が載っていて、RK3328のXIN24Mに入力されています。これがFREFになります。
PLL周波数は仕様書(RK3328 TRM)によると、
FOUTVCO = FREF / REFDIV * (FBDIV + FRAC / 224)
と書かれています。
しかしこれはおそらく誤記で正しくは、
FOUTVCO = FREF / REFDIV * (FBDIV + FRAC / 2^24)
だと思われます。
クロックドライバの実装も後者でしたし、hdkさんに教えてもらった他のRockchipの仕様書でも2^24になっていましたから、RK3328の仕様書にある224は2^24の誤記とみて問題ないでしょう。
最終的なPLL周波数は、
FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2
となります。
REFDIV, FBDIV, POSTDIV1, POSTDIV2, FRACに設定される値は、クロックドライバで下記のように定義されています。
//drivers/clk/rockchip/clk-rk3328.c
static struct rockchip_pll_rate_table rk3328_pll_frac_rates[] = {
/* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
RK3036_PLL_RATE(1016064000, 3, 127, 1, 1, 0, 134217),
/* vco = 1016064000 */
RK3036_PLL_RATE(983040000, 24, 983, 1, 1, 0, 671088),
/* vco = 983040000 */
RK3036_PLL_RATE(491520000, 24, 983, 2, 1, 0, 671088),
/* vco = 983040000 */
RK3036_PLL_RATE(61440000, 6, 215, 7, 2, 0, 671088),
/* vco = 860156000 */
RK3036_PLL_RATE(56448000, 12, 451, 4, 4, 0, 9797894),
/* vco = 903168000 */
RK3036_PLL_RATE(40960000, 12, 409, 4, 5, 0, 10066329),
/* vco = 819200000 */
{ /* sentinel */ },
};
このコードの何がおかしいのかお見せするため、試しに先頭の行の値を使ってPLL周波数を計算してみます。PLL周波数の目標値であるrateは1016064000です。その他の設定値は、
です。この設定値に基づいて各設定値を計算してみると、
となってしまい、1足りない変な値になります。1足りない原因は2項目の計算結果が63999になってしまうことですから、直すにはfracの値を1増せば良いです。fracを134218にすると、
となって、めでたしめでたしです。
以上の解析結果に基づいてfracの値を1増やすパッチをLinux MLに送りました。英語がイマイチで、うまく説明できず、原始人のような「これ値違う、俺直す」になってしまっていますが……。
RockchipのアーキメンテナのHeikoさんは、コミットメッセージがあまりにもひどいと直してくれる(昔も修正されたことがある)みたいなので、そこに甘えておきます。原始人英語がそのまま取り込まれても別に構いませんし。
目次: ROCK64/ROCKPro64
RK3328のACODECパッチをALSA MLに送ったところ、すんなり取り込まれました。やった。作者が自分ではないドライバを投稿したのは初めてかもしれません。それでも取り込まれるんですね。
あと48kHz → 44.1kHz系に切り替えたときに音が出なくなってしまう病気の応急処置パッチも取り込まれました。素早く切り替えるとやっぱり音が鳴らなくなるんですが、これ以上追う手段が無いので(2018年12月19日の日記参照)諦めています。できればRockchipの中の人に直してほしいね…。
メモ: 技術系の話はFacebookから転記しておくことにした。
目次: ROCK64/ROCKPro64
RK3328のI2S1で44.1kHz系を再生するとEINVALエラーになってしまう問題は、I2Sのマスタークロック周波数が11289600ではなく11289599などという変な値が渡されて、マスタークロックとビットクロックが整数比ではなくなることが原因でした。
エラーを無視して処理を流してみると、分周比がおかしくなります。本来11289600 / 2822400 = 4にならなければいけないのですが、11289599 / 2822400 = 3になって、周波数が高めに設定されてしまい、異常に音が高くなります。
Rockchip Linuxはどうやって解決しているのか見るとDIV_ROUND_CLOSESTというマクロで割り算の結果を4側に丸めていました。本当の原因は変な端数の値を返すクロックドライバだと思うので、この対応はちょっとイケてないですね……。
ACODECにも2つほど問題があって、完全には解決できていません。
問題1つ目は、44.1kHz系を再生すると、全く音が出なくなる症状です。これはコアのリセットで直るようです。
リセットを掛けないと、切り替え以降、何をしても全く音が出ません。しかしRockchip Linuxのコードは全くリセットを掛けておらず、なぜこれで動くのか理解できません……。
気になる点としては、リセットすることでdai_set_fmtで設定されたI2Sのマスタースレーブ設定が吹き飛んでしまうことです。しかしACODECはなぜかマスタースレーブ設定が間違っていても動いてしまいます。ハードが設定値を無視しているか、Rockchip Linuxのドライバが間違っているかどちらかでしょう。真相はわかりません。
問題2つ目は、48kHz系 → 44.1kHz系への切り替え時、たまに音が異常に小さくなる症状です。これは直せそうにないです。
これくらいまではわかりましたが、鳴るときor鳴らないときの法則が全くわからないので、これ以上追うのは厳しいです。
体感では、クロック系の切り替えが早すぎると(1秒くらい?)症状が出やすいです。何でだろう??
while :; do aplay -D hw:0,0 48k.wav ; aplay -D hw:0,0 44k.wav ; done
こんなスクリプトをグルグル回すと、44kHz系は全く音が出ません。待ち時間が足りないのかと思いPRECHARGEの後に500msのウェイトを入れましたが、結果は変わらず音が出ません。。。
Raspberry Pi対抗ボードの多くはRaspberry Pi 3のEthernetが遅いこと(USB接続らしい)を引き合いに出し、ネットワークが速いことを宣伝文句にしています。
宣伝文句自体は疑っていませんが、どの程度の差があるかは知らないので、測定してみました。ちょうどTinker Boardも購入しましたし、Rockchip同士の比較もしてみたいと思います。
測定は簡単です。受信側のPCで下記を実行します。
$ iperf3 -s -p 11111
送信側の各種ボードで下記を実行します。
$ iperf3 -c (PCのIPアドレス) -p 11111
受信側のPCのCPUはRyzen 7 2700で、マザーボードはASUS B450-F GAMINGです。OSはDebian GNU/Linux amd64のTesting版です。測定時点でのカーネルは4.18.0-2-amd64というバージョンになっていました。
結果だけ先に言うとTinker Board(RK3288)の方が速いです。ROCK64(RK3328)の方が後発のSoCなのですが、Ethernetは遅いみたいですね。
ちなみにRaspberry Pi 3は94Mbpsでした。そもそもGigabit Etherじゃないので、比べ物になりません。
念のため各ボードのEthernetケーブルを入れ替えてみましたが、結果は変わりませんでした。
参考までにファイルサーバとして使っているPentium Jのマシンから、同様の計測を行ったところ942Mbits/sec でした。
結果はこんな感じでした。
katsuhiro@linaro-alip:~$ iperf3 -c 192.168.1.2 -p 11111 Connecting to host 192.168.1.2, port 11111 [ 4] local 192.168.1.16 port 58608 connected to 192.168.1.2 port 11111 [ ID] Interval Transfer Bandwidth Retr Cwnd [ 4] 0.00-1.00 sec 113 MBytes 950 Mbits/sec 0 358 KBytes [ 4] 1.00-2.00 sec 112 MBytes 942 Mbits/sec 0 358 KBytes [ 4] 2.00-3.00 sec 112 MBytes 941 Mbits/sec 0 358 KBytes [ 4] 3.00-4.00 sec 112 MBytes 941 Mbits/sec 0 358 KBytes [ 4] 4.00-5.00 sec 112 MBytes 941 Mbits/sec 0 358 KBytes [ 4] 5.00-6.00 sec 112 MBytes 943 Mbits/sec 0 406 KBytes [ 4] 6.00-7.00 sec 112 MBytes 941 Mbits/sec 0 406 KBytes [ 4] 7.00-8.00 sec 112 MBytes 941 Mbits/sec 0 406 KBytes [ 4] 8.00-9.00 sec 112 MBytes 941 Mbits/sec 0 406 KBytes [ 4] 9.00-10.00 sec 112 MBytes 941 Mbits/sec 0 406 KBytes - - - - - - - - - - - - - - - - - - - - - - - - - [ ID] Interval Transfer Bandwidth Retr [ 4] 0.00-10.00 sec 1.10 GBytes 942 Mbits/sec 0 sender [ 4] 0.00-10.00 sec 1.10 GBytes 942 Mbits/sec receiver iperf Done.
katsuhiro@rock64:~$ iperf3 -c 192.168.1.2 -p 11111 Connecting to host 192.168.1.2, port 11111 [ 4] local 192.168.1.102 port 54768 connected to 192.168.1.2 port 11111 [ ID] Interval Transfer Bandwidth Retr Cwnd [ 4] 0.00-1.00 sec 97.6 MBytes 819 Mbits/sec 0 356 KBytes [ 4] 1.00-2.00 sec 96.4 MBytes 808 Mbits/sec 0 395 KBytes [ 4] 2.00-3.00 sec 95.8 MBytes 804 Mbits/sec 0 395 KBytes [ 4] 3.00-4.00 sec 95.7 MBytes 803 Mbits/sec 0 395 KBytes [ 4] 4.00-5.00 sec 95.8 MBytes 803 Mbits/sec 0 395 KBytes [ 4] 5.00-6.00 sec 95.8 MBytes 804 Mbits/sec 0 395 KBytes [ 4] 6.00-7.00 sec 95.8 MBytes 804 Mbits/sec 0 395 KBytes [ 4] 7.00-8.00 sec 95.7 MBytes 803 Mbits/sec 0 395 KBytes [ 4] 8.00-9.00 sec 95.8 MBytes 804 Mbits/sec 0 395 KBytes [ 4] 9.00-10.00 sec 95.8 MBytes 803 Mbits/sec 0 395 KBytes - - - - - - - - - - - - - - - - - - - - - - - - - [ ID] Interval Transfer Bandwidth Retr [ 4] 0.00-10.00 sec 960 MBytes 805 Mbits/sec 0 sender [ 4] 0.00-10.00 sec 958 MBytes 804 Mbits/sec receiver iperf Done.
katsuhiro@raspberrypi:~ $ iperf3 -c 192.168.1.2 -p 11111 Connecting to host 192.168.1.2, port 11111 [ 4] local 192.168.1.105 port 46476 connected to 192.168.1.2 port 11111 [ ID] Interval Transfer Bandwidth Retr Cwnd [ 4] 0.00-1.00 sec 11.3 MBytes 94.6 Mbits/sec 0 29.7 KBytes [ 4] 1.00-2.00 sec 11.2 MBytes 94.1 Mbits/sec 0 29.7 KBytes [ 4] 2.00-3.00 sec 11.2 MBytes 94.1 Mbits/sec 0 29.7 KBytes [ 4] 3.00-4.00 sec 11.2 MBytes 94.2 Mbits/sec 0 29.7 KBytes [ 4] 4.00-5.00 sec 11.2 MBytes 94.1 Mbits/sec 0 29.7 KBytes [ 4] 5.00-6.00 sec 11.2 MBytes 94.2 Mbits/sec 0 29.7 KBytes [ 4] 6.00-7.00 sec 11.2 MBytes 94.2 Mbits/sec 0 29.7 KBytes [ 4] 7.00-8.00 sec 11.2 MBytes 94.1 Mbits/sec 0 29.7 KBytes [ 4] 8.00-9.00 sec 11.2 MBytes 94.2 Mbits/sec 0 29.7 KBytes [ 4] 9.00-10.00 sec 11.2 MBytes 94.1 Mbits/sec 0 29.7 KBytes - - - - - - - - - - - - - - - - - - - - - - - - - [ ID] Interval Transfer Bandwidth Retr [ 4] 0.00-10.00 sec 112 MBytes 94.2 Mbits/sec 0 sender [ 4] 0.00-10.00 sec 112 MBytes 94.2 Mbits/sec receiver iperf Done.
目次: ROCK64/ROCKPro64
Tinker Boardでサウンド周りを有効にしてlinux-nextを動かしてみたものの、指摘された不具合(2018年12月5日の日記参照)が出ません。
メールではDMAドライバのどこかでクラッシュした、と言われました。サウンド周りのハードウェアはI2Sとコーデックが居ますが、DMAを使うのはI2Sだけです。コーデックmax98090はSoC外部に居ますから、SoC内部のDMAを使う術がありません。
I2Sが原因ならば、SoC内部のハードウェア起因ですから、Tinker BoardだろうがChromebook C201だろうが、ボードに関わらず現象が再現しても良さそうなのに。
Chromebookで使われているグルードライバrockchip-snd-max98090の影響も疑って、Chromebook C201のデバイスツリー(rk3288-veyron-speedy.dts)からデバイスノードの設定をパクってきて、max98090をspdif-transimtterに差し替えて(Tinker Boardにmax98090は搭載されていない)、無理やり動かしてみましたが、特に何事も無く動いてしまいました。
どうやってもChromebook C201じゃないと再現しないのかな?良くわからないバグだ……。
ROCK64のときはアナログオーディオ出力でもHDMI出力でも、SoC内蔵のI2Sハードが動作しましたが、Tinker Boardはちょっと事情が違います。
Tinker Boardにもアナログオーディオ端子は付いていますが、接続先はRK3288ではなくオンボードのUSB Audio(Realtek ALC4040)です。アナログオーディオのためにわざわざ専用USBデバイスを載せるとは、豪華なボードだなあ〜。
というわけで、Tinker BoardでSoC内蔵のI2Sが動くかどうか試すには、アナログオーディオ端子ではダメで、HDMI出力じゃないと本当に動作しているかどうかわからないです。我が家にはデジタルテレビならありますが、ボードからケーブルが届かないですね。
できればHDMIが映せて、音も出せて、ボードの隣に置いても邪魔にならないくらい小さいモニタがあるとベストですが、我が家にそんなもんは無い……。
メモ: 技術系の話はFacebookから転記しておくことにした。少し加筆した。
< | 2018 | > | ||||
<< | < | 12 | > | >> | ||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
- | - | - | - | - | - | 1 |
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 | - | - | - | - | - |
合計:
本日: