CAN ビットタイミングは CAN を使う上で必須の設定で、パラメタは CAN の規格で決まっています。標準化されているので、どの CAN コントローラにも同様の設定項目があります。どのデバイスのデータシートにも簡単な説明と設定方法は書かれていますが、設定する項目数が多く計算もごちゃごちゃしており、また、各パラメタの計算方法は書かれていなかったり別ドキュメントだったりして、確信をもって設定するのに手こずる部分です。そのわり通信障害が出たりすると詳しく知らなくてはいけない部分です。どんな理屈でビットタイミングを計算するのかの理解の一助になればとこのページを書きました。

このページは CAN FD の規格を元にしています。CAN 規格には CAN 2.0 (いわゆる Classic CAN) とそれより新しい CAN FD (CAN with Flexible Data-Rate) がありますが CAN 2.0 は CAN FD のサブセットなのでそれ向けの情報を探している人は FD の部分は飛ばして読んでください。

このページでの CAN 規格の参照元は Bosch から出されている CAN with Flexible Data-Rate Specification Version1.0 という仕様書ですが、厳密にはこれは正式な CAN 規格ではなく ISO から発行されている ISO 11898-1 が正式なものです。ISO の規格はちょっと入手の敷居が高くて見ていませんが、色々なデータシートの内容と矛盾していないので十分規格に近いと考えています。

ビットタイミングとは

CAN ビットタイミングは、通信のビットレートと信号読み取りのタイミングを決めるものです。CAN 通信の 1 ビット分の時間をセグメントに分け、各セグメントの大きさを指定することにより設定します。

以下の図は CAN Bit Time を構成するセグメントの説明です。Bit Time とは CAN 1 ビット分の時間です。

出典:Bosch CAN with Flexible Data-Rate Specification Version1.0

このように、1 ビット分の時間を複数のセグメントに分割して設定を行います。分割を行う理由は主に二点です

  • CAN 通信はクロック信号を伴わないシリアル通信で、データの読み取りを行う時点 (Sample Point) を決めないといけない
  • CAN バス上で送る信号には遅延が生じるので遅延量を考慮に入れて読み取りタイミングを決めないといけない

このことを意識しながら Bit Time の各セグメントを見て行くと理解しやすいかもしれません。Bosch の CAN 規格が元ネタなので文章が機械翻訳調になってしまって悪しからず。

Synchronization Segment (SYNC_SEG) バス上のノードの同期をとるのにつかわれます。信号のエッジはこのセグメントに収まることを想定しています。

Propagation Time Segment (PROP_SEG) 物理的な遅延時間を補償するために使われます。物理的な遅延は、トランシーバの遅延と電気の伝送速度に起因します。この区間は信号の内容に信頼性がないので読み取りを行いません。

Phase Buffer Segment1 (PASE_SEG1)
Phase Buffer Segment12(PASE_SEG2)
信号を読み取り可のセグメントです。これらのセグメントの境目に Sample Point を置きます。読み取り精度を高めるために、セグメントを伸縮して Sample Point の位置を調整します。

Sample Point Sample Point の時点でバス上のレベルを計測してビット値を決めます。Sample Point は PHASE_SEG1 の終わりに置きます。

実際のデバイスへの設定では、これらの値を直接使わず PROP_SEG と PHASE_SEG1 を統合した TSEG1 と PHASE_SEG2 と同等の TSEG2 という値を使います。何故かどのデバイスも同様です。

出典:MCP25XXFD Reference Manual

CAN FD の場合データ部のビットレートを変えることができるため、データ部は別個にビットタイミングを設定します。基本部分の設定は Nominal Bit Timing と呼ばれ、データ部は Data Bit Timing と呼ばれます。

ビットタイミング値の単位

ビットタイミング値は時間を表す値ですが、単位は秒とかではなく Time Quanta という単位が使われます。1 Time Quata は、CAN 制御モジュールの1クロック分に要する時間です 。要するに、ビットタイミング値はクロック数で指定されます。この辺仕様書とかデータシートなどを読むと厳密さのために回りくどい説明になっていますが、考え方は単純です。CAN 仕様では、CAN 制御モジュールには システムクロックにプリスケーラをかけたクロックが使われるとされているので、制御モジュールのクロック周波数は fclk = fsys / brp となります。brp は Bit Rate Prescaler の略でプリスケーラの値です。

ビットタイミングの計算方法 (MCP25XXFD流)

ビットタイミングの各パラメタは、正常に動きさえすれば何でも良く、計算法は標準化されていません。したがって計算する方法はいくつかあるようです。MCP25XXFD リファレンスマニュアルに書かれている方法がわかりやすかったので、このページではそれを踏襲します。

まずはビットレートを決める

CAN のビットタイミングの説明を読んだとき最初、わかりづらいなー、と思ったのですが、その理由の一つが、パラメタの中にビットレートがないことです。次の節で詳しく触れますが CAN のビットレートは各種パラメタを総合すると決まる値で、直接指定するパラメタがありません。

でも、ビットタイミング計算はビットレートから始めるのが自然です。どうやってビットレートを決めるかというと Bit Time を決めるところから始めます。Bit Time は CAN 1 ビット分の時間ですから以下のように計算できます

BTs=1BR

BR はビットレートです。時間は Time Quanta の単位で表すので、上の時間を Time Quanta に換算する必要があります。1 TQ は 1 クロックの時間ですから、

TQ = BRPxTSYSCLK = BRP FSYSCLK

BTs は秒単位の Bit Time、BRP は Bit Rate Prescaler の略です。

ここから、TQ 単位での Bit Time Tbit が以下のように得られます

TBIT=BTsTQ

この Tbit がビットレートを決めることになります。Tbit の意味は、CAN 信号 1 ビットに要するクロック数です。

CAN コントローラに指定するパラメタ

前述の通り、Tbit は以下のように各セグメントから構成されています。

TBIT = SYNC_SEG+PROP_SEG+PHASE_SEG1+PHASE_SEG1 = SYNC_SEG+TSEG1+TSEG2

このうち SYNC_SEG は固定長で 1 なので、Tbit 長は TSEG1 TSEG2 によって決まります。この二つの値をデバイスに与えてビットレートと Sample Point を決定します。

また、通信が不安定な際デバイスは Sample Point を動かして同期を取ろうと試みます。許容される移動幅を Synchronization Jump Width (SJW) と呼び、この値もデバイスに設定します。 SJW は PHASE_SEG1 と PHASE_SEG2 のうち小さい方以下の値を選びます。下図を見ると理解しやすいかもしれません。PROP_SEG 区間は信号の信頼性が低いため読み取りは避けるべき、そういうわけで、Sample Point の調整は PHASE SEG の中で行うべき、ということです。

たいていのデバイスは TSEG1, TSEG2, SJW を指定することによりタイミングを設定します。

各パラメタを計算する

MCP25XXFD 流では、以下の順番でパラメタを決めて行きます。

  • まず目標とする Sample Point を決める
  • Sample Point から TSEG1 と TSEG2 を求める
  • PROP_SEG 長を計算する
  • SJW を決める

Sample Point は Tbit の 70% から 80% ぐらいが良いといわれています。Sample Point を求める式は以下の通り

SP = 1+TSEG1 TBIT x 100

Sample Point をある値に決めて TSEG1 を求めるには

TSEG1 = SP100 x TBIT 1

TSEG2 を求めるには

TSEG2 = TBIT TSEG1 1

PROP_SEG は、トランシーバの遅延時間 Tx propagation delay, Rx propagation delay (データシートに最悪値が書かれています)と、電気の伝搬速度からくる Tbus から求めます。Tbus は通常光の速度の 2/3 で計算します。これはおおよそ 5 ns/m です。秒の単位の伝搬遅延は以下の計算式で求めます。

TPROP = 2 x ( Ttx + Trx + 5 x 10-9 x L )

ここで L はバスの長さで単位は m です。PROP_SEG は TQ が単位なので以下のように計算します。

PROP_SEG = ceil ( TPROP TQ )

ここから SJW は以下のように計算

SJW = min ( TSEG1PROP_SEG , TSEG2 )

ここまででタイミングの設定に必要なパラメタが得られました。この計算を Nominal Bit Time と Data Bit Time の両方について行います。

Data Bit Timing 設定はこれだけでは終わらない – Propagation Delay Compensation

ここまででも十分に煩雑なのですが、CAN FD を高いビットレートで使う場合これだけでは終わりません。これまでの計算で求めた TSEG1、TSEG2、SJW を Nominal Bit Time と Data Bit Time に対して設定することは必要ですが、FD フレームではこれだけでは通信できないのです。

どういうことかというと、通信の伝搬遅延が問題となるのです。高いビットレート PROP_SEG を計算すると Bit Time より大きくなってしまいます。つまり Sample Point をどこに置いても読み取りデータは信頼できないということ。

下の図は実際に Nominal Bit Rate を 1 Mbps、Data Bit Rate を 6 Mbps に設定したときの Nominal 部から Data 部に切り替わる場所をキャプチャしたものです。上の波形が Tx、下の波形が Rx です。遅延による両者のずれが大きく、CAN では自分が送った信号を Rx でモニタしてデータに食い違いがないか見ていますが食い違いが生じてエラーになってしまいます。

この遅延に対応するためにどのデバイスにも Transceiver Delay Compensation (伝送遅延補償) という仕組みがついています。これは、以下の図のように、伝送遅延を実際に計測してその遅延をもとに Sample Point を決めるものです。

出典:STMicro AN5348 Introduction to FD CAN

実際の Sample Point (通常 Secondary Sample Point と呼ばれます) は、以下のように決められます

SSP = TDCO + TDELAY

ここで、TDCO は Transmitter Delay Compensation Offset の略で、あらかじめ設定しておく基準点、Tdelay は測定した伝送遅延です。TDCO にはもともとの Sample Point を使えばとりあえずうまく通信するようです。それには TDCO は以下のように計算します

TDCO = DBRP x DTSEG1

DBRP はデータ部のクロックプリスケーラ値、DTSEG1 はデータ部の TSEG1 です。

実際の計算は…

以上の計算を毎度手でやっていると大変に面倒ですし計算間違いもしやすいです。embassy-rs では HAL に計算機能が含まれていて、ユーザは計算方法を知らなくても使えるようになっています。これに触発されて開発中のライブラリにも自動計算機能を加えました。以下はそれを JavaScript に移植したものです。今のところ STM32C092KCT を使って 6 Mbps まで試しましたがうまく設定できるようです。8 Mbps ではまだ成功していないのですが実験系のクロックにも問題があるのでそこも含めて検討を続けているところです。

CAN / CAN-FD ビットタイミング計算機

Nominal Phase

Data Phase


まとめ

以上、CAN FD のビットタイミングの設定方法の概要でした。記事の内容は大体各メーカのリファレンスマニュアルにも書かれていますが読んでいるとわかりづらかったり解釈に迷うところが多くあったので、自分の持った疑問についてはできるだけ明らかになるように努めました。

参考資料

CAN with Flexible Data-Rate Specification Version 1.0 by Bosch

MCP25XXFD Family Reference Manual by Microchip

AN5348 Application Note - Introduction to FDCAN peripherals for STM32 MCUs by STMicro

embassy by embassy-rs

AN1798 Application Note - CAN Bit Timing Requirements by NXP