Avance.Lab

技術紹介

ラズパイからI2Cポートを使ってCAN送信する方法

公開日:2024.02.09 更新日:2024.02.09

tag: CANRaspberry Pi車載

こんにちは、ソラです。

ラズパイもいろんなことができて便利ですね。
多くの機能を付けたいところですが、機器の組み合わせで、
「ポートが足りない」
「そもそもポートがない」
ということがありますよね?

そんなときは、変換基板を使用して違う機能のポートから対応することができます。
今回は、その一つとして、I2Cポートを使用して、CAN送信をしたいと思います。

構成

■機器構成

機器ラズパイ4B
変換基板  I2C CAN 変換ボードhttps://www.switch-science.com/products/7437
言語C言語

■CAN構成

CAN通信速度500kbps変換基板モジュールのデフォルト設定をそのまま使用します。
※変更したい場合は、仕様に基づき、アドレスと通信速度を送り、設定してください。
CANアダプタKvaser Leaf Light v2    
確認用PC(OS)   Windows10 64bit
確認用ツールCandy自社開発のCANアプリです。
※あとがきに、紹介ページのリンクを記載しておきます。

構成図

環境の構成を下記に示します。

ソースコード

ソースコードを記載します。

CAN送信データ(CANID、DLC、DATA、チェックサム)をバッファへセットします。
linuxのI2Cデバイスクラスを使用して、I2Cポートから送信します。
CAN送信データは、I2C CAN 変換モジュールの仕様により、16バイト分のデータで、
最後はチェックサムが必須になります。

【メイン関数】
CAN送信データの作成と送信を行います。

#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/i2c-dev.h>
#include <linux/i2c.h>

#define DEV_NAME = "/dev/i2c-1"

int8_t i2c_send(uint8_t dev_addr, uint8_t reg_addr, const uint8_t* data, uint16_t length);
int8_t makeCheckSum(int8_t *dta, int8_t len);

/*** メイン ***/
void main(void)
{
 int8_t ret;
 uint8_t send_data[16];
 
 // 送信データの作成
 send_data[0]  = 0;
 send_data[1]  = 0;
 send_data[2]  = 0;
 send_data[3]  = 0x80; // CANID
 
 send_data[4]  = 0;
 send_data[5]  = 0;
 send_data[6]  = 8;    // CANデータサイズ
 
 send_data[7]  = 0x11; // 送信データ1
 send_data[8]  = 0x22; // 送信データ2
 send_data[9]  = 0x33; // 送信データ3
 send_data[10] = 0x44; // 送信データ4
 send_data[11] = 0x55; // 送信データ5
 send_data[12] = 0x66; // 送信データ6
 send_data[13] = 0x77; // 送信データ7
 send_data[14] = 0x88; // 送信データ8
 
 send_data[15] = get_check_sum(send_data,15); // チェックサム
 
 // データ送信
 ret = i2c_send(0x25, 0x30, send_data, 16);
}

【データ送信関数】
送信したいデータをI2Cで送信します。

/*** I2Cスレーブデバイスにデータ送信 ***/
int8_t i2c_send(uint8_t dev_addr, uint8_t reg_addr, const uint8_t* data, uint16_t length) 
{
 // I2Cデバイスをオープンする
 int32_t fd = open(DEV_NAME, O_RDWR);
 if (fd == -1) 
 {
  return FALSE;
 }
 
 // I2C-Write用のバッファを準備する
 uint8_t* buffer = (uint8_t*)malloc(length + 1);
 if (buffer == NULL) 
 {
  close(fd);
  return FALSE;
 }
 
 buffer[0] = reg_addr;                   // 1バイト目にレジスタアドレスをセット
 memcpy(&buffer[1], send_data, length);  // 2バイト目以降にデータをセット
 
 // I2C-Writeメッセージを作成する
 struct i2c_msg message = { dev_addr, 0, length + 1, buffer };
 struct i2c_rdwr_ioctl_data ioctl_data = { &message, 1 };
 
 // I2C-Writeを行う
 if (ioctl(fd, I2C_RDWR, &ioctl_data) != 1) 
 {
  free(buffer);
  close(fd);
  return FALSE;
 }
 
 free(buffer);
 close(fd);
 
 return TRUE;
}

【チェックサム関数】
送信データに必要な、チェックサムを作成します。

/*** チェックサム計算 ***/
static uint8_t get_check_sum(uint8_t *data, uint8_t len)
{
 unsigned long sum = 0;
 for(int i=0; i<len; i++)
 {
  sum += (data[i] & 0xff);
 }
 if(sum > 0xff)
 {
  sum = ~sum;
  sum += 1;
 }
 
 sum  = sum & 0xff;
 return (uint8_t)sum;
}

コンパイルと動作確認

コンパイルし、実行ファイルを起動します。

$gcc -o i2c_test i2c_test.c
$./i2c_test

実行結果

CANデータを取得するツールで値を確認し、
送信したデータが取得できていることを確認できました。

あとがき

ラズパイのI2Cポートを使ってCAN通信の確認ができました。
今回の変換に限らず、他にも変換して通信する方法は、多々あると思います。
興味がある方は、探してみるのはどうでしょうか。

確認に使用した自社開発ツールのCandyは、以下で紹介しています。

第1回 Candy 〜 メッセージ送受信 〜https://avancesys.co.jp/laboratory/article/%e7%ac%ac1%e5%9b%9e-candy-%e3%80%9c-%e3%83%a1%e3%83%83%e3%82%bb%e3%83%bc%e3%82%b8%e9%80%81%e5%8f%97%e4%bf%a1-%e3%80%9c/
第2回 Candy 〜 通信設定 〜https://avancesys.co.jp/laboratory/article/%e7%ac%ac2%e5%9b%9e-candy-%e3%80%9c-%e9%80%9a%e4%bf%a1%e8%a8%ad%e5%ae%9a-%e3%80%9c/
第3回 Candy 〜 ログ記録 〜https://avancesys.co.jp/laboratory/article/%e7%ac%ac3%e5%9b%9e-candy-%e3%80%9c-%e3%83%ad%e3%82%b0%e8%a8%98%e9%8c%b2-%e3%80%9c/
ソラ
ソラ

組み込み系の開発が多いですね。

スマートフォンのアプリなど作ってみたいですね。

関連記事