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

Помогите по CRC32. На компьютерном Си работает, в микроконтролере дает неверный результат

Считаю контрольную сумму 16-ти байт

Quote

01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

Формирую бинарный файл с этими данными, получаю результат 0xСECEE288(crc файла в Проводнике). Контроллер выдает 0x31311D77. Загнал алгоритм (код ниже) в C-Free компилятор. Тоже получил 0xСECEE288. Сравнил сформированные таблицы - одинаковые. Закипел.

Код формирования таблицы unsigned long crc_table[256]; Таблица глобальная

void Crc32Init(void)
{
unsigned long crc;
	for (int i = 0; i < 256; i++)								//инициализируем таблицу расчёта Crc32
		{
			crc = i;
			for (int j = 0; j < 8; j++)							//цикл перебора полинома
			crc = crc & 1 ? (crc >> 1) ^ 0xEDB88320UL : crc >> 1;
			crc_table[i] = crc;
		}
	inCRC = 0xFFFFFFFF;
}

Код самого подсчета

unsigned long int Crc32(unsigned char Byte)
{
	inCRC = (inCRC >> 8) ^ crc_table[(inCRC ^ Byte) & 0xFF];
	return inCRC ^ 0xFFFFFFFF;
}

inCRC - глобальная переменная unsigned long int inCRC = 0xFFFFFFFF; в которой накапливается сумма. Может подскажет кто, где я накосячил?

 

 

 

 

 

 

 

 

 

 

Изменено пользователем Димон Безпарольный

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 * 2, конечно, "сэм-восэм", но c 1 до 15 никак не 16 чисел, входные байты могут и "зеркалиться" относительно их середины.
А "если мы с вами посмотрим, то мы с вами увидим" ((с) моя школьная историчка): 0xСECEE288 инверсия 0x31311D77.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

8 hours ago, Obam said:

0xСECEE288 инверсия 0x31311D77

Точно инверсия. Буду разбираться откуда она берется. Сам алгоритм выдает на двух компиляторах данные без инверсии.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Нашел причину. Выполнение строки:

 

return inCRC ^ 0xFFFFFFFF;

Дает разный результат на компьютерном С++ и в камне. В камне return inCRC ^ 0xFFFFFFFF; и return inCRC; дает одинаковый результат! На компьютерном С++ - дает инверсию.

Так например Crc32(0x55); дает число 0x36fcb509 в камне независимо от варианта команды return. На С-Free на компьютере будет 0xC9034AF6 при команде  return inCRC ^ 0xFFFFFFFF; и 0x36fcb509 при команде return inCRC;

 

Почему в камне вычисление значения 0x36fcb509 ^ 0xFFFFFFFF; не инвертирует число, а на компьютере происходит инверсия? Подозреваю что что - то с разрядностью но не могу понять что.

Изменено пользователем Димон Безпарольный

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

14.01.2021 в 00:49, Димон Безпарольный сказал:

Может подскажет кто, где я накосячил?

Построение функций принципиально косячное. Не используйте в них глобальные переменные! Использование такого стиля дает сплошные побочные эффекты. Функции зависят черт-знает от чего и портят кучу всего в программе.

Всё необходимое для своей работы функция должна получать через параметры. Нужны дополнительные хранилища вспомогательных данных - используйте локальные переменные. Нужно, чтобы локальные переменные сохраняли значения между вызовами - делайте их локальными статическими.

По существу: как вы проверяли результат? Приведите полный текст тестовой программы. Вы, случаем, не значение вашей глобальной переменной inCRC32 проверяли?

А вот эта функция

14.01.2021 в 00:49, Димон Безпарольный сказал:

unsigned long int Crc32(unsigned char Byte)

мне вообще непонятна. Зачем считать CRC32 от одного байта? А еще её результат зависит от двух глобальных объектов программы, один из которых ещё и изменяется ей же самой. Просто набор штампов, как не следует писать программы.

