Jump to content

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

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

Recommended Posts

9 часов назад, MasterElectric сказал:

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

Я этого нигде не предлагал.

Подход в стиле С++ предполагает описание класса CRC32 с некоторым набором публичных методов и приватных данных. Для расчета создаем объект класса (локально), вызываем нужные нам методы, получаем результат. При выходе из области видимости, объект автоматически освобождает занимаемую им в стеке память. Понадобилось посчитать CRC в другом месте - создали там локальный объект, использовали его, он снова разрушился при выходе из области видимости и т.д.

9 часов назад, MasterElectric сказал:

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

Областью видимости, очевидно. Глобальную переменную может поменять кто угодно в любой момент времени. Никто не может гарантировать её неизменности между вызовами функции. Кто мешает поменять её, например, в обработчике прерывания или в любой другой функции? А локальную статическую переменную может изменить только та функция, в которой она определена. Она гарантированно останется неизменной от выхода из функции до следующего входа в неё.

Share this post


Link to post
Share on other sites
24 minutes ago, Darth Vader said:

Подход в стиле С++ предполагает описание класса CRC32 с некоторым набором публичных методов и приватных данных. Для расчета создаем объект класса (локально), вызываем нужные нам методы, получаем результат. При выходе из области видимости, объект автоматически освобождает занимаемую им в стеке память. Понадобилось посчитать CRC в другом месте - создали там локальный объект, использовали его, он снова разрушился при выходе из области видимости и т.д.

А почему это нельзя сделать простой функцией?

Share this post


Link to post
Share on other sites
14 минут назад, Tpeck сказал:

А почему это нельзя сделать простой функцией?

Можно, я даже пример выше привёл полного расчёта одной функцией.

Но, иногда требуется большая гибкость в расчёте. Самый простой пример - посчитать СRC области памяти с разрывами. Т.е надо посчитать от А до Б, потом, не сбрасывая расчет, продолжить с В до Г и т.д. И вот тогда одной функцией уже не обойдешься. Нужно семейство взаимосвязанных функций, имеющих доступ к общему набору данных, скрытому от всей другой программы. А это уже класс С++ в чистом виде.

Share this post


Link to post
Share on other sites

Когда требуется считать CRC данных с "разрывами", то в функцию, выполняющую расчёт CRC, дополнительным параметром можно передать CRC, которое было рассчитано для предыдущего блока данных. И так повторить для требуемого количества блоков.

Share this post


Link to post
Share on other sites
7 минут назад, ivan24190 сказал:

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

Можно и так.

Я просто обратил внимание автора топика на то, что делать так, как он некрасиво. Общие для его функций данные не должны быть видны никому, кроме этих функций. Их надо скрыть. И вот мы не спеша приходим к концепции класса.

Share this post


Link to post
Share on other sites

Слегка модифицировав предыдущий пример функции расчета, можно получить такую, которой можно считать данные с разрывами

#include <stdint.h>


//--------------------------------------------------------------------------------------------------------------------------	
// Тип расчёта: начать новый или продолжить старый
//--------------------------------------------------------------------------------------------------------------------------	
typedef enum {
  CALC_NEW,
  CALC_CONTINUE
} CalcVariant_t;


//--------------------------------------------------------------------------------------------------------------------------	
// Функция расчёта КС CRC-32
// obj_p - указатель на объект
// len - размер объекта в байтах
// variant - тип расчёта: начать новый или продолжить старый
//--------------------------------------------------------------------------------------------------------------------------	
uint32_t calc(const void *obj_p, uint32_t len, CalcVariant_t variant) {
  // Таблица предвычисленных констант для быстрого расчёта
  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
  };
  
  static uint32_t CurrVal = 0xFFFFFFFF;                 // текущее накопленное значение суммы
  const uint8_t   *CurrByte_p  = (const uint8_t*)obj_p; // указатель на текущий байт данных
  
  if(variant==CALC_NEW) {
    CurrVal = 0xFFFFFFFF;                               // для нового расчёта сбрасываем накопленную сумму
  }
  
  while (len--) {
    CurrVal = (CurrVal >> 8) ^ Crc32Table[(CurrVal ^ *CurrByte_p++) & 0xFF];
  }
  
  return ~CurrVal;                                      // возвращаем значение CRC32, как инверсии накопленной суммы
};

Хорошо видно, зачем нужны локальные статические константы и переменные.

Share this post


Link to post
Share on other sites
4 hours ago, Darth Vader said:

для нового расчёта сбрасываем накопленную сумму

Я бы просто начальное значение передавал... Избавив себя от головной боли про хранимое состояние. И про thread-safe. Оно или начальное или результат расчета про предидущему сегменту.

Edited by GenaSPB

Share this post


Link to post
Share on other sites
3 часа назад, MasterElectric сказал:

нужно еще улучшать

#include "crc32.h"


//--------------------------------------------------------------------------------------------------------------------------	
// Функция расчёта КС CRC-32
// obj_p - указатель на объект
// len - размер объекта в байтах
// start_val - начальное значение для расчёта: 
//  - для начала нового надо передать 0
//  - для продолжения предыдущего надо передать предыдущее значение КС
//--------------------------------------------------------------------------------------------------------------------------	
uint32_t calc(const void *obj_p, uint32_t len, uint32_t start_val) {
  // Таблица предвычисленных констант для быстрого расчёта
  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
  };
  
  start_val = ~start_val;                               // начальное значение суммы для расчёта
  const uint8_t   *CurrByte_p  = (const uint8_t*)obj_p; // указатель на текущий байт данных
  // Накапливаем значение
  while (len--) {
    start_val = (start_val >> 8) ^ Crc32Table[(start_val ^ *CurrByte_p++) & 0xFF];
  }
  
  return ~start_val;                                    // возвращаем значение CRC32, как инверсии накопленной суммы
};

Это потоково-безопасный вариант, за счет отказа от статической локальной переменной, хранящей предыдущее рассчитанное значение. Теперь оно передаётся параметром. Собственно, это главное достоинство именно такой реализации перед предыдущей.

Стоит заметить, что вариант реализации через класс С++, о котором я говорил ранее, изначально по-определению потоково-безопасный. Там накапливаемая сумма является приватным членом класса. Если надо посчитать КС, то каждый поток создает свой локальный экземпляр класса. В результате потоки никак не влияют друг на друга, каждый из них использует и меняет только свои данные.

Share this post


Link to post
Share on other sites
On 3/25/2021 at 11:02 AM, Eddy_Em said:

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

Зачем на STM32 вычислять CRC программно?

 

Хороший вопрос !

Присоединяюсь.

Только почему-то его все, включая топик-стартера, проигнорировали :(

Share this post


Link to post
Share on other sites
2 минуты назад, dimka76 сказал:

Только почему-то его все, включая топик-стартера, проигнорировали :(

Не всегда возможно использовать встроенный, даже если он есть. Может быть полином не устраивает, а может например - аппаратный блок нереентерабелен. Или аппаратный CRC занят в данный момент. Мало ли почему.

Share this post


Link to post
Share on other sites

У меня например софтовый CRC потому что уже есть программа для формирования криптованных образов прошивок для раздачи заказчикам. И сразу закладываюсь что возможно новая версия изделия будет на другом процессоре (с отсутствующим или другим блоком CRC), чтобы не менять ПО у себя и Программу-загрузчик на ПК у заказчика.

Share this post


Link to post
Share on other sites

Ну я сразу давал ссылку на статью про аппаратный блок CRC, но судя по всему ТС нужен CRC для обновления прошивки, а свободного времени в бутлоадере 99%, тем более с аппаратным CRC при расчете CRC32 не все нормально. 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.