2024年4月17日水曜日

STM32G4のFDCANでチョット遊ぶ

 STM32G4のFDCANを軽く触ってみた。

 FDCAN1とFDCAN2を有効化、GPIOはAF_ODで初期化して、47Ωでプルアップ。ボーレートは250kbaudと2.5Mbaudに設定。FDCAN1から送ってFDCAN2で受信。

 ドライバ無しのCANネットワークはArduinoとか小規模なマイコン(回路)でTXをダイオードORして1本にまとめてRXへ分配するのと同じような考え方。


 試しに、標準、FD(低速)、FD(高速)、標準、FD(低速)、FD(高速)、FD(低速)、FD(高速)、という8個のパケットを送信。

 オシロで見ると、ちゃんとボーレートが切り替わっているのが見える。ジャンパワイヤを何本か飛ばした程度であれば、オープンドレインの470Ωで2.5Mbaudは問題なさそう。もう少し早く(or容量が大きく)なるとちょっと厳しいかな。抵抗値は220Ωくらいまでは問題ないと思うけど、あんまり小さくしてもねぇ。ちゃんと使いたいならドライバ入れろって話だし。

 SiglentのオシロはCAN 2.0Bまで対応かな? CAN FDはデコードできない。ただしCAN FDのパケットは単にエラーになるだけで、ほとんどの場合はそれに続くCAN 2.0パケットは正しくデコードできる。CAN FDでは2.0のリモートフレームで8バイトを超えるデータ数を要求できるけど、Siglentのデコーダではこれはエラーとして処理している。


 プロトコルトリガはスタートならFDにもトリガがかかる。プロトコルトリガ自体はたぶんFPGAとかで簡易的に処理しているはずなので、データ流しっぱなしにすれば画面更新レートも非常に高い(デコーダは追いつかないけど)。


 IDとかでトリガすることもできるけど、操作性がかなり悪い。まあ、このオシロはデフォで操作性が悪いので、プロトコルトリガだからという問題ではないのだが。Siglentのドキュメントを読むとTelnetでCANバストリガ関係も設定できるんだけど、試しに叩いてみても反応しない。


 LAP-Cは一応CAN FDにも対応。ただしCAN FDを使う場合はBRSのON/OFFが混在していると正常にデコードできない。一旦エラーになると多くの場合で後続のパケットも巻き込んでエラーになる。BRSのON/OFFを混在させなきゃいけない状況というのも特に思いつかないので、実用上は問題ないのかもしれないけど。

 LPA-Cのプロトコルトリガは結構手抜き実装な感じがあるな。LAP-C Proだと改善してるのかな? /* LAP-CとLAP-C Pro、当初は併売してたけど、もうLAP-Cは売ってないんだな。価格帯が全く違うから、電子工作用のロジアナとしてZEROPLUSはもう高級品だ */

*

 STM32G4のFDCANで、CAN 2.0BとCAN FDを混在させた時に、時々CAN FDの長いパケットの後ろがゼロ埋めになることがある。

 例えば受信結果は

     635 12 ESI0 BRS0 CLS     0 63 1  RMT

0000019F 64 ESI0 BRS0 CLS     0 63 1  DAT: 70 D7 5D D6 95 8E 47 8A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

0BB80000  3 ESI0 BRS0 CLS     0 63 1  RMT

000006E7  4 ESI0 BRS0 CLS     0 63 1  DAT: C6 E7 3E 20

 みたいな感じになる。

 その区間をオシロで見てみると

 前後のId635やId0BB80000は正しく見えているけど、Id0000019FはBitRateSwitchがOFFで64バイトなのに、明らかに短い。

 起動時直後に頻発するような印象。少し送信してると問題なくなる感じ。

*

 G4のFDCANはTIM3と連携して、送信時と受信時のTIM3のカウント値を記録する機能がある(FDCANに内蔵したカウンタも使えるけど、BRS ONだとtickの長さが変わるので、with BRSで使うならTIM3が必要)。受信側は受信時のタイムスタンプが得られるけど、送信側はあくまでも送信したタイムスタンプを後で読み出すことしかできない。STM32F1のbxCANではSOFのタイムスタンプ値を8バイトの末尾2バイトに埋めて送信する機能があるけど、G4のFDCANではそういう機能は無いはず。


 例えばTIM3のtickを16us(170MHzならプリスケーラ2720)に設定してやれば1.048秒で1周期になるので、GPSの1PPSでTIM3をクリアすれば、あるパケットを送信した時刻をUTCに対して16us秒の分解能で計測できる。続くパケットで「さっきのパケットはUTCで何マイクロ秒の時刻でした」というのを送ってやれば、受信側でも1個目のパケットの受信時刻を計測しておいて、続くパケットに含まれる時刻情報と1個目の時刻を比較してやれば、UTCに対して良い精度で自分のカウンタを同期できる。差を微分すればUTCに対する自分のカウンタの速度差も計測できる。

 このタイムマーカーパケットはあくまでも送受信間でタイマを比較するために使うだけ(決められた時刻ピッタリに送る必要はないもの)だから、破棄されない程度の優先度であれば良いので、大きなパケットが流れているバスでも時刻比較に使うことができるはず。ただしルータを通すとディレイやジッターが増えるから、ルータを使うのであればルータ自身が時刻決定を行ったうえで、下位のネットワーク(タイムサーバーから遠い方)へ伝播させる必要がある(ジッタはルータ1段ごとにランダムに増えていく)。


 ランダムなパケットを送りつつ、タイムマーカーを送るテスト。

 Std123h DLC0が基準パケット、Std123h DLC2が基準パケットを送信した時刻を送るパケット。ランダムなパケットはFIFOの空きが1より多い場合に送信しているから、タイムマーカーを割り込んで送ることができる。

 受信側はStd123h DLC0のパケットを受信した際のタイムマーカーと、Std123h DLC2で送られてくるタイムスタンプを比較して、時刻サーバーと自身の時刻差を求めることができる。あるいは、Std123h DLC2だけを送って、前回のStd123hのタイムスタンプを送る、みたいな運用でもいい。ただしこの場合はStd123hを送る間隔分、タイムスタンプ値を得るまでの遅延が発生する。


 また、TIM3のリセット(外部入力で蹴られる)をトリガから出力して、TIM2で受ければ、外部から入力された1PPSの数をカウントできる。適当な原点からの経過時間をGPS基準で32bitの秒と16bitの分数で表現できる。今回の場合だと分解能16usで130年程度(ほぼ47.93ビットレンジ)を計測できる。例えば1970年1月1日0時からの経過秒数とか、1980年1月6日0時からの経過秒数とか。ロールオーバーが気になるならシステム起動時とか任意の時点を原点にしてもいいし。


 タイムマーカーのパケット(Std123h DLC0)を送った時刻を、32bitの秒と16bitの分数の合わせて8byteとして送信している(8バイトに収まるのでCAN 2.0で送れる。もちろんCAN FD with BRSで送ったほうが短く遅れるけど)。

 今回はTIM3のクロックソースにコアクロック(外付け水晶を逓倍したもの)を使用しているけど、GPSから10MHzを受けられるのであればそれを使うのが一番精度が出る(10MHzである必要はなくて、今回の場合であれば62.5kHzの整数倍であればいい)。

 STM32G4のFDCANを使えば、かなりシンプルな方法で広い範囲に正確な時刻を共有することができる。

*

 CAN/CAN FDは車載の安全要求の厳しい環境で使う前提だからか、STM32G4のFDCANは、他のSTM32のペリフェラルとはだいぶ雰囲気が違う。ビットフィールドが中途半端な位置に配置されていたり、あるいはリファレンスマニュアルで一切解説されていないビットが定義されていたり、いろいろと謎い。外部のガイドラインみたいなものに従って実装してるのかな?

0 件のコメント:

コメントを投稿