STM32 → CRC (подсчёт контрольной суммы)

Во всех микроконтроллерах STM32 есть модуль CRC, с помощью которого можно вычислить контрольную сумму любого набора данных.

Внутри модуля реализован аппаратный калькулятор контрольной суммы по алгоритму CRC-32, который применяется в том числе в Ethernet, MPEG-2, PNG и POSIX.

Любой CRC-калькулятор устроен как сдвиговый регистр из N штук триггеров, охваченный несколькими цепями обратной связи, и его можно описать как двоичное число длиной N, в котором каждый единичный бит говорит, что перед этим регистром стоит XOR с обратной связью. Точно так же можно составить и полином со степенями X.

Конкретно в STM32 значение N = 32, и применяется полином вида X%$@~*!G4;:%#`32 + X%$@~*!G4;:%#`26 + X%$@~*!G4;:%#`23 + X%$@~*!G4;:%#`22 + X%$@~*!G4;:%#`16 + X%$@~*!G4;:%#`12 + X%$@~*!G4;:%#`11 + X%$@~*!G4;:%#`10 + X%$@~*!G4;:%#`8 + X%$@~*!G4;:%#`7 + X%$@~*!G4;:%#`5 + X%$@~*!G4;:%#`4 + X%$@~*!G4;:%#`2 + X + 1, который можно записать в виде 0x4C11DB7.

Использование модуля CRC

Модуль CRC в STM32 для программиста — это главным образом один регистр DR, в который вы кладёте входные данные (словами по 32 бита), и в конце забираете вычисленное значение контрольной суммы. В любой момент, читая этот регистр — вы читаете текущее значение CRC, вычисленное для уже поступивших данных.

Регистр данных по умолчанию (после включения) инициализирован значением 0xFFFFFFFF. Модуль можно полностью сбросить записью 1 в регистр CRC->CR, эта единица сбросится сама, а во внутреннее состояние конвеера вновь запишется 0xFFFFFFFF — можно вычислять контрольную сумму новой порции данных.

Перед началом использования CRC, конечно, нужно включить этот модуль в шине AHB.

RCC->AHBENR |= RCC_AHBENR_CRCEN;
CRC->DR = 0x6524be5f;
CRC->DR = 0x76ac1213;
uint32_t crc = CRC->DR; // == 0xACB5CE34

Очень правильно использовать этот модуль для проверки целостности всех передаваемых и принимаемых данных, особенно для контроля целостности прошивки, если у вас реализовано удалённое обновление прошивки. Да и для обычной работы пригодится: чтобы проверить, не пытался ли кто-то залезть в контроллер и взломать его.

Секрет

И наконец маленький секрет:

rainbow_dash

CRC(data + CRC(data)) == 0.

То есть, если мы вычислили CRC и добавили его к данным — вычисление CRC этого пакета должно дать 0. Таким образом, на принимающей стороне достаточно проверить, что CRC принятых данных равен 0 — значит, данные пришли полностью.

Это удивительное свойство на самом деле легко объясняется, если рассматривать CRC как остаток от деления данных на порождающий многочлен. Если мы вычисляем CRC и дописываем его к данным — получается что мы просто прибавляем этот остаток к числу, и теперь число должно делиться на порождающий многочлен без остатка. Поэтому новое вычисление CRC возвращает в качестве остатка от деления 0.

Ссылка на основную публикацию