CANは、Controller Area Networkの略で、シリアル通信の一種です。マイコンだと色々なシリアル通信(I2C, SPI, UART)がありますが、CANはあまりメジャーではないですね。ただ、一方で自動車業界では、超メジャーな通信手段になってます。
車とかバイクとかの故障診断(OBDⅡ)の情報はCAN信号経由ででてくるので、理解しておくと、バイクが好きな自分としては、いいことあるかな?とか思って、ちょっとCANについて調べてみました。
説明は標準フレーム+High Speed CANに限定して書いてます。
参考した文献やサイトは以下の通りです。
CQ出版社 車載ネットワークシステム徹底解説 佐藤道夫著
MICROCHIP Understanding Microchip’s CAN Module Bit Timing
一応下調べを十分にしてからまとめてるつもりですが、くそ素人なので、解釈が間違ってるかもしれません
それでわ、やっていきましょう。
CANって、どうやってつなげんの?
CAN-HighとCAN-Lowの2本の線がCANの信号線で、CAN用のデバイスたちをこんな感じでつなげるよ。
絵の中で、NODEと書いてあるのが、デバイス。この場合3個つないでる。ぶら下がるデバイスをノードっていうのが、通らしいよ。
ノード間で主従があるの?
I2Cとかは、デバイス間でマスター・スレーブの設定があるけど、CANでは、みんな平等にあつかうよ。
High-Lowの間にある120Ωってなに?
終端抵抗、ターミネータともいうよ。信号の反射を防ぐためのバッファの役目があって、CANラインの両端に120Ωの抵抗を二個つけとくよ。
どんな信号がくるの?
シリアル信号で0/1を表すのに、CANだと下のようにCAN-HとCAN-Lの差動電圧で表現するよ。
なんでそんなことする?って一般的なデジタル信号だと絵の右上の状態みたいなノイズがのると、誤判定してしまうけど、2線間の電圧差をみてれば、同じようなノイズがのってれば、差は同じでしょって理屈で、ノイズに強いからだよ。
ドミナントとリセッシブ?
信号には、ドミナント(high側が3.5V, low側が1.5V)、リセッシブ(high側とlow側も同じ2.5V)の二つの状態があるよ、ドミナントが論理値で0, リセッシブが1になるよ。
なんで信号を送るときはCANの状態がドミナントになったりリセッシブになったりして、切り替わりながら、0/1の信号を送るよ。
ちなみに各ノードが同時に信号を出すシチュエーションがたまにあるけど、そういうときは、ドミナントが優先されるよ。
こんな感じで、Nodeによっては、自分が出したい信号が実際のCAN信号に反映されないことがままあるよ。意外にこの仕組みが重要だったりするよ。
どんぐらいのはやさでデータ遅れるの?
マックス1Mbpsだよ。
どんな感じでデータが流れるの?
各ノードはフレームという単位で情報のやりとりをするよ。フレームも種類があるけど、とりあえず他はほっといて、データフレームというのが一番重要だよ。
データフレームには最大で8バイトのデータがのっかっていて、CANバスに送信されるよ。
絵のように誰でもデータフレームを送信することができるよ。そして誰でも見ることができるよ。
マルチマスタ、マルチキャスト?
誰でもメッセージを送信できて、送信されたメッセージをみんなが受信できて、それに対して、なんかのアクションを起こせるっていう仕組みをカッコつけていうと、それぞれマルチマスタ、マルチキャストプロトコルっていうよ。
データにはIDがついている
データフレームには送信したいデータが保存されているほかにも、IDというのがついてるよ。メッセージの名前みたいなもんだよ。標準フォーマットだと11bit、つまり0x0~0x7FFまでのIDを割り当てることができるよ。
どのタイミングでデータをだすの?
それぞれノードはCANバスの信号を監視していて、バスがアイドル状態になったと思ったら、送信したいデータがあるなら、送信を始めるよ。
送信したいデバイスがいっぱいあったら、フルーツバスケットみたいに空いているバスに一斉に送信みたいなシチュエーションにもなるよ。
どうやって、衝突を防ぐの?
通信調停(アービトレーション)というのを送信するメッセージのIDを使ってやるよ。
例えば、Node1とNode2が同じタイミングでデータフレームを出したときは、データフレームの初めのほうについたメッセージのIDの送信中に自分のIDのBitとCANバスのロジックレベルを比較して、一致しなければそのノードの送信を取りやめるよ。
ちなみに、メッセージはかならずSOFという最初の合図をドミナントでしてから、次にIDを送信していくよ。
CANバスはドミナント優先(ロジック ‘0’)なので、結果的には、IDが小さいほうのメッセージが優先されることになるよ。
ノード間で遅れがでたら大変じゃない?
たしかに、上のアービトレーション中に各ノードが同時に同じスロットの信号が出てこないと困りそうね。自分の送信したbitとCANバスのロジックレベルを比較して、自分のIDが優先されているか、そうじゃないかを判定するんだから、下のように1bit誰かが遅れてると、正確な比較ができなくて、困るよ。
Hard Synchronization
上の絵のような遅れが発生しないようにHard Synchronizationという同期機能があるよ。これは、CANバスがリセッシブからドミナントに切り替わるときに実施するよ。
バスに何も信号が流れないアイドル状態のときはバスのリセッシブになっている。そして、メッセージが送信されると、最初はSOFで、バスがドミナントになるよ。Hard シンクロはこの立下りのタイミングでやるらしいよ。
Hardシンクロはメッセージで一回だけ、SOFのタイミングで実行するだけ、他はしないよ。
これで、NodeBが信号を出しそこなうことがなくなったね。
ただ、これで問題解決かっていうと、そうでもなくて、同期信号が相手に届くまでに時間がかかったり、相手の応答が遅かったりすると、うまく信号が受け取れなくなったりするケースもあるらしいよ。
ビットタイミング
なので、1bitずつ確実に同期しましょうってことで、ビットタイミングという考えがあるよ。下の絵のように通信速度が決まると1bitの通信に必要な時間NBTが決まる。
1Mbpsだとすると1bitの通信時間は1usだよね、これを4つのセグメントに分割したものが、下の絵だよ。1bitの信号を実際に取得する箇所がsample pointで、各セグメントの幅をいい感じに調整して、↓の位置を変えて信号の遅れに対処するのが狙いみたい。
各セグメントの幅の調整には、TQという謎の値を使うよ。これは、CANのコントローラ扱える時間的解像度(扱える最小の時間)のこと。
CANのクロック周波数はマイコンでは分周比を変えられるようになっているから、実際には、分周後の周波数の1周期分が1TQになるよ。
例えば、クロック周波数が8MHz、分周比は1だとすると、1TQは、1/8000000 sec = 125 nsになるよ。またこの時、ボーレートが1Mbpsだとすると、1bitあたりの時間は1us=1000nsで、1bitは、8TQ分ってことになるね。
この8TQ分をPROP SEGに3TQ、PSEG1に2TQ、PSEG2に2TQとかして割り振っていき、サンプルポイントを調整してく訳。ちなみにSYNC=1TQで固定で決まってるよ
アービトレーション中の遅れをビットタイミングでどう調整するの?
アービトレーション中は、各ノードが好き勝手に一斉送信しだすので、当然、下の絵のように遅れが発生するよ。
アービトレーションは自分の送信した値と相手の値を比較しないことには、始まらないので、相手が遅れて、信号が来ないとこまるよ。
なので、遅れがあっても、PROP SEGの幅を調整して、信号の遅れの影響を吸収するようにするよ。
この絵で、NodeAはかわいそうだけど、PROPの長さ ≧ (NodeAからNodeBに信号を渡す時間B-A) + (NodeBからNodeAに信号を渡す時間A-B) になっていれば、PROPセグメント内でNodeBの信号を受け取れることになるはずだから、問題ないよ。
Re-Synchronization
もう一個同期の処理があるよ、それが再同期処理。Hardシンクロと同じようにリセッシブからドミナント切り替わるときに処理がはしるよ。ただ、Hardシンクロと違い、SOF時じゃなくても、信号が立ち下がるときに何回も呼ばれるよ。
これは再同期いらない。完璧バージョン。
これは、立下りのエッジがSYNCセグより遅れてきた場合、ズレ分の赤ブロックをPSEG1に足すよ。
これは、SYNCセグより前に立下りのエッジがきた場合、赤ブロックをPSEG2から引くよ。
実際に赤ブロックはコントローラがバスの立下りエッジからSYNCセグまでの時間をTQ値として、計測して、PSEG1とPSEG2を短くしたり、長くしたりして、同期状態を維持できるようにしているよ。
SJW
これは赤ブロックの最大値のことだよ。マイコンとかでは、設定パラメータになっているよ。SJW< 赤ブロックになったら、SJWの値でしか補正しないよ。
ずっと立ち下がらなかったら同期できないじゃん?
下が実際のCAN信号をオシロでみたやつだよ。なぜかデータフィールドはすべて0の信号を出しているのに、時々1になってるね。(ちょっと見にくいけど灰色の枠がそう)
これ、ビットスタッフィングというやつだよ。同じ信号が5連続つづいたら、一回逆の信号をはさむよ。これで、立下り信号を強制的にだして、同期できない状態がつづくのを回避するよ。
上の例だと0x00の書いてあるところがデータフィールドで、各データ8bitだから、1回~2回信号が立ち上がってる訳だよ。
だた、見てわかるように、EOF(後で出てくる)とバスアイドル時はビットスタッフィングはしないよ。
データフレームの詳細
詳しくはこんな感じ。
下の数字は各フィールドのビットサイズだよ。SOFとIDとデータフィールドは既にでてきたね。
RTR
データフレームのほかにもリモートフレームっていうフレームが実はあるのだけど、それを区別する識別子で、データフレームでは、常にドミナントになるよ。
コントロールフィールド
6bitのコントロールフィールドの内訳が下。今回、説明しているIDは11bitの名前がついてるけど、それでは足らんってひとは29bit長まで、拡張できるよ。IDEはその識別子で、ドミナントで11bit、リセッシブで29bit長使うって意味になるよ。
そして、予約bitを一個挟んで、DLC (データレングスコード)というのが続くよ。これは、この後にくるデータフィールドのデータサイズを指定するよ。
最大のサイズが8バイトなので、8バイト送りたいときは 0b1000(d3=1, d2=0, d1=0, d0=0)、4バイト送りたいときは0b0100(d3=0,d2=1,d1=0,d0=0)になるよ。
実際のデータだと下のピンク枠のとこだね。0x8になってるので、8バイトのデータがあとに続いてるよ。
CRC
CRCって、日本語だと巡回冗長検査っていうよ。いわゆるパリティビットとかチェックサムに似たような機能で、データに破損がないか確認するためのデータだよ。CANだけじゃなくて、色々なところで、使われてる一般的な手法らしいよ。
確かに、なにもないと、途中でなにがあっても気づかないよね。
送信ノードが自分の送るデータに紐づいた形で、CRCをつけて、送信するよ。受信側は、そのCRCからデータに問題がないかチェックするよ。
なぜ、そんなことができるの?
細かいことを書き出すと数学的になってしまうので、省略するよ。コンセプト的には、下のような感じで、受信した信号を割る数を決めておいて、割り切れれば、OK。割り切れないとダメみたいな感じで、判断するよ。
下が実際の例だよ。ID=0x499で8バイトの全部ゼロのデータを送るとCRCというのが0x0751というのがでたよ。
データを0x00->0xFFに変更したら、同じようにCRCも0x6FFCという数値になったよ。こうやって、送信するノードは自分のデータに合わせて、CRCを計算して、送信してるよ。
実際には、チェック対象のbit列を多項式(イラストの45に相当)に変換して、決められた生成多項式(イラストの7の値に相当)で除算して、CRCを計算してるよ。
上のイラストでは、割り算の7にあたるものが生成多項式というやつで、CANでは、CRC-15-CANというのを使うルールになってるよ。読んでみたけど、考えた人頭いいんだろうな感じがすごいでてたよ。
興味あったら、Wikiで巡回冗長検査で調べるとでてくるよ。
また、下の記事では、理論的なところを簡単に説明しているので、よかったら、参考にしてね。
CRCデリミタ
CRCの最後につける1bitだよ。リセッシブで固定。
ACK
ACKは、送信されたメッセージにたいして、受信ノードが聞いてるよっていう合図をドミナントで、だすとこだよ。送信ノードはここは、リセッシブで流しているので、これが下の絵のようにドミナントになるってことは、受信している誰かがいるってことになるよ。
ちなみにCRC同様にACKにもデリミタがあって、最後はリセッシブで終わるよ。
分かりにくいので、受信ノードがドミナントを返さなくなった時の状態も下にのせとくよ。全部リセッシブだね。これだとエラーになるよ。
EOF
終わりの合図。7bitのリセッシブ固定だよ。
エラーとかどういう内容で検知するの?
最後に出した図でACK ERRORという表示があったけど、コントローラは色々なエラーを検知して、それをカウントアップしてるよ。
・ビットモニタリングエラー
自分の出した信号がちゃんとバスのロジックに反映されてない時に検知するよ。当然、そうならないシチューエーション(調停中とかACKフィールド内)は除外するよ。
・ACKエラー
これは↑で説明したよ。
・CRCエラー
これも↑で説明したよ。
・フォームエラー
これは、例えばデータフレームなのにRTRがリセッシブになってたり、決められたルールどおりになってないじゃないか?こら!というエラーだよ。
・ビットスタッフィングエラー
ビットスタッフィングがちゃんとはいってないときに判定するエラーだよ。
警告、退場!
コントローラは↑で説明したエラーの回数をカウントアップしていって、一定回数以上で、警告。さらにこえると、バスオフといって、そのデバイスがCANバス上から退場させるよ。
マイコンによって、警告時の割り込みとかバスオフ後の処理のさせ方とか色々カスタマイズができるので、調べてみるといいかもね。
長くなっちゃったけど、以上だよ。分かりにくかったり、間違ってたらごめんね。
それでは、ハッピーCAN通信。
バイク弄りで路頭に迷っている者です。こちらの記事を拝見しましたが私には難し過ぎました。
バイクの純正ヘッドライトにcan Hiと Loの端子があります。社外品に交換したいのですがヘッドライトコネクターを外すとエラー警告が出てしまいます。can通信をキャンセルする方法は何かありますか?回答頂けると助かります。
分かりやすく書いたつもりなんですが、
文章力なくてすいません;
状況が正確に理解できていませんが。
警告でるというのは多分OBDのCANラインでエラーをはいてるからかと思いますが、
この時、ヘッドライト外して、出力端子が開放になって、ECUが断線判定したのか?
CAN通信が原因なのか?
状況を切り分けた方がよさそうです。
前者だったら、後付けのライトの負荷調整などで
いけそうですが、後者の場合は、
まずCANバスの信号をみて、ヘッドライトから
でてくる信号IDと中身を確認しといて、
これと同じ信号をマイコンか何かで送信してやる
必要がありますね。