CRC-15-CANを計算するプログラムを書いた
(この記事はQiitaで書いた下記記事と同一です。)
はじめに
仕事でCAN通信のプログラムを書いているんだけど、CRCエラーの表示が出る。 デバッグのために、CRCの変換プログラムが必要になっった。 CANのCRCはCRC-15という特殊なフォーマットでネット上に資料が少ない。 ソースや調べたことをまとめておくことにした。
実装例
言語はCを使用。
#include <stdio.h> #include <stdint.h> // int to bin char* int_to_binstr(int bin, int len) { int i; static char buff[32]; 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() { int i; 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の生成多項式x15 + x14 + x10 + x8 + x7 + x4 + x3 + 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
任意の CRC 値になるバイト列を逆算してみよう - Qiita
Catalogue of parametrised CRC algorithms