#はじめに
仕事でCAN通信のプログラムを書いているんだけど、CRCエラーの表示が出る。
デバッグのために、CRCの変換プログラムが必要になっった。
CANのCRCはCRC-15という特殊なフォーマットでネット上に資料が少ない。
ソースや調べたことをまとめておくことにした。
#実装例
言語はcを使用。
(追記)コメントでint_to_binstr()の終端処理等の記述が抜けていたという指摘があり、修正した。
#include <stdio.h>
#include <stdint.h>
// int to bin
char* int_to_binstr(char buff[], int bin, int len)
{
int i;
for (i = 0; i < len; i++) {
if (bin & (1UL << (len - i - 1))) {
buff[i] = '1';
}
else {
buff[i] = '0';
}
}
buff[len] = '\0';
return buff;
}
uint16_t can_crc_next(uint16_t crc, uint8_t data)
{
uint8_t i;
crc ^= (uint16_t)data << 7;
for (i = 0; i < 8; i++) {
crc <<= 1;
if (crc & 0x8000) {
crc ^= 0xc599;
}
}
return crc & 0x7fff;
}
void cal_crc15(unsigned char* buff, int len) {
uint16_t crc;
crc = 0;
printf("crc15 0x");
for (int i = 0; i < len; i++) {
printf("%02X ", buff[i]);
}
printf("\n-> ");
for (int i = 0; i < len; i++) {
crc = can_crc_next(crc, buff[i]);
}
char binstr[16];
printf("0x%04X(%s)\n", crc, int_to_binstr(binstr, (int)crc, 15));
}
int main()
{
uint8_t data[] = { 0x00, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
cal_crc15(data, 11);
}
#CRC元データについて
CRCの元データはSOFからデータまで。スタッフビットは除く。
バイナリはHEXにする。
SOF側が半端なビットになるようにする。
uint8_t data[] = { 0x00, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
#プログラムの動作
CRCの初期値は0。
crc = 0;
データをHEXごとに取り出して7ビット左シフトしてCRCと排他的論理和をとる。
crc ^= (uint16_t)data << 7;
CRCを1ビット左シフト
crc <<= 1;
CRCの最上位ビットが1なら、CRC15の生成多項式x^15 + x^14 + x^10 + x^8 + x^7 + x^4 + x^3 + 1(=0xc599)との排他的論理和を取る。
if (crc & 0x8000) {
crc ^= 0xc599;
}
15ビットなので16ビットの最上位ビットを省く。
return crc & 0x7fff;
#注意
CANコントローラ(MCP2515)の吐き出した値と一致することは確認できているが、CAN15の仕様と完全に一致しているかは確認できていない。
おそらく大丈夫だとは思うが。
#参考URL
http://forum.easyelectronics.ru/viewtopic.php?f=49&t=34508
https://qiita.com/niQSun/items/5bf1d8d9ceea16d83951
https://qiita.com/dearblue/items/669e2ce2fae57baf1e90
https://ja.wikipedia.org/wiki/%E5%B7%A1%E5%9B%9E%E5%86%97%E9%95%B7%E6%A4%9C%E6%9F%BB
https://reveng.sourceforge.io/crc-catalogue/1-15.htm#crc.cat-bits.15