MCP2517FDでCAN FD通信を行う

# 目的
**CAN FDで送受信してみたい**。
CAN FDに対応しているマイコンはRH850くらいしか知らないが、車載向けなので個人で入手は難しい(多分)。
そこで **MCP2517FD** という外付けのCANコントローラを使用した。

CAN FDはCANの拡張である。よってCANの知識が必要。
・[猿でも分かるCANプロトコルの基本](https://qiita.com/mindwood/items/93d5c2dc0e340cc20769)
・[CAN通信いろいろ](https://qiita.com/Banayad/items/cf24b774a83ef8a22ca0)
・[CANについて](https://qiita.com/fattolys/items/e8f8081d3cb42d7da0f6)
・[CAN(controller area network)](https://qiita.com/kaizen_nagoya/items/e8c0bd7bfb2827b83de9)

# CAN FDの概要
既存のCANではビットレートもデータ長も足りていないため、両方を改善したのが CAN FD である。

* CAN IDなどは通常のCANと同様のビットレート
* データ部は**最大512bit(64byte)**に拡張
* **データ部だけビットレートを上げる**ことができる（Flexible DataRate → FD）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154323/16bbf5cd-3218-e82b-3ba6-47026dea7a47.png)

[はじめてのCAN/CAN FD](https://assets.vector.com/cms/content/know-how/VJ/PDF/For_Beginners_CAN_CANFD.pdf)
[次世代の車載ネットワーク「CAN FD」とは](https://monoist.atmarkit.co.jp/mn/articles/1712/28/news004.html)
[CAN FD(CAN with Flexible Data Rate)とは](https://sunnygiken.jp/product/can-fd-tool/about_canfd/)

# ハード構成
自分で送信したCAN FDのフレームを自分で受信する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154323/8ac1970e-a328-63c0-6297-b50206c6480f.png)

|部品            | 購入元 | マニュアル | 補足資料 |
|----------------|------------------|------------------|---|
|CANコントローラ  | [MCP2517FD-H/SL](https://www.marutsu.co.jp/pc/i/26939698/) | [20005688B_JP.pdf](http://ww1.microchip.com/downloads/jp/DeviceDoc/20005688B_JP.pdf) |[20005678B_JP.pdf](http://ww1.microchip.com/downloads/jp/DeviceDoc/20005678B_JP.pdf)|
|CANトランシーバ  | [MCP2562FD-E/P](https://www.marutsu.co.jp/pc/i/896635/) | [20005284A_JP.pdf](http://ww1.microchip.com/downloads/jp/DeviceDoc/20005284A_JP.pdf) |
|オシレータ      |[セラミック発振子 40MHz](http://akizukidenshi.com/catalog/g/gP-02886/)|
|終端抵抗        | 120Ω |
|パスコン        | [セラミックコンデンサ 0.1μF](http://akizukidenshi.com/catalog/g/gP-00090/) ||

## クロック生成
40MHz/20MHz/4MHz の外付け水晶振動子、セラミックレゾネータ、外部クロックが使える。
4MHzの場合PLLで10逓倍の40MHzにできる。特に理由がなければ40MHzか4MHzがよいだろう。

||最高ビットレート|SPI最高通信速度|
|---|---|---|
|40MHz or 4MHz(x10)|8.0Mbps|20.0Mbps|
|20MHz|6.7Mbps|10.0Mbps|

**以下が使えることを確認済み**
・[セラミック発振子 コンデンサー内蔵タイプ 40MHz](http://akizukidenshi.com/catalog/g/gP-02886/)
・[セラミック発振子 コンデンサー内蔵タイプ 20MHz](http://akizukidenshi.com/catalog/g/gP-08696/)
・[水晶発振子 20MHz](http://akizukidenshi.com/catalog/g/gP-08673/) と セラミックコンデンサ(20pFくらい) x 2個
・[水晶発振子  4MHz](http://akizukidenshi.com/catalog/g/gP-08665/) と セラミックコンデンサ(20pFくらい) x 2個

# MCP2517FDの制御
MCP2517FDのデータシートは以下の2つがある。
[20005688B_JP.pdf : ハードやレジスタの仕様](http://ww1.microchip.com/downloads/jp/DeviceDoc/20005688B_JP.pdf)
[20005678B_JP.pdf : 補足資料](http://ww1.microchip.com/downloads/jp/DeviceDoc/20005678B_JP.pdf) 

## SPIインターフェース
使ったコマンドは「Reset」「Read」「Write」の3つ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154323/07d7c688-5347-ffb6-558e-da9582334720.png)

SPIのクロックは**SYSCLKの半分まで**上げることができる。4MHzの水晶を使う場合のみ注意が必要で、
**リセットからPLLのONまでの間は4MHz/2の2MHzが上限**である。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154323/b0a76963-94e6-8d68-3e41-23d63474c3f2.png)
上記はリセットコマンド発行時のSPIとCLKOの波形である。
マニュアルにはnCSのHIGHでリセットと書いてあるが、コマンドを書き込んだ時点でリセットがかかって
CLKODIVが10分周に戻ってるように見える。。。

## 初期設定
定格ビットレート: 500kbps
データ ビットレート: 2Mbps
TEF & TXQ: 使わないので無効化
FIFO1: 受信用 
FIFO2: 送信用
フィルタ0: FIFO1に振り分け、全CAN IDを受け入れ
トランスミッタ遅延補償: 自動設定、TDCO=DBRP×DTSEG1
CRCとRAMのECCチェック: 使用しない

|レジスタ|設定値|説明|
|----------|----|----|
|OSC       |0x00000001<br>0x00000000|オシレータが4MHz: PLL=1<br>オシレータが4MHz以外: PLL=0|
|C1NBTCFG  |0x003E0F0F<br>0x00160F0F|SYSCLKが40MHz: BRP=1, TSEG1=63, TSEG2=16, SJW=16<br>SYSCLKが20MHz: BRP=1, TSEG1=23, TSEG2=16, SJW=16|
|C1DBTCFG  |0x000E0303<br>0x00060101|SYSCLKが40MHz: BRP=1, TSEG1=15, TSEG2= 4, SJW= 4<br>SYSCLKが20MHz: BRP=1, TSEG1= 7, TSEG2= 2, SJW= 2|
|C1TDC     |0x00020F00<br>0x00020700|SYSCLKが40MHz: TDCMOD=2, TDCO=15, TDCV=0<br>SYSCLKが20MHz: TDCMOD=2, TDCO=7, TDCV=0|
|C1FIFOCON1|0xE7600400|FIFO1: ペイロード=64byte, FIFO=8段, 受信FIFO|
|C1FLTCON0 |0x00000081|Filter0=許可, Filter0をFIFO1に振り分け|
|C1FIFOCON2|0xE3600480|FIFO2: ペイロード=64byte, FIFO=4段, 送信FIFO|
|C1CON     |0x00000760|REQOP=000, TXQEN=0, STEF=0|

### ビットレート
C1NBTCFG・C1DBTCFG に指定する BRPとTSEG1、TSEG2の値からビットレートが決まる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154323/0acd2066-efb3-9266-53c1-8d542ec46dfb.png)
上記は SYSCLK 40MHz, BRP=1, TSEG1=15, TSEG2=4 の例。
(SYSCLK / BRP) / (SYNC + TSEG1 + TSEG2) = (40MHz / 1) / (1 + 15 + 4) = 2Mbps
マニュアルにはBRPをなるべく小さくとあるので1にした。
SJWはなるべく大きくと記載されているのでTSEG2と同じ値にした。
SJWに指定できる値は制限がある： SJW ≤ min(DPHSEG1, DPHSEG2)。

マニュアルではTSEG1とTSEG2の値の割合をTSEG2までのTQが80%になるように調整している。
(SYNC+TSEG1) / (SYNC+TSEG1+TSEG2) = 80%

### CAN IDフィルタ
CiFLTOBJm と CiMASKm で受信対象のCAN IDをフィルタリングできる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154323/4c86585e-0ce3-59e3-440e-1856d52a2742.png)
比較はビット単位で行われ CiMASKm が0のビットは常に受け入れる。
CiMASKm が1のビットは CAN ID と CiFLTOBJm のビットが比較され、一致すると受け入れられる。

0x4** のCAN IDを受け入れるなら CiMASKm を 0x700 に CiFLTOBJm を 0x400 にする。
全CAN IDを受け入れるなら CiMASKm を全て0にすればよい。

## メッセージ送信
1. C1FIFOSTA2 を読み出し、FIFOに空きがあることを確認(TFNRFNIF==1)
1. C1FIFOUA2 を読み出し、送信FIFOのアドレスを取得
2. 0x400 + アドレス + 0 にCAN IDを書き込み
2. 0x400 + アドレス + 4 にDLCなどを書き込み  
2. 0x400 + アドレス + 8 以降に送信データを書き込み
2. C1FIFOCON2 のTXREQとUINCを1にして書き込み(転送を開始し、FIFOを進める)

## メッセージ受信
1. C1FIFOSTA1 を読み出し、FIFOにデータがあることを確認(TFNRFNIF==1)
1. C1FIFOUA1 を読み出し、受信FIFOのアドレスを取得
2. 0x400 + アドレス + 0 からCAN IDを読み出し
3. 0x400 + アドレス + 4 からDLCなどを読み出し
4. 0x400 + アドレス + 8 以降からDLC分だけデータを読み出し
5. C1FIFOCON1 のUINCを1にして書き込み(読み出し済みのバッファを空ける)

# 動作結果
期待通りデータ部のbpsが上がっている。

Saleae のロジックアナライザで波形を取得した。
CAN FDには対応していないが、[プラグイン](https://github.com/suteaka78/Saleae_CAN-FD_Analyser) を追加すれば解析できるようになる。
VisualStudio2017でビルドしたものは [こちら](https://github.com/suteaka78/Saleae_CAN-FD_Analyser/blob/master/CANFD.dll)。CANFD.dllをどこか適当な場所に置き、
Options → Preferences → Developer にCANFD.dllを置いたフォルダのパスを指定し、ソフトを再起動する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154323/a3de4265-47fd-ce0d-7db2-184766e2f729.png)
・CAN ID             ：11bit 0x3FB
・DLC                ：4
・Data               ：F7 00 AA F7
・フレームフォーマット ：FDF=1
・ビットレート スイッチ：BRS=1

## 64byteの転送にかかった実測時間
SOF から ITM までの時間を計測した結果。
データによってはビットスタッフィングでフレーム全体の時間が延びるため、
最短時間はデータ部を0xAAで埋めてスタッフビットが入らないように計測し、
最長時間はデータ部を0x00で埋めてなるべくスタッフビットが入るようにした。

|フォーマット|ビットレート|データ長|転送時間|CANとの速度差|
|-------|---------------|---|-------|---|
|CAN    | 500kbps       |8|**219us ~ 250us**|-|
|CAN    | 500kbps       |64|**1752us ~ 2000us** (8byte x 8回)|-|
|CAN FD | 500kbps+2Mbps |64|**331us ~ 386us**|5倍|
|CAN FD | 500kbps+5Mbps |64|**166us ~ 190us**|10倍|
|CAN FD | 500kbps+8Mbps |64|**124us ~ 141us**|14倍|


計測した結果 **CAN FD のほうが2Mbpsでも5倍、5Mbpsなら10倍速い**。 
車載の開発でCANリプロ（ソフトウェア更新）をすると、CANの遅さがボトルネックとなって
大変時間かかるので、もっとCAN FDを採用してほしいと思う。