Нормальные функции подсчета CRC32 произвольного объекта данных data размером size байт выглядят примерно так:

uint32_t Crc32(const void *data, uint32_t size);

Да, для платформонезависимости результата пользуйтесь именами типов из файла stdint.h. Иначе один и тот же ваш код будет давать разный результат на разных архитектурах: на 8-битных один, на 16-битных другой, на 32-битных третий, а на 64-битных четвертый.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, Darth Vader said:

Зачем считать CRC32 от одного байта?

Функция работает получая данные как с массивов, так и на лету с приема байт. Согласен что написано криво, надо причесать. Но это не решит проблемы потому что на глюк не похоже. Если инвертировать результат, функция считает CRC правильно на лету, из EEPROM 2580, из ФЛЭШ контроллера и еще бог знает откуда - проблем нет. Для проверки работы функции я написал вызов:

	Crc32Init();
	Crc32(0x55);

Так вот. В коде функции:

unsigned long int Crc32(unsigned char Byte)
{
	inCRC = (inCRC >> 8) ^ crc_table[(inCRC ^ Byte) & 0xFF];
	return inCRC ^ 0xFFFFFFFF;
}

Есть строка     return inCRC ^ 0xFFFFFFFF;. Она ничего не меняет. Т.е. возвращаемый результат будет тем же, что и при  return inCRC; Это в камне. Приходится дополнительно инвертировать результат чтобы совпало с вариантом на ПК. А вот в варианте на ПК return inCRC ^ 0xFFFFFFFF; как раз инвертирует результат как и должно быть. Что мне пока непонятно. Один и тот же код работает по разному.

 

Нашел причину. Вызов функции был неправильным. Правильно надо присваивать значение CRC локальной переменной uint32_t .  CRCSUM = Crc32(Chr); Тогда результат подсчета будет правильный. Всем спасибо за советы. Пошел причесывать код.

Изменено пользователем Димон Безпарольный

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, Darth Vader said:

Не используйте в них глобальные переменные!

Перед подсчетом CRC32 нужно вызвать Crc32Init(); Она в частности проинициализирует inCRC = 0xFFFFFFFF;. Переменная  inCRC используется в двух функциях. Поэтому она глобальна. Как тогда реализовать иначе?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, Димон Безпарольный сказал:

Как тогда реализовать иначе?

Сделать ОДНУ функцию, которая всё делает сама. 

Например так:

// Реализация функции расчёта CRC-32
// data_p - указатель на произвольный объект
// len - размер объекта в байтах
uint32_t Crc32(const void *data_p, uint32_t len) {
  static const uint32_t Crc32Table[256] = {
    0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
    0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
    0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
    0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
    0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
    0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
    0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
    0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
    0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
    0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
    0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
    0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
    0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
    0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
    0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
    0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
    0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
    0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
    0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
    0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
    0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
    0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
    0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
    0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
    0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
    0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
    0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
    0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
    0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
    0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
    0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
    0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
    0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
    0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
    0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
    0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
    0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
    0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
    0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
    0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
    0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
    0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
    0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
    0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
    0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
    0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
    0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
    0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
    0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
    0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
    0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
    0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
    0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
    0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
    0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
    0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
    0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
    0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
    0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
    0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
    0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
    0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
    0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
    0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
  };
    const uint8_t   *buf  = (const uint8_t*)data_p;
    uint32_t  crc   = 0xFFFFFFFF;
    
    while (len--) {
        crc = (crc >> 8) ^ Crc32Table[(crc ^ *buf++) & 0xFF];
    }
    return ~crc;
};

Это быстрый табличный расчёт CRC32 с полиномом 0x04C11DB7. Для другого полинома будут другие значения в массиве Crc32Table[256].

Взято отсюда.

Проведен небольшой рефакторинг: тип входного параметра-указателя для универсальности заменен на void*, константный массив спрятан внутрь функции, типы заменены на более конкретные.

Изменено пользователем Darth Vader

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

12 minutes ago, Darth Vader said:

