目次: ROCK64/ROCKPro64
以前(2018年12月)にROCKPro64を購入したのですが、シリアルが文字化けして使い物にならず、ずっとお蔵入りになっていました。
最初はケーブルの接続や、接地がおかしいのかと思いましたが、GND側はきっちり0Vでした。どうも単純な原因ではなさそうだったので、オシロスコープで信号を見ることにしました。テストパターンとして0と1が交互に出現し、一番転送が難しいパターンと思われる0x55 'U' の文字を出力しています。
正常に出力できているROCK64と比較すると、ROCK64は出力が0 → 1 → 0と変化する際に0V → 3V → 0Vのように電圧が振れますが、ROCKPro64は、0V → 2.48V → 0Vのように立ち上がり側が遅く、中途半端な電圧になっています。
下記の画像の青色の線がROCK64のシリアル出力で、オレンジ色の線がROCKPro64のシリアル出力です。どちらも1秒ごとに 'U' を出力して、最初の立ち下がり(Start Bit、必ず0)にトリガを掛けています。
ROCK64は綺麗な波形ですが、ROCKPro64は0V → 3Vへの立ち上がりが間に合っていないことが分かるかと思います。
文字化けの原因ですけども、シリアルの転送速度(1.5Mbps、1ビット666ns)に対し、0 → 1の立ち上がりが遅すぎる(650nsくらい)からでしょう。出力側は1を送出しているつもりでも、信号が立ち上がるのが遅いため、受信側は0だと解釈してしまう場合があります。
転送速度を落とせば改善するかもしれません。しかしRockchipのU-Bootはなぜか1.5Mbps固定で転送してくる困った奴で、下手にシリアルの転送速度を変えるとU-Bootが操作できなくなり、非常に使いづらいのです。イマイチですね……。
ROCKPro64にはRockchipのRK3399と言うSoCが搭載されていて、RK3399は一部のピンのDrive Strength、つまりピンに流せる電流量を調整できます。決して特殊な機能ではなく、大抵のSoCが持つ普通の機能です。
ROCKPro64がコネクタに引き出しているシリアルはUART2です。UART2はGPIO4_C4(TX)とGPIO4_C3(RX)というピンに割り当てられています。幸運なことにRK3399ではこれらのピンのDrive Strengthが変更できるので、設定値を振って(※)オシロで波形を見てみました。
下記の画像が測定結果です。1枚目はデフォルトかつ最小の3mA、2枚目は最大の12mA設定です。出力している文字は前回同様0x55 'U' で、トリガも前回同様Start Bitの立ち下がりに仕掛けています。オシロのRising, Falling Time解析をONにしたので、立ち上がり、立ち下がりに掛かった時間も一緒に表示されています。
Drive Strength = 3mAのときのシリアル出力波形
Drive Strength = 12mAのときのシリアル出力波形
字が若干見づらいので、一応書いておくと、立ち上がりの時間は650ns → 300nsくらいに改善しました。良い感じですね。
ちなみにスクリーンショットの色が変で、文字が読みづらいのは仕様です。Tektronixさん、スクリーンショット背景の白黒反転処理、バグってますよ……??
それはさておきDrive Strengthの変更で、ROCKPro64のシリアル文字化けはかなり改善されました。しかし完全ではなく大量に出力した際に若干文字化けします。
さらなる改善のためには、シリアルの転送速度を落とすくらいしか思いつきません。が、U-Bootの書き換えをするのが面倒くさいので、また今度にします……。
(※)レジスタ名はGRF_GPIO4C_Eで、アドレスは0xff77e138です。書き込む値は0x03c00xx0をお勧めします。xxの部分はドライブ能力を最小にするなら00で、最大にするなら3cです。
メモ: 技術系の話はFacebookから転記しておくことにした。追記、文章の組み換えをした。
目次: Linux
Linuxのクロックフレームワークで実装できるクロック分周器のドライバは2種類あります。
1つはinteger dividerで、入力されたクロック周波数の1/3や1/4など整数比の周波数で出力するハードウェアです。もう1つはfractional dividerで、周波数をx/yにするハードウェアです。
後者のfractional dividerドライバは、標準動作とカスタム動作のドライバが書けます。標準動作の場合、分子と分母に設定できる値に、何ら制約がないものとして動作します。カスタム動作のドライバは、特殊な制約のあるハードウェア向けです。
今のところカスタム動作のfractional dividerドライバを実装しているのはRockchipだけです。Rockchipの場合、分母が分子の20倍以上でなければ出力周波数が不安定になる制約があるようです。
Rockchipが変な仕様であることは間違いないと思いますが、Linuxに対応しているだけ、まだマシとも取れますね。世の中には「どうしてこうなった??」としか思えない、変な仕様のハードウェアがたくさん存在しますし……。
メモ: 技術系の話はFacebookから転記しておくことにした。
目次: ROCK64/ROCKPro64
先日購入したHDMIモニタのおかげで、ROCK64のI2S0つまりHDMI Audioの動作確認ができました。
しかし以前(2018年11月11日の日記参照)悩んでいた通り、単純にI2S0を有効にすることはできません。DMAチャネルが足りない問題が発生するためです。
ROCK64に搭載されているRockchip RK3328のDMACは、16のDMAチャネルを持っていますが、そのうち8chしか同時に使えない仕様になっています。
現在のlinux-nextのROCK64向けデバイスツリーでは、既に7chを使用(I2S1 2ch, SPDIF 1ch, SPI0 2ch, UART2 2ch)していますから、ここに2chを使用するI2S0を追加すると合計9chになって、オーバーしてしまいます。
仕方ないのでUART2のDMA割り当てを解除して、I2S0に割り当てるパッチを投稿しました。
私がパッチに書いた説明が悪かったのだと思いますが、メンテナーのHeikoさんから「どうしてUART2のDMAチャネルをI2S0が使えるのかわからない」という返事がきました。ですよね……私も最初意味不明でしたし。
できる限り説明を加えて返事しましたが、理解してもらえると良いな。
ややこしいことに、RK3328の仕様書を見ると、各DMAチャネルにはIDが(仕様書ではReq number)が振られていて、ぱっと見16チャネルが全て同時に使えそうに見えるんですよ。
この仕様書から「各DMAチャネルは独立しているけど、全てのチャネルが同時に使える訳ではない」という意味を読み取れる人はなかなかいないと思います。
少なくとも私はDMAのReq numberとチャネル数の関係を理解するのは無理だったので、DMACのドライバ(PL330)を追いかけました。
サウンド系からDMAチャネルの割り当てを要求するとき、次のような呼び出し関係になります。
rockchip_pcm_platform_register()
devm_snd_dmaengine_pcm_register()
snd_dmaengine_pcm_register()
dmaengine_pcm_request_chan_of()
dma_request_slave_channel_reason()
of_dma_request_slave_channel()
ofdma->of_dma_xlate() => of_dma_pl330_xlate()
dma_get_slave_channel()
dma_chan_get()
pl330_alloc_chan_resources()
pl330_request_channel()
まず、関数of_dma_pl330_xlate() にはローカル変数chan_idが登場します。これがDMAのIDに相当します。例えばUART2の送信側ならchan_id = 6になります。
元になる数字はどこから来るかというと、of_dma_match_channel() でデバイスツリーから情報を貰っています。RK3328の場合、デバイスツリーでDMAチャネルを指定する際は、Req numberを書くようです。
次に、関数pl330_request_channel() に構造体struct pl330_dmacのメンバーchannelsという配列が登場します。このchannelsの数がDMACのDMAチャネルの数と等しいです。Req numberとは無関係に、DMAチャネルを要求されると先頭から埋まっていきます。
こんな仕様が初見でわかる訳ないじゃない。むり。
メモ: 技術系の話はFacebookから転記しておくことにした。1節加筆。
< | 2019 | > | ||||
<< | < | 02 | > | >> | ||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
- | - | - | - | - | 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 | - | - |
合計:
本日: