Я пытаюсь рассчитать CRC однобайтового ввода данных, используя блок вычисления CRC stm32l152.
Блок CRC принимает только 32-битные входные данные. Мне удалось рассчитать CRC для ввода 32-битных данных, но теперь я изо всех сил пытаюсь заставить его работать для ввода байтовых данных.
Мои тестовые входные данные 0x20
, и я ожидаю, что на выходе 0xD62B0954
Параметр CRC: полином 0x04C11DB7
, инициализация: 0xFFFFFFFF
Как я могу решить эту проблему, у меня заканчиваются идеи?
Пример кода для 32-битных данных:
CRC->DR = u32Input`
u32Crc = CRC->DR;
Я также нашел этот фрагмент кода для побайтового вычисления CRC, но результат отличается.
static uint32_t crc32_step(uint32_t crc, uint8_t data)
{
crc = ~crc ^ data;
CRC->DR = (~CRC->DR) ^ __RBIT(~(crc << 24));
return (crc >> 8) ^ ~__RBIT(CRC->DR);
}
Я получаю следующий вывод, используя приведенный выше код с предоставленным CRC 0xFFFFFFFF
: 0xC491DF37
Я не очень понимаю, что делает функция crc32_step
, но я даже не уверен, что это правильное направление.
Буду очень признателен за любые подсказки или идеи.
Блок CRC в stm32 использует CRC32? если да, то не слишком ли использовать его для однобайтовой проверки? Как упоминает @IanAbbott, я бы выбрал программную реализацию с таблицей или без нее.
@armengedon Я согласен, что это было бы немного излишеством, но это только часть истории. На самом деле я сначала использую модуль CRC для вычисления 32-битных фрагментов данных, и только для оставшихся байтов, которые не составляют двойное слово, мне нужно решение для побайтового вычисления. Программное решение кажется жизнеспособным решением. Желательно без таблицы поиска, в безопасную память. Падение производительности не должно быть слишком большим, потому что макс. 3 байта для расчета. КПР от.
Для вычисления CRC порциями (например, ноль или более «аппаратных» порций, за которыми следует ноль или единица, замыкающая «программная» порция), некоторые реализации CRC могут потребовать, чтобы биты CRC были объединены XOR со значением «все единицы» (т. -flipped) между фрагментами и/или после последнего фрагмента.
Пожалуйста, предоставьте CRC 32-битных данных и этих данных. Это могут быть любые данные. Устройство можно настроить для вычисления широкого диапазона возможных CRC.
Вычисляемый CRC выглядит как CRC-32/MPEG2. Вот простой код на C для его вычисления:
#include <stddef.h>
#include <stdint.h>
uint32_t crc32mpeg2(uint32_t crc, void const *mem, size_t len) {
unsigned char const *data = mem;
if (data == NULL)
return 0xffffffff;
while (len--) {
crc ^= (uint32_t)(*data++) << 24;
for (unsigned k = 0; k < 8; k++)
crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
}
return crc;
}
Подпрограмма вызывается с NULL
для mem
, чтобы получить начальное значение CRC. Таким образом, он будет использоваться следующим образом:
#include <stdio.h>
int main(void) {
unsigned char data[1] = { 0x20 };
uint32_t crc = crc32mpeg2(0, NULL, 0);
crc = crc32mpeg2(crc, data, 1);
printf("%08x\n", crc);
return 0;
}
Результат:
d62b0954
Спасибо за ваш код, он отлично работает. Вы правы в предположении CRC-32/MPEG2. Я приму этот ответ, так как он решает мою проблему. Кажется, нет решения с использованием модуля CRC.
Программное решение должно быть адекватным для одного-трех байтов. Если вы можете позволить себе 1 КБ памяти для таблицы, вы можете сделать ее немного быстрее, если это необходимо.
Самый эффективный способ вычисления CRC в программном обеспечении — использовать таблицу и выполнять вычисления по восемь битов за раз. Ниже приведена таблица, позволяющая их рассчитать:
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
static uint32_t crc32mpeg2_table[] = {
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4,
};
uint32_t crc32mpeg2(uint32_t state, uint8_t *buff, size_t buff_sz)
{
while (buff_sz-- > 0) {
int index = (state >> 24) ^ *buff++;
state <<= 8;
state ^= crc32mpeg2_table[index];
}
return state;
}
/* this main() function to demonstrate that the crc
* applied to a string with a single space character works */
int main()
{
uint8_t buff[] = { 0x20 };
uint32_t crc = crc32mpeg2(0xffffffff, buff, sizeof buff);
printf("0x%08x\n", crc);
}
Как видите, результатом после применения его к вашему входному буферу является ожидаемое значение:
$ ./crcmpg3
0xd62b0954
$ _
Чтобы создать таблицу, вы можете просто запустить алгоритм, предложенный Марком Адлером (@MarkAdler) в его ответе, для полного набора возможных входных байтов (от 0x00
до 0xff
), как в:
#include <stddef.h>
#include <stdio.h>
#include <stdint.h>
/* this is the function provided by Mark in his response */
uint32_t crc32mpeg2(uint32_t crc, void const *mem, size_t len) {
unsigned char const *data = mem;
if (data == NULL)
return 0xffffffff;
while (len--) {
crc ^= (uint32_t)(*data++) << 24;
for (unsigned k = 0; k < 8; k++)
crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
}
return crc;
}
int main()
{
int i;
char *sep = "uint32_t crc32mpeg2_table[] = {\n\t";
for (i = 0; i < 256; i++) {
status = crc32mpeg2(i & 0xff, &ch, sizeof ch);
printf("%s0x%08x", sep, status);
sep = i % 8 == 7 ? ",\n\t" : ", ";
}
printf("\n};\n");
}
Это создаст таблицу выше. Когда у вас есть таблица, вам просто нужно использовать эту функцию (гораздо быстрее, так как вы работаете с одним полным байтом за итерацию), чтобы получить результат:
uint32_t crc32mpeg2(uint32_t state, uint8_t *buff, size_t buff_sz)
{
while (buff_sz-- > 0) {
int index = (state >> 24) ^ *buff++;
state <<= 8;
state ^= crc32mpeg2_table[index];
}
return state;
}
Правильное использование функции состоит в том, чтобы вызвать ее, передав старое состояние (которое представляет собой CRC до последнего обработанного байта), чтобы получить новое состояние (новый CRC после обработки новой группы байтов). Первое значение для состояния должно быть инициализирован 0xffffffff
, поэтому для вычисления CRC "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
вы можете использовать этот main:
#include <string.h>
#include <stddef.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
int main()
{
/* first piece */
char *s = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, ";
uint32_t crc = crc32mpeg2(0xffffffff, s, strlen(s)); /* intialize with 0xffffffff */
printf("CRC(\"%s", s);
/* second piece */
s = "sed do eiusmod tempor incididunt ut labore et dolore ";
crc = crc32mpeg2(crc, s, strlen(s));
printf("%s", s);
/* third piece */
s = "magna aliqua.";
crc = crc32mpeg2(crc, s, strlen(s));
printf("%s\") => ", s);
/* print crc of the whole string */
printf("0x%08x\n", crc);
}
который должен вывести:
$ crcmpg3.c
CRC("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.") => 0x81e9201f
$ _
Существует даже способ предварительно вычислить таблицу (таблицы) препроцессором. Я сделал это для нескольких компиляторов C, но, к сожалению, исходный код закрыт.
Вам понадобится некоторый код для отката эффектов конечных 24 нулевых битов. Однако, вероятно, было бы проще вычислить CRC в программном обеспечении (или использовать эту программную процедуру для обновления CRC для конечных байтов блока, длина которого не делится на 4). Программные подпрограммы CRC часто используют справочную таблицу для ускорения, но могут быть реализованы без справочной таблицы путем индивидуальной обработки каждого бита данных.