Соответствие CRC32 из STM32F0 и zlib

Я работаю над каналом связи между компьютером под управлением Linux и STM32F0. Я хочу использовать какое-то обнаружение ошибок для своих пакетов, и поскольку STM32F0 имеет CRC32 hw, а у меня есть zlib с CRC32 в Linux, я подумал, что было бы неплохо использовать CRC32 для моего проекта. Проблема в том, что я не получу одинаковое значение CRC для одних и тех же данных на разных платформах.

#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <zlib.h>

int
main(void)
{
  uint8_t byte0 = 0x00;
  uint32_t crc0 = crc32(0L, Z_NULL, 0);
  crc0 = crc32(crc0, &byte0, 1);
  printf("CRC32 value of %" PRIu8 " is: %08" PRIx32 "\n", byte0, crc0);
}

выводит CRC32 value of 0 is: d202ef8d, который совпадает с результатом на нескольких онлайн-калькуляторах.

Однако кажется, что какие бы настройки я ни использовал на STM32, я не могу получить тот же CRC. Я нашел блок-схему того, как CRC hw вычисляет свое значение в примечании к приложению от ST, но я не могу понять, как это делается в zlib.

Кто-нибудь знает, совместимы ли они?

[править 1] Оба они используют одно и то же значение инициализации и многочлен.

[править 2] Код STM32 относительно невостребован, поскольку он использует hw.

...
/* Default values are used for init value and polynomial, see edit 1 */
CRC->CR |= CRC_CR_RESET;
CRC->DR = (uint8_t)0x00;
uint32_t crc = CRC->DR;
...

person evading    schedule 21.01.2015    source источник
comment
Если версия STM32 дает неверный результат, вероятно, вам следует показать соответствующий код с результатами.   -  person user694733    schedule 21.01.2015
comment
Документ, который вы связали, сказал, что начальное значение в этой модели должно быть программируемым, но ваш код не инициализирует его. Также вы должны показать результат, который вы получите от этого.   -  person user694733    schedule 21.01.2015


Ответы (5)


Из документации видно, что ваш код STM32 не просто неинтересен - он скорее неполный. Из документации, чтобы использовать оборудование CRC, вам необходимо:

  1. Включите периферийные часы CRC через периферийное устройство RCC.
  2. Установите регистр данных CRC на начальное значение CRC, настроив регистр начального значения CRC (CRC_INIT). (A)
  3. Установите обратный битовый порядок ввода / вывода с помощью битов REV_IN [1: 0] и REV_OUT соответственно в регистре управления CRC (CRC_CR). (A)
  4. Установите размер полинома и коэффициенты с помощью битов POLYSIZE [1: 0] в регистре управления CRC (CRC_CR) и регистре полинома CRC (CRC_POL) соответственно. (B)
  5. Сбросьте периферийное устройство CRC с помощью бита сброса в регистре управления CRC (CRC_CR).
  6. Установите данные в регистр данных CRC.
  7. Прочтите содержимое регистра данных CRC.
  8. Отключите периферийные часы CRC.

Обратите внимание, в частности, на шаги 2, 3 и 4, которые определяют вычисляемую CRC. Они говорят, что в их примере rev_in и rev_out false, но для zlib crc они должны быть истинными. В зависимости от того, как реализовано оборудование, полином, вероятно, также потребуется перевернуть (0xedb88320UL). Начальный CRC должен быть 0xffffffff, а конечный CRC инвертирован, чтобы соответствовать zlib crc.

