PIC三昧(18) CRC、データ配列のCRC8をハードで計算、PIC16F18855

Joseph Halfmoon

前回は書き変えに便利で安心EEPROMを使ってみました。今回はFlashメモリのCRCをCPU使わずに計算することもできるCRCモジュールを使用してみます。Flashに対して使用すれば「改ざん」なども検出可能かも。ただし、今回はデータメモリの中の配列のCRC8をCPU制御で計算してもらいます。設定が分かり難い?

※『PIC三昧』PIC関係の記事総目次はこちら

※作業はMicroChip社の統合開発環境 MPLAB X IDEと、その上で走るコンフィギュレーションツールMCC Classic を使用して行っています。ターゲット・マイコンはPIC16F18855です。

Cyclic Redundancy Check(CRC) Module

CRCは通信の途中でビットが化けてんじゃねえか、とかいうときにその検出に威力を発揮いたします。すこし前に別シリーズのArmのマシン語命令で「2を法とする世界の多項式」に向き合いビビリましたが、まさにCRC計算に使うのがその多項式であります。まあCRCは頻繁に使うのでその度にビビっているわけにもいかず。機械的に計算して済ませるのみっす。

実はCRCモジュールには、メモリをスキャンするスキャナーが内蔵されておるということを知り、流石PIC16と感心。データメモリの上の配列をスキャンするのにスキャナーを使おうと野望を燃やしたのです。しかし失敗。なぜならば、

    • CRCスキャナーはFlashメモリに対してのみ働く
    • データメモリ上のオブジェクトの計算をする場合はCRCモジュールにCPUでデータを順次書き込め

ということみたいです。データシートよく読んだら書いてありました。トホホ。。

今回計算してみるCRCは、CRC8です。ハードウエア的にはCRC16も計算できるのですが、ビット幅が狭い方が簡単だし。

例によってCRC8にもいろいろあり、なのであります。今回成り行きで設定したものは、「CRC業界」じゃCRC-8/DVB-S2というお名前で知られているものみたいです。MPLAB X IDEのMCCクラシックからCRC8を設定したときに「プリディファイン」かつ「デフォルト値のまま」が「たまたま」それだった、というだけのことです。

相当前にAHT21B温湿度センサのデータ検査に旧MAXIM社方式のCRC-8をMicroPythonで計算したことがありましたが、それとは多項式が違います。なおPICマイコンのCRCモジュールは汎用性が高いです。設定さえ間違わなければMAXIM社方式であろうとCCITTであろうとなんでも計算できるのではないかと思います。

MCC Classicでの設定

例によってリソースをプロジェクトに追加する必要があります。Resources

 

CRCを制御するためのAPIを自動生成してもらうためにCRCを追加。そして標準出力にPrintfしたいのでEUSARTも取り込んでおきます。

CRCの設定画面が以下に。Use Pre-defined Polynominalにチェックを入れ、プルダウンメニューからCRC-8を選択すると、「多項式」は0xD5になってました。各ビットがxのべき乗の項の係数を表しますが、そこには踏み込みませぬぞ。メンドイし。Seed(初期値ということでよいのかな)は0で良いみたい。この設定がCRC-8/DVB-S2ということかね(お名前からするとデジタルテレビ向けに昔開発されたもの?)CRCsetting

緑色のマーカ部分、CRC Calculationという機能があり、早とちりで「やったね」と思った私は馬鹿でした。ここに書き込んでCalculateボタンを押したら設定条件のCRCを自在に計算してくれる?と思ったら、設定例の1例くらいを表示してくれるだけのものみたいです。けっこうショボい機能。すみません。

なお赤のところにEnable Scannerというチェックボックスがあり、これにチェックを入れると、CPUの横でCRCモジュールが勝手にFlashメモリにアクセスしてCRCを計算してくれる機能が使えるようになります。一種DMA的な。CPUの邪魔にならないようになど、メモリアクセス方法などもいろいろ選択可能デス。ただし対象はFlashメモリだけなので、今回のようにデータメモリ上のデータをスキャンすることはできないみたいです。

念のため、ピンマネージャの設定が以下に。いつもと変わらん。pinMGR

自動生成された関数に一か所疑義あり

MCCクラシックは設定条件に合わせて一そろいのAPIを自動生成してくれるので、いつも助かってます。しかし、今回は1か所納得いかない部分あり。以下です。

CRCのInitialize用の関数で、ターゲットのビット長や多項式の次数を制御するためのDLEN、PLENの設定のところです。コメントアウトしてある

CRCCON1 = (0 << 4) | (7);

上記が自動生成されたコードです。しかし、これだと期待通りの結果が出ませぬ。そこで以下のようにベタに0x77を代入してます。なぜかは知らねど、こう変更すると結果オーライ。CRC_Initialize_CRCCON1

手抜きなテストプログラム

上記の修正以外はあまり頭を使っていない実験コードが以下に。

uint8_t calcCRC8(uint8_t* buf, int siz)
{
    CRC_Initialize();
    CRC_Start();
    for (int idx=0; idx < siz; idx++) {
        while(CRC_IsBusy());
        CRC_8BitDataWrite(buf[idx]);
    }
    while(CRC_IsBusy());
    return (uint8_t)CRC_CalculatedResultGet(NORMAL,0x00);
}

void main(void)
{
    SYSTEM_Initialize();
    INTERRUPT_GlobalInterruptEnable();
    INTERRUPT_PeripheralInterruptEnable();

    uint8_t test1[]={0x55, 0x66, 0x77, 0x88};
    uint8_t test2[]={0x01, 0x23, 0x45, 0x67, 0x89};
    
    while (1)
    {
        RA0 = 1;
        __delay_ms(1000);
        printf("TEST1 CRC=0x%02x\n", calcCRC8(test1, 4));
        RA0 = 0;
        __delay_ms(1000);
        printf("TEST2 CRC=0x%02x\n", calcCRC8(test2, 5));
    }
}

calcCRC8()関数に、CRC計算対象へのポインタとデータ長さを渡すとCRC8を計算してくれます。今回はCRC-8/DVB-S2ですが、MCCで設定する多項式や初期値などでどうとでもなります。

CRC期待値

CRCの期待値は、以前にもお世話になった以下のサイトで計算させていただきました。このサイト、よくできてます。中間結果も出力されるのが何気に便利。

CRC Calculator (Javascript)

まずは test1[]配列のCRC-8/DVB-S2test1_expectedValue

末尾をみれば0x56であると。

つづいてtest2[]配列のCRC-8/DVB-S2。test2_expectedValue

こんどは0x4Cでした。

実験結果

PIC16F18855にオブジェクトを書き込んで計算させた結果が以下にResults

期待値通りの結果がでてますな。

まさか自動生成のDLENの値が不適合とは思っていなかったので、ちょっと危なかったケド。

PIC三昧(17) EEPROM、データ書き込み&読み出し、PIC16F18855 へ戻る

PIC三昧(19) TEMP、チップの温度をADCで測定、PIC16F18855 へ進む