RaspberryPiとMCP2515でCAN通信をやってみる

# やった事
・2台のラズパイの間で、CAN通信を行う。
　動画は2台のラズパイがCAN通信しているターミナルをPCからにVNC接続して表示している状態です。
<iframe width="560" height="315" src="https://www.youtube.com/embed/yhf1WAStsGA" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

・受信側のターミナルの様子
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483299/db28a843-1cc4-eed6-868f-7760f23ffe8f.png width=440>


# 記事内項目一覧
   * [ハードウエア編](#ハードウエア編)
   * [ソフトウエア編](#ソフトウエア編)
   * [動作確認](#動作確認)
   * [Raspi間通信](#Raspi間通信)
   * [連続してデータを送る](#連続してデータを送る)
   * [エラー対応](#エラー対応)
   * [参考リンク](#参考リンク)

# ハードウエア編
### 準備するモノ
　・Raspberry-pi：2台　(電源,モニター等)
　・MCP2515 CANバスモジュールTJA1050レシーバSPIモジュール (amazon等で入手可能)
　・ケーブル
　・ジャンパーピン(CANバスモジュール終端抵抗用)

<iframe style="width:120px;height:240px;" marginwidth="0" marginheight="0" scrolling="no" frameborder="0" src="https://rcm-fe.amazon-adsystem.com/e/cm?ref=qf_sp_asin_til&t=kiyokiyo012-22&m=amazon&o=9&p=8&l=as1&IS1=1&detail=1&asins=B07F68GHBJ&linkId=ef4f79df214a6994753d987833323d7b&bc1=ffffff&amp;lt1=_top&fc1=333333&lc1=0066c0&bg1=ffffff&f=ifr">
</iframe>

### ハードウエアセッティング
　・MCP2515にジャンパーピンをつけて短絡。終端抵抗ONになる。
　 　※製品によってはOFFになるものもあるようなので、手持ちのデバイスに合わせて設定。
　・配線
　　※MCP2521の間はそれぞれのHとLを接続

| Raspberry-pi | 配線 | MCP2515 |
|:-----------|------------:|:------------:|
|02 5V          | <-> |VCC 5V電源
|06 GND         | <-> |GND
|24 GPIO8  | <-> |CS
|21 GPIO9  | <-> |MISO
|19 GPIO10 | <-> |MOSI
|23 GPIO11 | <-> |SCK
|22 GPIO25      | <-> |INT

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483299/95d6e71a-509e-1f55-2f5c-624c9c027235.jpeg width=320> <img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483299/cb24d85a-05a6-2feb-963c-2a3dcf021e57.png width=320>

# ソフトウエア編

### 環境セッティング
・CANコントローラとの接続設定
　CANコントローラ(MCP2515)と、RaspberryPiの接続はSPI通信で行います。
  そのため最初にSPIを有効にする必要があります。

```php:tarminalに入力
sudo vim /boot/config.txt
```

SPIを有効にしたら、エディタで/boot/config.txtを開き、次の3行を加えます。

```php:config.txtへの追加内容
dtparam=spi=on
dtoverlay=mcp2515-can0,oscillator=16000000,interrupt=25
dtoverlay=spi-bcm2835-overlay
```

<details><summary>注意事項</summary>
注意事項１
過去の記述例を見ると「dtoverlay=mcp2515-can0-overlay」等と、”-overlay”が最後についている例が多いですが、現在は付けなくなったようです。
× dtoverlay=mcp2515-can0-overlay,oscillator=8000000,interrupt=25
○ dtoverlay=mcp2515-can0,oscillator=8000000,interrupt=25
注意事項２
「oscillator=8000000」は、CANモジュールの発振子に合わせてください。私が使ったものは8MHzでした。
注意事項３
「interrupt=25」は、配線に合わせてください。ここでは GPIO 25 をモジュールの INT に繋いだため、25としてあります。
</details>

設定を有効にするために、一度再起動します。
こうすることで、RaspberryPiのSPI端子をMCP2515との接続に割り当てることができます。

### CAN Utilsのインストール
CAN通信を確認するためのソフトcan utilsをダウンロードして、実際にCAN通信を確認します。
以下のコマンドを実行し、ソフトをダンロードして、インストールします。

```php:tarminalに入力
sudo apt-get install can-utils

```

<details><summary>参考:ソースコードからbuild & install</summary>
<div>

```
$ git clone https://github.com/linux-can/can-utils.git
$ cd can-utils
$ make
$ sudo make install
```
</div>
</details>

# 動作確認
まずはraspiとMCP2515の接続確認。(MCP2515のCAN_H,CAN_Lは未接続)
下記を順次入力していく。参考に入力時のレスポンスの例も記載

・接続確認。レスポンスがなければ接続不良の可能性あり。

```php:tarminalに入力
dmesg | grep mcp251x
```

このようなレスポンスがあれば接続成功

```php:tarminalのレスポンス
[    9.022975] mcp251x spi0.0 can0: MCP2515 successfully initialized.

```

・通信確認
CANのビットレートは500kbpsに設定します。
「loopback on」では、実際にCANバスに信号を出さず、CANコントローラである「MCP2515」のみで操作が完結しています。
can0のNICをUp後に、ifconfigでcan0が認識できている事を確認します。

```php:tarminalに入力
sudo ip link set can0 type can bitrate 500000 loopback on
sudo ip link set can0 up
sudo ifconfig
```


補足：多量のデータを送信する場合は、txqueuelenを増やしておかないと、エラーになります。

```
sudo ifconfig can0 txqueuelen 1000
```

受信の準備

```php:tarminal_1に入力
candump can0
```

送信
もう1つターミナルを立ち上げて以下のコマンドを実行。

```php:tarminal_2に入力
cansend can0 123#1122334455667788
```

すると1つめのターミナルに送信した内容が表示される。
以上でraspiとMCP2515の通信を確立できた。

# Raspi間通信
上記のraspiとMCP2515を2セット準備します。(両方とも前述のセットアップを完了させる)
またMCP2515のCAN_L同士とCAN_H同士を結線する。(終端抵抗もONにする)

1台目のラズパイで以下のコマンドを実行し、受信の準備をします。
(もう一台が送信するまでは、なにも表示されません。)
※前述でcan upを実施している場合はエラーがでるので
一度`sudo ip link set can0 down`を実行してから実施する。

```php:tarminalに入力
sudo ip link set can0 type can bitrate 500000
sudo ip link set can0 up
#sudo ifconfig can0 でも動作する

```

1台目のraspi

```php:raspi_1　受信側
candump can0
```

もう1台のraspiで以下のコマンドを実行します。

```php:raspi_2　送信側
cansend can0 123#1122334455667788
```

dumpしたコンソールに下記が表示されたら通信ができています。

```php:raspi_1　受信側
pi@raspberrypi:~ $ candump can0
  can0  123   [8]  11 22 33 44 55 66 77 88
  can0  123   [8]  11 22 33 44 55 66 77 88
  can0  123   [8]  11 22 33 44 55 66 77 88
  can0  123   [8]  11 22 33 44 55 66 77 88
```

# 連続してデータを送る

```php:raspi_can.sh
#!/bin/bash
val=0
id=100
while true; do
  data=`printf '%.16x\n' ${val}`
  #echo $data
  echo $id"#"$data
  cansend can0 $id"#"$data
  #echo $((val++))
  val=$(( $val+1 ))
  sleep 0.2
done
```

```php:raspi_can.shのあるディレクトリで実行
bash raspi_can.sh
```
・受信側の表示
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483299/db28a843-1cc4-eed6-868f-7760f23ffe8f.png width=540>

これを応用していけばCANデバイスを操れるようになる(はず)。

# エラー対応
candumpやcansendが動かない場合
can0デバイスがdownしている可能性があるため、以下のコマンドを実行してください。

```
sudo ifconfig can0 up
```

逆にcan0デバイスの機能を無効化したい場合は、以下のコマンドを実行します。

```
sudo ifconfig can0 down
```


# 参考リンク
・トランジスタ技術 2019年1月号
・[Raspberry PiでCANを使う](http://nopnop2002.webcrow.jp/CAN/CAN-RaspberryPi.html)
・[OBD2(CAN)で自動車と通信(ソフト編)](http://make.bcde.jp/raspberry-pi/obd2can%E3%81%A7%E8%87%AA%E5%8B%95%E8%BB%8A%E3%81%A8%E9%80%9A%E4%BF%A1%E3%82%BD%E3%83%95%E3%83%88%E7%B7%A8/)
・[RaspberryPiとArduinoをCAN通信させた](https://yoshichi9.hatenablog.com/entry/2017/09/05/014909)
・[Raspberry Pi で CAN通信（準備）](http://www.kirurobo.com/2017/12/raspberry-pi-can.html)
・[Raspberry Pi と MCP2515 で CAN 通信](https://rabbit-note.com/2015/09/13/raspberry-pi-mcp2515-can/)
・[Raspberry Pi CAN通信 (MCP2515 TJA1050 CAN Bus Module)](https://qiita.com/mt08/items/535ab4690eecbcf5375d)