Запись образующего полинома CRC: прямая, зеркальная и Купмана
В даташите написано «полином 0x8005», в спецификации Modbus — «0xA001», в таблице Купмана — «0xC002», и всё это один и тот же CRC-16. Путаница с записью полинома — частая причина того, что контрольная сумма «не сходится» с устройством.
Обновлено Редакция GAW
Образующий полином CRC — многочлен по модулю 2, на который делят данные; остаток от деления и есть CRC. Для 16-битного CRC это многочлен 16-й степени, например x¹⁶ + x¹⁵ + x² + 1. Его коэффициенты записывают как двоичное число, и есть три распространённых способа это сделать — отсюда путаница.
Три записи одного полинома
| Запись | Правило | x¹⁶ + x¹⁵ + x² + 1 | x¹⁶ + x¹² + x⁵ + 1 |
|---|---|---|---|
| Полная | все члены, включая старший | 0x18005 | 0x11021 |
| Прямая (нормальная) | без старшего члена | 0x8005 | 0x1021 |
| Зеркальная (reversed) | прямая, биты в обратном порядке | 0xA001 | 0x8408 |
| Купмана | полная, сдвинутая вправо на 1 (без +1) | 0xC002 | 0x8810 |
Прямую запись использует каталог RevEng и большинство даташитов. Зеркальную — программы, которые сдвигают регистр вправо и обрабатывают младший бит первым; так написан пример расчёта в спецификации Modbus: «XOR с полиномом 0xA001». Нотация Купмана появилась в его исследованиях полиномов: старший член там сохранён, а обязательный младший +1 подразумевается, чтобы значение помещалось в слово разрядности CRC.
Полином — ещё не весь алгоритм
По модели параметров, описанной в термине CRC, кроме полинома нужны начальное значение регистра, отражение входа и результата и финальный XOR. В каталоге RevEng на каждый из двух популярных полиномов приходится по нескольку стандартов:
| Алгоритм | Полином | Init | Отражение | Контрольное значение |
|---|---|---|---|---|
| CRC-16/MODBUS | 0x8005 | 0xFFFF | да | 0x4B37 |
| CRC-16/ARC | 0x8005 | 0x0000 | да | 0xBB3D |
| CRC-16/IBM-3740 (CCITT-FALSE) | 0x1021 | 0xFFFF | нет | 0x29B1 |
| CRC-16/XMODEM | 0x1021 | 0x0000 | нет | 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.
Источники
- 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¹⁶
- 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
- P. Koopman. CRC Polynomial Zoo — Notes (Carnegie Mellon University) — в таблицах Купмана полином записан с неявным +1: старший член сохранён, младший (+1) отброшен — так значение помещается в машинное слово; пример CRC-8: (0xEA; 0x1D5) — неявная и явная запись одного полинома, 0xAB — его зеркальная запись с неявным +1; зеркальные полиномы имеют одинаковые хэмминговы веса
Нашли ошибку?
Смотрите также
- CRCЦиклический избыточный код для обнаружения ошибок
- Калькулятор CRCCRC-8, CRC-16, CRC-32, Modbus, блок CRC STM32, код на C
- Контрольная суммаПроверочное значение по данным: простая сумма, LRC, Internet checksum, CRC
- Порядок байтовLittle-endian и big-endian в памяти и протоколах
- Modbus RTUКадр, паузы 3,5 символа, функции, регистры, CRC-16, RS-485, отладка