Raspberry Pi 5 がバグッてる?

この前、投稿したRP1チップ用のGPIOライブラリが以外に高速に動作するようなのでソフトウェア実装のI2CやSPIもいけるかなと実験してみたところ先頭のパルス幅制御がなぜかうまくいかない。

Raspberry Pi 5のRP1-Chipを使い倒す(GPIO)

単純なプログラムで試してみても先頭だけ想定通りのパルス幅にならない。ループではなくusleep/nanosleepを使っても同じ結果となる。

CPUキャッシュ制御による影響かとも思ったが数マイクロ秒もの遅延が発生するとは思えないし...なんとかバリアとかいうアセンブラ命令も試してみたけど変化なし。時間間隔が短いときに先頭のパルスが潰れてしまうのはなぜだろう?

PS.
色々試してポート出力の直後でポート入力すると正しい動作になることがわかったが1.2usぐらいのウェイトがかかってしまうようだ。
それしか方法がないとするとソフトウェアで生成可能なパルスの最大周波数は400KHz程度まで落ちてしまうことになる。RP1チップ劇速!とか思っていたがもしかして前バージョンより遅くなってない?

で、さらに調べてみたところポート出力を2回実行することで5MHzまで速度を上げることが出来た。但し、トグル出力は複数回実行出来ないので改善不可能。

GPIOが非同期実行なためプログラム通りに動かすためには強制的に同期させるためのコードを追加する必要があるということになるようだ。GPIOは入力或いは二回出力すると同期がとれるようだが入力は1.2us以上と劇遅なので注意するべし。

【ループ1000回。先頭のパルスを拡大】

【ループ1000回。先頭のパルス幅がヘン】

【ループ2000回。まだ少しヘン】

【ループ5000回。もうちょい】

【ループ10000回。まあまあ】

【テストプログラム】

この件、調べてみたらBCM2712のPCIEコントローラに起因する問題らしい...

【drivers/pinctrl/pinctrl-rp1.c:rp1_pinctrl_probe()】

【コメント原文】
Workaround for the vagaries of PCIe on BCM2712

If the link to RP1 is in L1, then the BRCMSTB RC will buffer many
outbound writes – and generate write responses for them, despite the
fact that the link is not yet active. This has the effect of compressing
multiple writes to GPIOs together, destroying any pacing that an application may require in the 1-10us range.

The RC Slot Control configuration register is special. It emits a
MsgD for every write to it, will stall further writes until the message
goes out on the wire. This can be (ab)used to force CPU stalls when the link is inactive, at the cost of a small amount of downstream bandwidth and some 200ns of added latency for each write.

Several back-to-back configuration writes are necessary to “fill the pipe”, otherwise the outbound MAC can consume a pending MMIO write and reorder it with respect to the config writes – undoing the intent.

of_iomap() is used directly here as the address overlaps with the RC driver’s usage.

【コメント日本語訳】
BCM2712 における PCIe の不安定さに対する回避策

RP1 へのリンクが L1 の場合、BRCMSTB RC は、リンクがまだアクティブでないにもかかわらず、多くの送信書き込みをバッファリングし、それらに対する書き込み応答を生成します。これにより、GPIO への複数の書き込みがまとめて圧縮され、アプリケーションが 1~10us の範囲で必要とするペーシングが破壊されます。

RC スロット制御構成レジスタは特別なレジスタです。このレジスタは、書き込みごとに MsgD を発行し、メッセージが送信されるまで以降の書き込みをストールします。このレジスタを悪用すると、リンクが非アクティブなときに CPU ストールを強制的に実行できますが、その代償として、ダウンストリーム帯域幅がわずかに消費され、書き込みごとに約 200ns のレイテンシが追加されます。

「パイプを埋める」には、連続した複数の設定書き込みが必要です。そうしないと、送信側の MAC が保留中の MMIO 書き込みを消費し、設定書き込みの順序を変更してしまう可能性があり、意図した動作が無効になります。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA


このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください