CRCモジュールの使い方

CRCモジュールの使い方

概要

CRCとは

dsPIC33CHシリーズにはCRCモジュールがマスターコアに1ch搭載されています。このモジュールを使えば通信を行う時の通信エラー検出が容易に行えます。

CRCとは

CRCとは「Cyclic Redundancy Check」の頭文字をとった用語で、日本語では巡回冗長検査といい誤り検出符号の一種で主にデータ転送に伴うエラーの検出に使われています。

単純な加算方法のチェックサム方式に比べ高い誤り検出が可能ですが、誤りを修正する機能は有りません。

CRCに関して詳しくはここでは説明いたしませんが、私が解りやすいと感じたサイトを紹介します。

ペリフェラルの構造

CRCモジュールの概略ブロック図は以下のとおりです。データ入力は128bitサイズのFifoメモリを有しており、このサイズ以内であれば連続してデータが書き込めます。

(fig.1)CRCエンジン ブロックダイアグラム DS70005371D-page 651より抜粋
(fig.2)CRCエンジン DS30009729B_JP – p.10より抜粋

ハードウェア構成と制御ブロック

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

(fig.3)ブロック図

レジスタ

CRC関連のレジスタは以下の8種類です。

レジスタ名機能説明
CRCCONLCRC Control
Register Low
CRC制御レジスタ Low
CRCCONHCRC 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
(fig.4)CRC関連レジスタ

ソースコード

算出方法

①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計算サイト様で検算を行っておりますが、ソースをご利用の際はご自身で都度ご確認をお願いします。

(fig.5)検算結果

実行時間

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

(fig.6)デフォルトアルゴリズムの実行時間

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

(fig.7)CRC16-USBアルゴリズムの実行時間

実行サイクルが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演算が完了したかをチェックしていましたが、割り込みやステートマシン処理なので他の演算を行う事も可能なので、処理の仕方によってはもう少し縮まるかもしれません。

参考

参考文献

参考サイト

CRC検算サイト

コメント

タイトルとURLをコピーしました