Перейти к содержанию

Запись образующего полинома CRC: прямая, зеркальная и Купмана

В даташите написано «полином 0x8005», в спецификации Modbus — «0xA001», в таблице Купмана — «0xC002», и всё это один и тот же CRC-16. Путаница с записью полинома — частая причина того, что контрольная сумма «не сходится» с устройством.

Обновлено Редакция GAW

Образующий полином CRC — многочлен по модулю 2, на который делят данные; остаток от деления и есть CRC. Для 16-битного CRC это многочлен 16-й степени, например x¹⁶ + x¹⁵ + x² + 1. Его коэффициенты записывают как двоичное число, и есть три распространённых способа это сделать — отсюда путаница.

Три записи одного полинома

ЗаписьПравилоx¹⁶ + x¹⁵ + x² + 1x¹⁶ + x¹² + x⁵ + 1
Полнаявсе члены, включая старший0x180050x11021
Прямая (нормальная)без старшего члена0x80050x1021
Зеркальная (reversed)прямая, биты в обратном порядке0xA0010x8408
Купманаполная, сдвинутая вправо на 1 (без +1)0xC0020x8810

Прямую запись использует каталог RevEng и большинство даташитов. Зеркальную — программы, которые сдвигают регистр вправо и обрабатывают младший бит первым; так написан пример расчёта в спецификации Modbus: «XOR с полиномом 0xA001». Нотация Купмана появилась в его исследованиях полиномов: старший член там сохранён, а обязательный младший +1 подразумевается, чтобы значение помещалось в слово разрядности CRC.

Полином — ещё не весь алгоритм

По модели параметров, описанной в термине CRC, кроме полинома нужны начальное значение регистра, отражение входа и результата и финальный XOR. В каталоге RevEng на каждый из двух популярных полиномов приходится по нескольку стандартов:

АлгоритмПолиномInitОтражениеКонтрольное значение
CRC-16/MODBUS0x80050xFFFFда0x4B37
CRC-16/ARC0x80050x0000да0xBB3D
CRC-16/IBM-3740 (CCITT-FALSE)0x10210xFFFFнет0x29B1
CRC-16/XMODEM0x10210x0000нет0x31C3

Контрольное значение — CRC строки «123456789». Если реализация на нём совпала, параметры выбраны верно. Проверить можно в калькуляторе CRC, а порядок байтов результата в кадре — отдельный вопрос, см. порядок байтов: в Modbus RTU младший байт CRC идёт первым.

Частые вопросы

Почему в Modbus полином 0xA001, а в каталоге CRC — 0x8005?

Это один полином x¹⁶ + x¹⁵ + x² + 1. Каталог RevEng записывает его в прямом порядке без старшего бита — 0x8005. Modbus считает CRC младшим битом вперёд, сдвигая регистр вправо, и для этого нужна зеркальная запись тех же 16 бит — 0xA001.

Как перевести полином в нотацию Купмана?

Записать полином полностью, со старшим битом: для CRC-16 Modbus это 0x18005. Затем сдвинуть вправо на один разряд, отбросив младший +1: получится 0xC002. Купман выбрал такую запись, чтобы значение помещалось в слово той же разрядности, что и CRC.

Достаточно ли знать полином, чтобы совпасть с устройством?

Нет. CRC-16/MODBUS, CRC-16/ARC и CRC-16/USB используют один полином 0x8005, но разные начальное значение, отражение и финальный XOR, и результаты у них разные. Проверяют реализацию по контрольному значению для строки «123456789»: у CRC-16/MODBUS это 0x4B37.

Источники

  1. Modbus Organization. MODBUS over Serial Line: Specification and Implementation Guide V1.02 — прил. B: при расчёте CRC в RTU, если младший бит был 1, регистр складывают по XOR с полиномом 0xA001 (1010 0000 0000 0001); образующий полином 1 + x² + x¹⁵ + x¹⁶
  2. G. Cook. Catalogue of parametrised CRC algorithms with 16 bits, reveng.sourceforge.io — полином в прямой записи без старшего бита: CRC-16/MODBUS — poly 0x8005, init 0xFFFF, refin/refout true, check 0x4B37; CRC-16/ARC — 0x8005, init 0, check 0xBB3D; CRC-16/IBM-3740 (CCITT-FALSE) — 0x1021, init 0xFFFF, без отражения, check 0x29B1; CRC-16/KERMIT — 0x1021, отражение, check 0x2189; CRC-16/XMODEM — 0x1021, init 0, check 0x31C3
  3. P. Koopman. CRC Polynomial Zoo — Notes (Carnegie Mellon University) — в таблицах Купмана полином записан с неявным +1: старший член сохранён, младший (+1) отброшен — так значение помещается в машинное слово; пример CRC-8: (0xEA; 0x1D5) — неявная и явная запись одного полинома, 0xAB — его зеркальная запись с неявным +1; зеркальные полиномы имеют одинаковые хэмминговы веса

Нашли ошибку?