person Mark Adler    schedule 21.01.2015
comment
Подумать только, я бы получил ответ от самого крестного отца zlib, фантастика! CRC_INIT и Polynomial фактически совпадают с zlib по умолчанию. Это были rev_in, rev_out и последняя инверсия результата, которые привели меня к этому. Спасибо! - person evading; 22.01.2015
comment
К сожалению, это не работает на STM32F4xx. Он имеет регистр данных и бит сброса. Никакая другая конфигурация невозможна. - person curator23; 07.02.2019
comment
@ curator23 Ну ладно. Тем не менее, он использует правильный полином, но без изменения порядка, в котором обрабатываются биты. По-прежнему может быть преимущество использования аппаратной CRC по сравнению с программной CRC, если вы перевернете биты в байтах, которые вы передаете в CRC, а затем измените биты в результирующей CRC. - person Mark Adler; 07.02.2019
comment
@MarkAdler Да, в core_cmInst.h нашел инструкцию rbit «обратные биты» и ее макрос gcc __RBIT. Не будет работать с DMA, но это маловероятный сценарий. Я предполагаю, что вы можете предварительно перевернуть биты, а затем инициировать DMA, если хотите :) - person curator23; 14.02.2019

Реализация CRC32 на STM32Fx, похоже, не является стандартной реализацией CRC32, которую вы найдете во многих онлайн-калькуляторах CRC, и той, которая используется в zip.

STM32 реализует CRC32-MPEG2, который использует прямой порядок байтов и без окончательной маски переворота по сравнению с zip CRC32, который использует прямой порядок байтов и маску окончательного переворота.

Я нашел этот онлайн-калькулятор, который поддерживает CRC32-MPEG2.

Если вас больше интересуют другие алгоритмы CRC и их реализация, посмотрите эту ссылку .

PS: Драйвер HAL от STM поддерживает ввод в форматах байтов, полуслов и слов, и, похоже, они отлично работают для STM32F0x в v1.3.1

person Ayyala    schedule 10.06.2016
comment
К вашему сведению: вы можете настроить STM32F0 так, чтобы он выдавал вам CRC32 в формате zip, используя CRC_ReverseInputDataSelect(CRC_ReverseInputData_32bits); CRC_ReverseOutputDataCmd(ENABLE); в библиотеке stdperiph - я не смотрел на более новую библиотеку HAL. Вам просто нужно инвертировать результат, который вы читаете с оборудования. - person Greg; 31.07.2016

Я не тестировал это, но подозреваю, что на самом деле вы не делаете 8-битную запись на STM32.

Вместо этого вы, вероятно, выполняете запись на всю ширину регистра (32 бита), что, конечно, означает, что вы вычисляете CRC32 большего количества байтов, чем предполагалось.

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

person unwind    schedule 21.01.2015
comment
Да, фактически он генерирует str инструкцию. Вы знаете, как я заставляю arm gcc вместо этого генерировать strb инструкцию? - person evading; 21.01.2015
comment
Во-первых, убедитесь (прочитав документацию по ЦП), что он действительно может обновить CRC с помощью всего 8 бит данных. Я просмотрел документацию по аналогичному чипу, и там говорится, что модуль CRC32 является только 32-битным. Итак, разумный вариант - изменить тест zlib на обновление на четыре 0-байта и сравнить это. - person unwind; 21.01.2015
comment
8-битная проблема (strb) будет связана с тем, что CRC->DR определен как volatile uint32_t*, поэтому все обращения ориентированы на слова (независимо от того, что вы сделали), попробуйте преобразовать в volatile uint8_t* - person Greg; 30.07.2016

У меня были аналогичные проблемы с реализацией CRC в модуле CRC STM32, где окончательная контрольная сумма не соответствовала. Я смог исправить это, посмотрев на пример кода в stm32f30x_crc.c, который предоставляется с STMCube. В исходном коде есть функция для 8-битной CRC, которая использует следующий код

(uint8_t) (CRC_BASE) = (uint8_t) CRC_Data;

записать в регистр DR. Как указывалось ранее, строка CRC-> DR определяется как изменчивый uint32_t, который будет обращаться ко всему регистру. Было бы полезно, если бы ST более явно указывал на доступ к регистру DR, а не просто заявлял, что он поддерживает 8-битные типы.

person James Yau    schedule 04.01.2018

По моему опыту, вы не можете сравнить код CRC32 между выводом блока CRC STM32 с онлайн-калькулятором CRC32.

Пожалуйста, найдите мой калькулятор CRC32 для STM32 по этой ссылке .

Эта функция использовалась в моем проекте и оказалась верной.

person Enix    schedule 25.09.2016