Сделать ОДНУ функцию, которая всё делает сама. 

Спасибо. Хочу только заметить что мной пишется бутлоадер для камней с большим количеством ОЗУ. Ему неважно сколько ОЗУ будет съедено. Да и ПЗУ тоже. Но вот ПЗУ желательно поменьше. Чисто субъективно.

Также непонятно как налету считать CRC. Файл прошивки может быть гораздо больше чем ОЗУ. А вот потеря времени на расчет таблицы малозначительна. Принятые данные напрямую пишутся в 2580 и налету считается CRC. Данные пишутся по 256 байт за раз. Как вариант можно CRC считать тоже по 256 байт.

 

Изменено пользователем Димон Безпарольный

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

47 минут назад, Димон Безпарольный сказал:

Переменная  inCRC используется в двух функциях. Поэтому она глобальна.

Ситуация ничего не напоминает?

В С++ именно для таких ситуаций придуманы классы. Общие данные - это данные (поля) класса. Функции, оперирующие этими общими данными - это функции-члены класса. Так что в некоторых случаях, если нужна большая гибкость расчета, удобнее сделать класс CRC32.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 minute ago, Darth Vader said:

Ситуация ничего не напоминает?

В С++ именно для таких ситуаций придуманы классы. Общие данные - это данные (поля) класса. Функции, оперирующие этими общими данными - это функции-члены класса. Так что в некоторых случаях, если нужна большая гибкость расчета, удобнее сделать класс CRC32.

Код написан на Си.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

35 минут назад, Димон Безпарольный сказал:

Код написан на Си.

Код может быть написан на чем угодно. Один файл на Си, другой на С++, третий на ассемблере. Всё равно компилируются они раздельно. А линкеру всё равно, на чем были написаны исходные коды объектных модулей. Так что писать стоит на том, на чем удобней в данный конкретный момент.

Но уж если хочется чистого Си, то можно сделать закат солнца вручную и изобрести понятие класса и указателя this средствами Си:

- описываем тип структуры с полями-данными, необходимыми для работы всех функций

- во все функции добавляем в качестве первого параметра указатель на эту структуру с именем this

- внутри функций обращаетесь к необходимым общим данным через этот указатель this

- перед началом нового расчета создаете эту структуру. Причем она может быть как глобальной, так и локальной.

- вызываете ваши функции, передавая им в качестве первого параметра указатель на структуру.

 

Изменено пользователем Darth Vader

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

http://we.easyelectronics.ru/STM32/crc32-na-stm32-kak-na-kompe-ili-na-kompe-kak-na-stm32.html вот тух хорошо расписано почему так вышло)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 2/19/2021 at 9:29 PM, Darth Vader said:

В С++ именно для таких ситуаций придуманы классы.

да и ты чтобы сбросить CRC предлагаешь создавать новый экземпляр класса?

On 2/19/2021 at 6:46 PM, Darth Vader said:

Построение функций принципиально косячное. Не используйте в них глобальные переменные! Использование такого стиля дает сплошные побочные эффекты. Функции зависят черт-знает от чего и портят кучу всего в программе.

Всё необходимое для своей работы функция должна получать через параметры. Нужны дополнительные хранилища вспомогательных данных - используйте локальные переменные. Нужно, чтобы локальные переменные сохраняли значения между вызовами - делайте их локальными статическими.

Набор штампов как не следует давать советы, подробнее о побочных эффектах пожалуйста и чем это локальная статическая отличается от глобальной кроме зоны видимости? 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А можно задать нескромный вопрос: что за камень используется, если у него нет блока аппаратного вычисления CRC?

Зачем на STM32 вычислять CRC программно? Может, вы еще и БПФ будете вручную считать вместо использования fftw3?

 

Примера ради открываю RM на STM32F072. В регистр CRC_POL заносим полином. В CRC_CR - порядок бит, размер полинома и т.п. Что там сложного-то?

Изменено пользователем Eddy_Em

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...