MicroPython的午睡(95) STM32版、ハードウエアCRC32演算器の試用

Joseph Halfmoon

今回からSTM32版の独自部分、stmモジュール内に定義された定数を使ってSTM32のハードウエアを探っていきたいと思います。今回は一番簡単そうなところということでCRC32計算ペリフェラルを使ってみたいと思います。このペリフェラル、使用するのは簡単だけれど、検算がメンドイ。

※「MicroPython的午睡」投稿順 Indexはこちら

ST Microelectronics社製Nucleo-F401REボード上で使用しているSTM32版MicroPythonについてはこちら

STM32マイコンが搭載するCRC計算ハードウエア

データが通信途中で化けてないよねとか、最近では悪者にメモリを改ざんされてないだろうね、といった検査に有効なのがCRCです。不正なビットパターンであれば一撃で発見可能。単純といえば単純なアルゴリズムですが、頻繁に処理するとCPU負荷も馬鹿にならないということだと思います。STM32系のマイコンにはハードウエアの計算器が搭載されとります。

前々回、I2C接続のセンサ、AHT21Bを接続したときにCRC8(Maxim‐Dallas式)を計算するソフトウエアの関数を使いました。しかし以下のような事情で、このときはハードウエア計算器を使えなかったのです。

    1. STM32F401REが搭載するCRC計算ハードウエアは2つある
    2. 1個はCRC32(それも特性多項式などキメウチ)専用
    3. 1個はCRC8/16対応で特性多項式プログラミング可能だがSPI専用

I2CでCRC8には帯に短し襷に長しでした。なお、STM32でも機種によっては、CRC32がキメウチのハードウエアではなく、特性多項式など指定可能でよりフレキシブルな回路を搭載している機種があるようです。そっちだったら使えたかもしれないっすけど。。。

今回はこのCRC32ハードウエアをMicroPythonから直接制御してCRC32(STM32式)を計算してみたいと思います。

今回実験に使用したMicroPythonコード

STM32版のMicroPythonでは、stmモジュール内にハードウエア周辺回路のアドレスなどが格納されているので、それを使えばハードの制御も自由自在?です。

#STM32F401RE: CRC32
import stm
import time

def enableCRC32():
    stm.mem32[stm.RCC + stm.RCC_AHB1ENR] |= 0x1000

def resetCRC32():
    stm.mem32[stm.CRC + stm.CRC_CR] |= 0x1

def writeCRC32(arg):
    stm.mem32[stm.CRC + stm.CRC_DR] = arg

def readCRC32():
    return stm.mem32[stm.CRC + stm.CRC_DR]

def toUint32(arg):
    if arg > 0:
        return arg & 0xFFFFFFFF
    else:
        return ((abs(arg) ^ 0xFFFFFFFF) & 0xFFFFFFFF) + 1

def main():
    print("STM32F401RE CRC test.")
    print("stm.CRC: 0x{0:08x}".format(stm.CRC))
    print("stm.CRC_CR: 0x{0:08x}".format(stm.CRC_CR))
    print("stm.CRC_DR: 0x{0:08x}".format(stm.CRC_DR))
    enableCRC32()
    while True:
        resetCRC32()
        print("CRC32 (AFTER RESET): 0x{0:08x}".format(toUint32(readCRC32())))
        writeCRC32(0x34333231)
        writeCRC32(0x38373635)
        print("CRC32: 0x{0:08x}".format(toUint32(readCRC32())))
        time.sleep(1)
    # Normal End

if __name__ == "__main__":
    main()

今回のCRC計算ハードウエアは、RCCからのクロック供給をイネーブルにしてやれば即利用可能です。一連の計算を開始する初期化のときに resetCRC32()を呼び、その後、CRCを計算したいシーケンスの長さだけwriteCRC32()で32ビット幅の被検証データを書き込んで、最後readCRC32()で結果を読み出す、という塩梅です。書き込みについては自動でよきに計らってくれるみたいなので、ウエイトしなきゃとかそういう心配なしにガンガン連続書き込みしても大丈夫みたいっす。知らんけど。

今回はテストということでアスキー文字列に直すと “12345678”という8バイトについてCRC32を計算してます。

計算は出来たけれども結果を確かめるのに一苦労

上記のプログラムをNucleo-F401RE機上に書き込んで動作させたところが以下です。STM32CRC_result

黄色のマーカで印をしたところがCRC32計算の結果です。しかし、この数字、どうやって確かめたものか。CRC32といってもいろいろありーの。STM32F401REのハードウエアの「キメウチ」の値はちょっとクセが強いみたいです。適当なCRC計算機で計算した結果とは合わず。弱りました。自分で検証用のプログラムを書かないとならないの?

そうしたらありました。GitHubにSTM32用のクセのあるCRC32用の答え合わせができるツールが。あざーす。

STM32 CRC32 software calculation utility

上記からダウンロードさせていただいたツールで計算してみたところが以下に。STM32CRCcalculator

計算結果、一致しておりますな。いつもながらの泥縄。答えが出てから正解を調べるとな。

MicroPython的午睡(94) STM32版、Key割り込みで温度/湿度表示切替 へ戻る

MicroPython的午睡(96) STM32版、曜日表現、Thonnyとマニュアル相違? へ進む