ところで、CRCといえば「CRC5-56」というのが世間の相場ではありますが、ここはデータ伝送のセカイ.データ伝送といえばエラーチェック、エラーチェックといえばCRC、というのがこのセカイの相場です.
しかしわたしはCRCというものを扱った経験がありません.
テープストリーマのformatを考える人が、様々なデータユニットのお尻のところにCRCフィールドを付加していましたが、あいにくわたしの担当はその前段の、再生したアナログ信号をデジタルビットストリームに変換する、いわゆるチャネル屋だったので、CRC発生・検査回路を実際に設計した経験はありませんでした.
いっちょやってみようと思いネットを徘徊したところ、こちらのページがCRCの入門として具体的でとても判りやすいようでした.作者の方、ありがとうございます.
以下はそのページから引用した、生成多項式x16+x12+x5+1のCRCについてです.
CRCの発生・検査にはどのくらいのハードウエアを要するのかというと、意外に少なくて済むみたいです.
◆BYTE単位でデータが入力され、そのレートが10MBYTE/Secだとする
◆bit単位のシフト演算をするので、80MHzのcolckが必要である
◆演算回路は17bitかそこらのシフトレジスタとXORぐらい (CRC16にて)
なので、たいしたコトはなさそう.
-----
サンプルプログラムをこちらに置きました.解凍して出来るcrcフォルダを、Linuxマシンのどこか適当なディレクトリに置きます.中身はこの3つです.
Makefile
crc.c ←CRC計算・チェックプログラム
rand.txt ←テスト用ランダムバイトデータ
【速攻で動かす】
make
と打ちますと、こんな表示が出ます.これは、CRCをチェックした結果です.最初の列にだけ注目すればOKです.意味はこうです.◆aaから始まる16行が16バイトの入力データ (上記サイトのデータと同じです)
◆後続のaca6が付加したCRC16です.16バイト入れて18バイトが出てくるわけです.
◆その後続の0000がCRCチェックの結果で、ノーエラーならゼロになります.
aa 0xaa 00aa
55 0x55 aa55
01 0x01 41a1
98 0x98 f97d
c0 0xc0 03f6
df 0xdf c6bc
34 0x34 05be
7f 0x7f eeda
4e 0x4e c6ae
26 0x26 17ac
84 0x84 ce52
10 0x10 6a92
66 0x66 5f8a
51 0x51 214b
00 0x00 7f43
00 0x00 cc78
ac 0xac 606c ←送信側で計算され付加されたCRC[15:8]
a6 0xa6 0000 ←送信側で計算され付加されたCRC[7:0]
00 0x00 0000 ←
00 0x00 0000 ←受信側で計算されたCRC[15:0]がゼロになったのでノーエラー
【CRC計算コマンド】
ディレクトリを見ると、16data_with_2crc.txt というファイルが新しく出来ています.これが、CRCを付加した18BYTEのデータです.中身はこうなっています.EZ-USBが外部から受け取ってPCへ送信すべきデータがこれです.
aa 0xaa 00aa
55 0x55 aa55
中略
00 0x00 7f43
00 0x00 cc78
ac 0xac 606c
a6 0xa6 0000
このファイルを生成したコマンド(つまりCRC計算コマンド)は、Makefileに書かれているこれです.
crc 16 < rand.txt > 16data_with_2crc.txt
rand.txtがランダムBYTEデータを記述したファイル.「16」は同ファイルの先頭16行に対してCRCを計算せよ、という指令.16data_with_2crc.txtは出力ファイル名.【CRCチェックコマンド】
つぎに、CRCチェックするコマンドはこうなっています.
crc 18 < 16data_with_2crc.txt
crcというプログラム自体は、生成する時も検査する時も全く同じものです.
しかし「18」というのがミソです.これは、CRCを付加して18BYTEになったデータを、CRCもひっくるめてCRCを再計算してね、という意味です.こうすると、ノーエラーなら19BYTE目と20BYTE目にはCRC=0が出てきます.
CRCを含めずにデータだけを計算してCRC同士を比較するのかと思ってたけど、正統なCRC計算はそうではないらしいです.【ソースコード1】
CRCの演算そのものは、1BYTE毎に行うのはたったのこれだけです.8回シフトしてXORしてるだけ.簡単です.その意味は上述の解説サイトへどうぞどうぞ.
void CRCcalc(unsigned char *dt, unsigned short *CRC)
{
int k;
for(k=0; k<8; k++)
{
if((*CRC & 0x8000) != 0) // check over flow CRCはCRCの途中計算
{
*CRC = *CRC << 1; // overflow
*CRC = *CRC ^ 0x1021;
}
else *CRC = *CRC << 1; // no overflow
if((*dt & 0x80) != 0) // check over flow dtは1BYTEのデータ
{
*dt = *dt << 1; // overflow
*CRC = *CRC ^ 0x0001;
}
else *dt = *dt << 1; // no over flow
}
}
【ソースコード2】
main()はファイルから1行取ってくるとか、1行表示するとか、附帯的な動作ばかりなわけですが、CRCも含めて演算対象であるというとこがちょっとなにかなぁと思わんでも無いです.
◆青字のループは、16回ループして16BYTEのデータに対するCRC演算を行うところです.
◆赤字のところは、CRC[15:8]をデータとして扱ってCRC演算するところです.
◆ピンクのところは、CRC[7:8]をデータとして扱ってCRC演算するところです.
◆最後に黒字のところで、CRCを表示させます.赤字のところで一歩早まってCRC[15:8]を表示させちゃうと死にます.
{
hex[2]=0;
strcat(hex,rmcr(line));
dt = (int)atof(hex); 一行のデータ=1BYTEデータ
CRCcalc(&dt, &CRC); // calc CRC1Byte 1BYTE逐次のCRC計算
printf("%s %s %04x\n",rmcr(line),hex,CRC); 一行表示
i++;
if(i>=len) break;
}
// CRC is also calclurated as a data
dt=0;//(unsigned char)((CRC >> 8) & 0x00ff); // CRC[15:8]
CRCcalc(&dt, &CRC); // calc CRC1Byte
dt=0;//(unsigned char)(CRC & 0x00ff); // CRC[7:0]
CRCcalc(&dt, &CRC); // calc CRC1Byte
dt=(unsigned char)((CRC >> 8) & 0x00ff); // CRC[15:8]
printf("%02x 0x%02x %04x\n",dt,dt,CRC);
dt=(unsigned char)(CRC & 0x00ff); // CRC[7:0]
printf("%02x 0x%02x %04x\n",dt,dt,CRC);
------
つぎはverilogで同じコトをやってみます.
その22へ その24へ
かしこ
INDEXページへ
https://hirasakausb.blogspot.com/2019/03/ez-usb-fx2lp-index.html
サイクリックリダンシーコード ですか、
返信削除遙か昔 チェックサムの時代に現れまして「サムではいけないの?」と言ってしまったわたし。
チェックサムよりもエラー検出能力が高いのだと推測しますが、定量的にどれだけなのかは全然知りません.
削除