概要
CRCとは
dsPIC33CHシリーズにはCRCモジュールがマスターコアに1ch搭載されています。このモジュールを使えば通信を行う時の通信エラー検出が容易に行えます。
CRCとは「Cyclic Redundancy Check」の頭文字をとった用語で、日本語では巡回冗長検査といい誤り検出符号の一種で主にデータ転送に伴うエラーの検出に使われています。
単純な加算方法のチェックサム方式に比べ高い誤り検出が可能ですが、誤りを修正する機能は有りません。
CRCに関して詳しくはここでは説明いたしませんが、私が解りやすいと感じたサイトを紹介します。
ペリフェラルの構造
CRCモジュールの概略ブロック図は以下のとおりです。データ入力は128bitサイズのFifoメモリを有しており、このサイズ以内であれば連続してデータが書き込めます。


ハードウェア構成と制御ブロック
今回は外部との入出力は行わず、固定値のメッセージを様々なCRCアルゴリズムを通した結果をRAMに格納します。

レジスタ
CRC関連のレジスタは以下の8種類です。
| レジスタ名 | 機能 | 説明 |
| CRCCONL | CRC Control Register Low | CRC制御レジスタ Low |
| CRCCONH | CRC Control Register High | CRC制御レジスタ High |
| CRCXORL CRCXORH | CRC XOR Polynomial Register High /Low | CRC 多項式レジスタ |
| CRCDATL CRCDATH | UARTx STATUS Register High | CRC Dataレジスタ High /Low |
| CRCWDATL CRCWDATH | CRC Shift Register High / Low | CRC シフトレジスタ High /Low |
ソースコード
算出方法
①CRCを算出する為の元のメッセージを以下のchar型かint型の配列に格納します。
unsigned char message_8bit[] = {0x44,0x43,0x42,0x41}; //メッセージ
unsigned int message_16bit[] = {0x4443,0x4241}; //メッセージ
②メッセージ配列が8bitの場合は以下をコールします。第1引数はメッセージ配列のポインタ、第2引数はデータ長、第3引数はCRCアルゴリズムを指定します。
CRC_Calc8(message_8bit , DataLength, CRC_8);
同様にメッセージ配列が16bitの場合は以下をコールします。
CRC_Calc16(message_16bit , DataLength, CRC_8);
アルゴリズムはCRC-8では13種類、CRC-16では23種類のデフォルトパラメータを定義しております。またパラメータ名はenum CRC_IDで定義しています。
コンフィグレーション設定についてはコンフィグレーション設定に記載しております。
コピーして下記のソースコードの「 //ここにコンフィグレーション設定を挿入する// 」の位置に挿入してください。
クロック設定用関数 vds_Main_Init_Clock_Register(); のソースコードはクロック設定のページに記載しております。
コピーして下記のソースコードの「 //ここにクロック設定ソースをコピペする// 」の位置に挿入してください。
/*------------------------------------------------------------------------------*/
/* @file CRCSample.c */
/* @brief 各種CRC値を求める */
/*------------------------------------------------------------------------------*/
/*------------------------------------------------------------------------------*/
/* コンフィグレーション設定*/
/*------------------------------------------------------------------------------*/
//ここにコンフィグレーション設定を挿入する//
/*------------------------------------------------------------------------------*/
/* インクルードファイル*/
/*------------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
/*------------------------------------------------------------------------------*/
/* 定数定義*/
/*------------------------------------------------------------------------------*/
enum CRC_ID
{
CRC_INHERIT = 0,
CRC_8 ,
CRC_8_CDMA2000,
CRC_8_DARC,
CRC_8_DVB_S2,
CRC_8_EBU,
CRC_8_ICODE,
CRC_8_ITU,
CRC_8_MAXIM,
CRC_8_ROHC,
CRC_8_WCDMA,
CRC_8_SAE_J1850,
CRC_8_SAE_J1850_ZERO,
CRC_8_8H2F,
CRC_16,
CRC_16_CCITT_FALSE,
CRC_16_ARC,
CRC_16_AUG_CCITT,
CRC_16_CDMA2000,
CRC_16_DDS_110,
CRC_16_DECT_R,
CRC_16_DECT_X,
CRC_16_DNP,
CRC_16_EN_13757,
CRC_16_GENIBUS,
CRC_16_MAXIM,
CRC_16_MCRF4XX,
CRC_16_RIELLO,
CRC_16_T10_DIF,
CRC_16_TELEDISK,
CRC_16_TMS37157,
CRC_16_USB,
CRC_A,
CRC_16_KERMIT,
CRC_16_MODBUS,
CRC_16_X_25,
CRC_16_XMODEM
};
enum CRC_PARAM
{
POLYNOMIAL = 0,
SEED_VALUE,
NON_DIRECT_VALUE,
REF_IN,
REF_OUT,
XOR_OUT,
POLY_ORDER,
DATA_LENGTH
};
#define CRC_INPUT_REFLECTED_DISABLE 0
#define CRC_INPUT_REFLECTED_ENABLE 1
#define CRC_OUTPUT_REFLECTED_DISABLE 0
#define CRC_OUTPUT_REFLECTED_ENABLE 1
#define CRC_POLY_ORDER_8BIT 8
#define CRC_POLY_ORDER_16BIT 16
#define CRC_POLY_ORDER_32BIT 32
#define CRC_DATA_WIDTH_8BIT 8
#define CRC_DATA_WIDTH_16BIT 16
#define CRC_DATA_WIDTH_32BIT 32
#define REVERSE_BIT_ALG_MCP_DEF 0
#define REVERSE_BIT_ALG_EDWINFREED 1
#define REVERSE_BIT_ALG REVERSE_BIT_ALG_EDWINFREED
/*------------------------------------------------------------------------------*/
/*変数定義*/
/*------------------------------------------------------------------------------*/
unsigned char message_8bit[] = {0x44,0x43,0x42,0x41}; //メッセージ
unsigned int message_16bit[] = {0x4443,0x4241}; //メッセージ
//unsigned char message_8bit[] = {0x44,0x43,0x42,0x41,0x44,0x43,0x42,0x41,0x44,0x43,0x42,0x41,0x44,0x43,0x42,0x41}; //送信メッセージ
unsigned int message_16bit[] = {0x4443,0x4241,0x4443,0x4241,0x4443,0x4241,0x4443,0x4241}; //送信メッセージ
unsigned long PolyNomial;
unsigned long SeedValue;
unsigned short NonDirectValue;
unsigned char Input_Reflected;
unsigned char Output_Reflected;
unsigned long FinalXorValue;
unsigned char PolyNomialOrder;
unsigned char DataWidth;
const unsigned int CRC_Parameter[40][7] =
{
//Poly,Init,NonDirect,RefIn,RefOut,XorOut,PolyLength
{0x07,0x00,0x00,0x0000,0x0000,0x00,0x08},//CRC_8
{0x9B,0xFF,0x21,0x0000,0x0000,0x00,0x08},//CRC_8_CDMA2000
{0x39,0x00,0x00,0x0001,0x0001,0x00,0x08},//CRC_8_DARC
{0xD5,0x00,0x00,0x0000,0x0000,0x00,0x08},//CRC_8_DVB_S2
{0x1D,0xFF,0x7E,0x0001,0x0001,0x00,0x08},//CRC_8_EBU
{0x1D,0xFD,0x65,0x0000,0x0000,0x00,0x08},//CRC_8_I_CODE
{0x07,0x00,0x00,0x0000,0x0000,0x55,0x08},//CRC_8_ITU
{0x31,0x00,0x00,0x0001,0x0001,0x00,0x08},//CRC_8_MAXIM
{0x07,0xFF,0x48,0x0001,0x0001,0x00,0x08},//CRC_8_ROHC
{0x9B,0x00,0x00,0x0001,0x0001,0x00,0x08},//CRC_8_WCDMA
{0x1D,0xFF,0x7E,0x0000,0x0000,0xFF,0x08},//CRC_SAE_J1850
{0x1D,0x00,0x00,0x0000,0x0000,0x00,0x08},//CRC_SAE_J1850_ZERO
{0x2F,0xFF,0x7D,0x0000,0x0000,0xFF,0x08},//CRC_8H2F
{0x8005,0x0000,0x0000,0x0000,0x0000,0x0000,0x10},//CRC_16_BUYPASS
{0x1021,0xFFFF,0x84CF,0x0000,0x0000,0x0000,0x10},//CRC_16_CCITT_FALSE
{0x8005,0x0000,0x0000,0x0001,0x0001,0x0000,0x10},//CRC_16_ARC
{0x1021,0x1D0F,0xFFFF,0x0000,0x0000,0x0000,0x10},//CRC_16_AUG_CCITT
{0xC867,0xFFFF,0x0411,0x0000,0x0000,0x0000,0x10},//CRC_16_CDMA2000
{0x8005,0x800D,0xFFFF,0x0000,0x0000,0x0000,0x10},//CRC_16_DDS_110
{0x0589,0x0000,0x0000,0x0000,0x0000,0x0001,0x10},//CRC_16_DECT_R
{0x0589,0x0000,0x0000,0x0000,0x0000,0x0000,0x10},//CRC_16_DECT_X
{0x3D65,0x0000,0x0000,0x0001,0x0001,0xFFFF,0x10},//CRC_16_DNP
{0x3D65,0x0000,0x0000,0x0000,0x0000,0xFFFF,0x10},//CRC_16_EN_13757
{0x1021,0xFFFF,0x84CF,0x0000,0x0000,0xFFFF,0x10},//CRC_16_GENIBUS
{0x8005,0x0000,0x0000,0x0001,0x0001,0xFFFF,0x10},//CRC_16_MAXIM
{0x1021,0xFFFF,0x84CF,0x0001,0x0001,0x0000,0x10},//CRC_16_MCRF4XX
{0x1021,0xB2AA,0xE109,0x0001,0x0001,0x0000,0x10},//CRC_16_RIELLO
{0x8BB7,0x0000,0x0000,0x0000,0x0000,0x0000,0x10},//CRC_16_T10_DIF
{0xA097,0x0000,0x0000,0x0000,0x0000,0x0000,0x10},//CRC_16_TELEDISK
{0x1021,0x89EC,0xC832,0x0001,0x0001,0x0000,0x10},//CRC_16_TMS37157
{0x8005,0xFFFF,0xEAA8,0x0001,0x0001,0xFFFF,0x10},//CRC_16_USB
{0x1021,0xC6C6,0x606A,0x0001,0x0001,0x0000,0x10},//CRC_A
{0x1021,0x0000,0x0000,0x0001,0x0001,0x0000,0x10},//CRC_16_KERMIT
{0x8005,0xFFFF,0xEAA8,0x0001,0x0001,0x0000,0x10},//CRC_16_MODBUS
{0x1021,0xFFFF,0x84CF,0x0001,0x0001,0xFFFF,0x10},//CRC_16_X_25
{0x1021,0x0000,0x0000,0x0000,0x0000,0x0000,0x10}//CRC_16_XMODEM
};
static const unsigned short crc16table[256] = {
0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040
};
/*------------------------------------------------------------------------------*/
/* プロトタイプ宣言*/
/*------------------------------------------------------------------------------*/
static unsigned long CRC_Calc8(unsigned char *message,unsigned int Length,unsigned char Algo);
static unsigned long CRC_Calc16(unsigned int *message,unsigned int Length,unsigned char
Algo);
unsigned int crc16_CPU(unsigned int crc, unsigned char const *ptr, int len);
unsigned short crc16_CPU_Table(unsigned short crc, unsigned char const *ptr, int len);
/*------------------------------------------------------------------------------*/
/* クロック設定 */
/*------------------------------------------------------------------------------*/
//ここにクロック設定ソースを挿入する//
/*------------------------------------------------------------------------------*/
/* Main関数 */
/*------------------------------------------------------------------------------*/
int main(void)
{
volatile uint32_t CRC_Result[80];
unsigned int DataLength;
/*--------------------------------------------------------------------------*/
/* クロック初期化*/
/*--------------------------------------------------------------------------*/
vds_Main_Init_Clock_Register(); /* クロック初期化 */
/*--------------------------------------------------------------------------*/
/* メインルーチン*/
/*--------------------------------------------------------------------------*/
while (1)
{
DataLength = sizeof(message_8bit)/sizeof(unsigned char);
CRC_Result[0] = CRC_Calc8(message_8bit , DataLength, CRC_8);
CRC_Result[1] = CRC_Calc8(message_8bit , DataLength, CRC_8_CDMA2000);
CRC_Result[2] = CRC_Calc8(message_8bit , DataLength, CRC_8_DARC);
CRC_Result[3] = CRC_Calc8(message_8bit , DataLength, CRC_8_DVB_S2);
CRC_Result[4] = CRC_Calc8(message_8bit , DataLength, CRC_8_EBU);
CRC_Result[5] = CRC_Calc8(message_8bit , DataLength, CRC_8_ICODE);
CRC_Result[6] = CRC_Calc8(message_8bit , DataLength, CRC_8_ITU);
CRC_Result[7] = CRC_Calc8(message_8bit , DataLength, CRC_8_MAXIM);
CRC_Result[8] = CRC_Calc8(message_8bit , DataLength, CRC_8_ROHC);
CRC_Result[9] = CRC_Calc8(message_8bit , DataLength, CRC_8_WCDMA);
CRC_Result[10] = CRC_Calc8(message_8bit , DataLength, CRC_8_SAE_J1850);
CRC_Result[11] = CRC_Calc8(message_8bit , DataLength, CRC_8_SAE_J1850_ZERO);
CRC_Result[12] = CRC_Calc8(message_8bit , DataLength, CRC_8_8H2F);
CRC_Result[13] = CRC_Calc8(message_8bit , DataLength, CRC_16);
CRC_Result[14] = CRC_Calc8(message_8bit , DataLength, CRC_16_CCITT_FALSE);
CRC_Result[15] = CRC_Calc8(message_8bit , DataLength, CRC_16_ARC);
CRC_Result[16] = CRC_Calc8(message_8bit , DataLength, CRC_16_AUG_CCITT);
CRC_Result[17] = CRC_Calc8(message_8bit , DataLength, CRC_16_CDMA2000);
CRC_Result[18] = CRC_Calc8(message_8bit , DataLength, CRC_16_DDS_110);
CRC_Result[19] = CRC_Calc8(message_8bit , DataLength, CRC_16_DECT_R);
CRC_Result[20] = CRC_Calc8(message_8bit , DataLength, CRC_16_DECT_X);
CRC_Result[21] = CRC_Calc8(message_8bit , DataLength, CRC_16_DNP);
CRC_Result[22] = CRC_Calc8(message_8bit , DataLength, CRC_16_EN_13757);
CRC_Result[23] = CRC_Calc8(message_8bit , DataLength, CRC_16_GENIBUS);
CRC_Result[24] = CRC_Calc8(message_8bit , DataLength, CRC_16_MAXIM);
CRC_Result[25] = CRC_Calc8(message_8bit , DataLength, CRC_16_MCRF4XX);
CRC_Result[26] = CRC_Calc8(message_8bit , DataLength, CRC_16_RIELLO);
CRC_Result[27] = CRC_Calc8(message_8bit , DataLength, CRC_16_T10_DIF);
CRC_Result[28] = CRC_Calc8(message_8bit , DataLength, CRC_16_TELEDISK);
CRC_Result[29] = CRC_Calc8(message_8bit , DataLength, CRC_16_TMS37157);
CRC_Result[30] = CRC_Calc8(message_8bit , DataLength, CRC_16_USB);
CRC_Result[31] = CRC_Calc8(message_8bit , DataLength, CRC_A);
CRC_Result[32] = CRC_Calc8(message_8bit , DataLength, CRC_16_KERMIT);
CRC_Result[33] = CRC_Calc8(message_8bit , DataLength, CRC_16_MODBUS);
CRC_Result[34] = CRC_Calc8(message_8bit , DataLength, CRC_16_X_25);
CRC_Result[35] = CRC_Calc8(message_8bit , DataLength, CRC_16_XMODEM);
CRC_Result[72] = CRC_Calc8(message_16bit , DataLength, CRC_16_USB);
CRC_Result[73] = CRC_Calc8(message_16bit , DataLength, CRC_INHERIT);
CRC_Result[74] = CRC_Calc8(message_16bit , DataLength, CRC_INHERIT);
DataLength = sizeof(message_16bit)/sizeof(unsigned int);
CRC_Result[36] = CRC_Calc16(message_16bit , DataLength, CRC_8);
CRC_Result[37] = CRC_Calc16(message_16bit , DataLength, CRC_8_CDMA2000);
CRC_Result[38] = CRC_Calc16(message_16bit , DataLength, CRC_8_DARC);
CRC_Result[39] = CRC_Calc16(message_16bit , DataLength, CRC_8_DVB_S2);
CRC_Result[40] = CRC_Calc16(message_16bit , DataLength, CRC_8_EBU);
CRC_Result[41] = CRC_Calc16(message_16bit , DataLength, CRC_8_ICODE);
CRC_Result[42] = CRC_Calc16(message_16bit , DataLength, CRC_8_ITU);
CRC_Result[43] = CRC_Calc16(message_16bit , DataLength, CRC_8_MAXIM);
CRC_Result[44] = CRC_Calc16(message_16bit , DataLength, CRC_8_ROHC);
CRC_Result[45] = CRC_Calc16(message_16bit , DataLength, CRC_8_WCDMA);
CRC_Result[46] = CRC_Calc16(message_16bit , DataLength, CRC_8_SAE_J1850);
CRC_Result[47] = CRC_Calc16(message_16bit , DataLength, CRC_8_SAE_J1850_ZERO);
CRC_Result[48] = CRC_Calc16(message_16bit , DataLength, CRC_8_8H2F);
CRC_Result[49] = CRC_Calc16(message_16bit , DataLength, CRC_16);
CRC_Result[50] = CRC_Calc16(message_16bit , DataLength, CRC_16_CCITT_FALSE);
CRC_Result[51] = CRC_Calc16(message_16bit , DataLength, CRC_16_ARC);
CRC_Result[52] = CRC_Calc16(message_16bit , DataLength, CRC_16_AUG_CCITT);
CRC_Result[53] = CRC_Calc16(message_16bit , DataLength, CRC_16_CDMA2000);
CRC_Result[54] = CRC_Calc16(message_16bit , DataLength, CRC_16_DDS_110);
CRC_Result[55] = CRC_Calc16(message_16bit , DataLength, CRC_16_DECT_R);
CRC_Result[56] = CRC_Calc16(message_16bit , DataLength, CRC_16_DECT_X);
CRC_Result[57] = CRC_Calc16(message_16bit , DataLength, CRC_16_DNP);
CRC_Result[58] = CRC_Calc16(message_16bit , DataLength, CRC_16_EN_13757);
CRC_Result[59] = CRC_Calc16(message_16bit , DataLength, CRC_16_GENIBUS);
CRC_Result[60] = CRC_Calc16(message_16bit , DataLength, CRC_16_MAXIM);
CRC_Result[61] = CRC_Calc16(message_16bit , DataLength, CRC_16_MCRF4XX);
CRC_Result[62] = CRC_Calc16(message_16bit , DataLength, CRC_16_RIELLO);
CRC_Result[63] = CRC_Calc16(message_16bit , DataLength, CRC_16_T10_DIF);
CRC_Result[64] = CRC_Calc16(message_16bit , DataLength, CRC_16_TELEDISK);
CRC_Result[65] = CRC_Calc16(message_16bit , DataLength, CRC_16_TMS37157);
CRC_Result[66] = CRC_Calc16(message_16bit , DataLength, CRC_16_USB);
CRC_Result[67] = CRC_Calc16(message_16bit , DataLength, CRC_A);
CRC_Result[68] = CRC_Calc16(message_16bit , DataLength, CRC_16_KERMIT);
CRC_Result[69] = CRC_Calc16(message_16bit , DataLength, CRC_16_MODBUS);
CRC_Result[70] = CRC_Calc16(message_16bit , DataLength, CRC_16_X_25);
CRC_Result[71] = CRC_Calc16(message_16bit , DataLength, CRC_16_XMODEM);
DataLength = sizeof(message_8bit)/sizeof(unsigned char);
CRC_Result[75] = crc16_CPU(0,message_8bit,DataLength);
CRC_Result[76] = crc16_CPU_Table(0,message_8bit,DataLength);
while (1)
{
Nop() ;
}
}
return 1;
}
/*------------------------------------------------------------------------------*/
/* @fn CalculateNonDirectSeed
(
unsigned long seed, // direct CRC initial value
unsigned long polynomial, // polynomial
unsigned char polynomialOrder) // polynomial order
*/
/* @brief 非直接初期値を求める*/
/* @param[in] seed:初期値*/
/* @param[in] polynomial:多項式*/
/* @param[in] polynomialOrder:多項式長*/
/* @Return 非直接初期値*/
/*--------------------------------------------------------------------------*/
unsigned long CalculateNonDirectSeed
(
unsigned long seed, // direct CRC initial value
unsigned long polynomial, // polynomial
unsigned char polynomialOrder) // polynomial order
{
/*--------------------------------------------------------------------------*/
/* ローカル変数の定義と初期化*/
/*--------------------------------------------------------------------------*/
unsigned char lsb;
unsigned char i;
unsigned long msbmask;
/*--------------------------------------------------------------------------*/
/* 非直接初期値を求める*/
/*--------------------------------------------------------------------------*/
msbmask = ((unsigned long)1)<<(polynomialOrder-1);
for (i=0; i<polynomialOrder; i++)
{
lsb = seed & 1;
if (lsb) seed ^= polynomial;
seed >>= 1;
if (lsb) seed |= msbmask;
}
return seed;
}
/*------------------------------------------------------------------------------*/
/* @fn ReverseBitOrder(unsigned long data) */
/* @brief ビットの上下をスワップします*/
/* @param[in] data:反転するデータ*/
/* @Return スワップ結果*/
/*------------------------------------------------------------------------------*/
unsigned long ReverseBitOrder(unsigned long data)
{
/*--------------------------------------------------------------------------*/
/*ローカル変数の定義と初期化*/
/*--------------------------------------------------------------------------*/
unsigned long result = 0;
#if (REVERSE_BIT_ALG == REVERSE_BIT_ALG_EDWINFREED)
//http://graphics.stanford.edu/~seander/bithacks.html#BitReverseTable
//奇数ビットと偶数ビットの交換
data =((data >> 1)&0x55555555)| ((data&0x55555555)<< 1);
//連続するペアの交換
data =((data >> 2)&0x33333333)| ((data&0x33333333)<< 2);
//ニブルの交換
data =((data >> 4)&0x0F0F0F0F)| ((data&0x0F0F0F0F)<< 4);
//バイトの交換
data =((data >> 8)&0x00FF00FF)| ((data&0x00FF00FF)<< 8);
// 2バイトの長いペアの交換
result =(data >> 16)| (data << 16);
#elif (REVERSE_BIT_ALG == REVERSE_BIT_ALG_MCP_DEF)
//Microchip Data Sheet
/*--------------------------------------------------------------------------*/
/*ローカル変数の定義と初期化*/
/*--------------------------------------------------------------------------*/
unsigned long maskin;
unsigned long maskout;
unsigned char i;
maskin = 0x80000000;
maskout = 0x00000001;
/*--------------------------------------------------------------------------*/
/* ビット反転*/
/*--------------------------------------------------------------------------*/
for(i = 0u; i < 32u; i++)
{
if(data & maskin)
{
result |= maskout;
}
maskin >>= 1u;
maskout <<= 1u;
}
#endif
return result;
}
/*------------------------------------------------------------------------------*/
/* @fn CRC_Set_Parameter(unsigned char Algo,unsigned char DataWidth)*/
/* @brief パラメータのパラメータのセット*/
/* @param[in] Algo:CRCアルゴリズム*/
/* @param[in] DataWidth:データ幅*/
/* @Return 無し*/
/* @Cycle 160Cycle*/
/*------------------------------------------------------------------------------*/
static void CRC_Set_Parameter(unsigned char Algo,unsigned char DataWidth)
{
if (Algo > CRC_INHERIT)
{
PolyNomial = CRC_Parameter[Algo - 1u][POLYNOMIAL];
SeedValue = CRC_Parameter[Algo - 1u][SEED_VALUE];
NonDirectValue = CRC_Parameter[Algo - 1u][NON_DIRECT_VALUE];
Input_Reflected = CRC_Parameter[Algo - 1u][REF_IN];
Output_Reflected = CRC_Parameter[Algo - 1u][REF_OUT];
FinalXorValue = CRC_Parameter[Algo - 1u][XOR_OUT];
PolyNomialOrder = CRC_Parameter[Algo - 1u][POLY_ORDER];
}
/*--------------------------------------------------------------------------*/
/* 非直接初期値を求める(1度だけ非直接初期値を求めれば、実行時に求める必要は無い)*/
/*--------------------------------------------------------------------------*/
// NonDirectValue = CalculateNonDirectSeed(SeedValue,PolyNomial,PolyNomialOrder);
/*--------------------------------------------------------------------------*/
/* CRCレジスタ設定*/
/*--------------------------------------------------------------------------*/
CRCCONL = 0x8000 | (Input_Reflected << 3u);
CRCCONH = ((DataWidth - 1u) << 8u) |(PolyNomialOrder - 1u);
CRCXORL = PolyNomial;
CRCXORH = 0x00u;
CRCWDATL = NonDirectValue;
CRCWDATH = 0x0000u;
}
/*------------------------------------------------------------------------------*/
/* @fn CRC_Flush_Clean_Output(void)*/
/* @brief データのフラッシュ、クリーンナップ、出力処理*/
/* @param[in] 無し*/
/* @Return 無し*/
/*------------------------------------------------------------------------------*/
static unsigned long CRC_Flush_Clean_Output(void)
{
unsigned long CRC_Result;
/*--------------------------------------------------------------------------*/
/* データフラッシュ*/
/*--------------------------------------------------------------------------*/
asm volatile ("repeat %0\n nop" : : "r"(DataWidth >> 1u));
CRCCON1bits.CRCGO = 0u;
IFS3bits.CRCIF = 0u;
CRCCONHbits.DWIDTH = PolyNomialOrder - 1;
if (PolyNomialOrder == CRC_POLY_ORDER_16BIT){CRCDATL = 0u;}
else if(PolyNomialOrder == CRC_POLY_ORDER_8BIT){*((uint8_t *)&CRCDATL) = 0x00u;}
CRCCONLbits.CRCGO = 1u;
/*--------------------------------------------------------------------------*/
/* データクリーンナップ*/
/*--------------------------------------------------------------------------*/
while(IFS3bits.CRCIF == 0u){;}
CRCCONHbits.DWIDTH = DataWidth - 1;
CRCCONLbits.CRCGO = 0u;
IFS3bits.CRCIF = 0u;
/*--------------------------------------------------------------------------*/
/* 出力*/
/*--------------------------------------------------------------------------*/
if (Output_Reflected == 0u)
{
if (FinalXorValue == 0x00u)
{
return((uint32_t)CRCWDATL);
}
else
{
return(((uint32_t)CRCWDATL ^ FinalXorValue) );
}
}
else
{
if (FinalXorValue == 0x00u)
{
CRC_Result = ReverseBitOrder(CRCWDATL );
return(CRC_Result >> (32 - PolyNomialOrder));
}
else
{
CRC_Result = ReverseBitOrder(CRCWDATL);
return(((CRC_Result >> (32 - PolyNomialOrder))^ FinalXorValue) );
}
}
}
/*------------------------------------------------------------------------------*/
/* @fn crc16_CPU(unsigned short crc, unsigned char const *ptr, int len)*/
/* @brief CRC16のCPU計算*/
/* @param[in] crc:初期値*/
/* @param[in] ptr:計算対象バイト*/
/* @param[in] len:計算対象バイト長*/
/* @param[out] CRC計算結果*/
/*------------------------------------------------------------------------------*/
unsigned int crc16_CPU(unsigned int crc, unsigned char const *ptr, int len)
{
#define CRC16POLY 0xa001
int i, j;
crc = ~crc;
for (i = 0; i < len; i++)
{
crc ^= ptr[i];
for (j = 0; j < 8; j++)
{
if (crc & 1)
{
crc = (crc >> 1) ^ CRC16POLY;
}
else
{
crc >>= 1;
}
}
}
return ~crc;
}
/*------------------------------------------------------------------------------*/
/* @fn crc16_CPU_Table(unsigned short crc, unsigned char const *ptr, int len)*/
/* @brief CRC16のテーブル参照計算*/
/* @param[in] crc:初期値*/
/* @param[in] ptr:計算対象バイト*/
/* @param[in] len:計算対象バイト長*/
/* @param[out] CRC計算結果*/
/*------------------------------------------------------------------------------*/
unsigned short crc16_CPU_Table(unsigned short crc, unsigned char const *ptr, int len)
{
crc = ~crc;
int i;
for ( i = 0; i < len; i++)
{
unsigned char c = ptr[i];
crc = (crc >> 8) ^ crc16table[(crc ^ c) & 0x00ff];
}
return ~crc;
}
/*------------------------------------------------------------------------------*/
/* @fn CRC_Calc8(unsigned char *message,unsigned int Length,unsigned char Algo)*/
/* @brief 8ビットデータサイズのCRC計算*/
/* @param[in] message:計算対象バイト列*/
/* @param[in] Length:計算対象バイト長*/
/* @paeam[in] Algo:CRCアルゴリズム*/
/* @Return 8ビットデータ結果*/
/*------------------------------------------------------------------------------*/
static unsigned long CRC_Calc8(unsigned char *message,unsigned int Length,unsigned char Algo)
{
/*--------------------------------------------------------------------------*/
/* ローカル変数の定義と初期化*/
/*--------------------------------------------------------------------------*/
unsigned long CRC_Result;
CRC_Set_Parameter(Algo,CRC_DATA_WIDTH_8BIT);
/*--------------------------------------------------------------------------*/
/* CRCデータレジスタにデータ転送*/
/*--------------------------------------------------------------------------*/
CRCCONLbits.CRCGO = 1;
while(Length > 0u)
{
*((uint8_t *)&CRCDATL) = *message++;
Length --;
}
while(IFS3bits.CRCIF == 0u){;}
/*--------------------------------------------------------------------------*/
/* CRCデータレジスタにデータ転送*/
/*--------------------------------------------------------------------------*/
while(Length --)
{
while(CRCCON1bits.CRCFUL);
*((uint8_t *)&CRCDATL) = *message++;
}
/*--------------------------------------------------------------------------*/
/* データフラッシュ、クリーン、出力*/
/*--------------------------------------------------------------------------*/
return(CRC_Flush_Clean_Output());
}
/*------------------------------------------------------------------------------*/
/* @fn CRC_Calc16(unsigned int *message,unsigned int Length,unsigned char Algo)*/
/* @brief 16ビットデータサイズのCRC計算*/
/* @param[in] message:計算対象バイト列*/
/* @param[in] Length:計算対象バイト長*/
/* @paeam[in] Algo:CRCアルゴリズム*/
/* @Return 16bitデータ結果*/
/*------------------------------------------------------------------------------*/
static unsigned long CRC_Calc16(unsigned int *message,unsigned int Length,unsigned char Algo)
{
/*--------------------------------------------------------------------------*/
/* ローカル変数の定義と初期化*/
/*--------------------------------------------------------------------------*/
unsigned int TempData;
CRC_Set_Parameter(Algo,CRC_DATA_WIDTH_16BIT);
/*--------------------------------------------------------------------------*/
/* CRCデータレジスタにデータ転送*/
/*--------------------------------------------------------------------------*/
CRCCONLbits.CRCGO = 1;
if(Input_Reflected == 0u)
{
while(Length --)
{
while(CRCCON1bits.CRCFUL);
CRCDATL = *message++;
}
}
else
{
while(Length --)
{
while(CRCCON1bits.CRCFUL);
TempData = *message++;
asm volatile ("swap %0" : "+r"(TempData));
CRCDATL = TempData;
}
}
while(IFS3bits.CRCIF == 0u){;}
/*--------------------------------------------------------------------------*/
/* データフラッシュ、クリーン、出力*/
/*--------------------------------------------------------------------------*/
return(CRC_Flush_Clean_Output());
}
結果
妥当性
演算の妥当性に関しては以下のCRC計算サイト様で検算を行っておりますが、ソースをご利用の際はご自身で都度ご確認をお願いします。

実行時間
各アルゴリズムに対しての実行サイクルと実行時間を以下に示します。(コンパイラオプション= 1 , 8bitデータ,16Byteの時)。また CRCモジュールとCPUで演算した時の比較をするために、そらみみの声-CRC16を計算する様のコードを参考にCRC_16_IBM( CRC_16_USB )を計算した結果も記載しました。

またCRCモジュール演算、 CPU演算、CPUルックアップ演算の比較を抜粋します

実行サイクルが700サイクルを超えているアルゴリズムはビット逆順アルゴリズム関数 ReverseBitOrder() を実行しているためです。
Microchipのデータシートに乗っているアルゴリズムでは830サイクル程かかっておりましたが、Bit Twiddling Hacksのアルゴリズムの一つを使用すると220サイクル程に低減しました。他のルックアップテーブルを使用する方法などは試していませんが、更に低減可能かもしれません。
今回は様々なCRCアルゴリズムを検証するため、各パラメータの初期値を毎回設定( CRC_Set_Parameter()関数)しております。(220サイクル)
前回と同一のアルゴリズムを使用するのであれば、引数のアルゴリズム名に「CRC_INHERIT」を指定すれば前回のパラメータが引き継がれます。上記関数のコールは初期に1度だけで良く、110サイクル程度は低減可能です。
所見
(fig.6)(fig.7)の結果より、
4byte、16byteともCPUのルックアップテーブルを用いた方が、CRCモジュールより速い
という事が分かりました。しかしながら4byteでは80%ほど速いのに対し、16byteでは42%と差が縮まっています。これはCRC演算を行う前後の処理に時間がかかっているせいで、メインのCRC演算の部分に関してはハードウェアで行うため、この様な結果になっていると思われます。
今回はブロッキング処理でCRC演算が完了したかをチェックしていましたが、割り込みやステートマシン処理なので他の演算を行う事も可能なので、処理の仕方によってはもう少し縮まるかもしれません。


コメント