Вычисление контрольных сумм

Что такое контрольная сумма (CRC) и для чего она нужна, я думаю знают многие. Ну а если кто не знает, то напомню, что контрольная сумма это некоторое число которое получается в результате обработки по определённому алгоритму некоторого объёма данных. Главное свойство контрольной суммы заключается в том, что она будет разной для двух массивов данных если они различаются хотя бы на один бит. Применяются контрольные суммы зачастую при передаче данных, для проверки целостности информации. Для расчета контрольных сумм применяются самые разнообразные алгоритмы, количество матана в которых превышает все разумные пределы. Именно поэтому применять мы их не будем, а пойдем другим путём. В контроллерах STM32 есть много полезной периферии, но ничего особо нового и необычного (например по сравнению с AVR) я не увидел. Лишь только одна штука меня немного приятно удивила и порадовала - аппаратная считалка контрольной суммы, и ей то мы сейчас и займемся.

Аппаратная это значит, что нам не нужно знать как оно там считается и тратить на это процессорное время. Мы просто записываем последовательно весь массив данных (контрольную сумму которого нам нужно посчитать) в определенный регистр, а потом из него же считываем результат, т.е.  работа с входными и выходными данными организована через один регистр (как в  UARTe).  Называется этот регистр CRC_DR, он 32-х битный. Более он ни чем не примечателен. Кроме него существует еще один регистр под названием CRC_IDR. Он восьмибитный, может хранить в себе любые данные, которые ни как не влияют на рассчет контрольной суммы. Его предназначение так и осталось для меня загадкой. И наконец третий регистр CRC_CR. Он существует ради одного бита который называется RESET. Установка этого бита в единицу сбрасывает считалку в исходное состояние. Нужно всегда устанавливать этот бит перед новым подсчётом CRC, ведь как я писал выше, для подсчёта контрольной суммы нужно последовательно писать в регистр CRC_DR данные. Именно поэтому есть вероятность что контрольная сумма посчитается не правильно, так как при подачи новой порции данных считалка не поймет что ей предлагают посчитать CRC для нового массива данных, а не продолжить расчет для предыдущего с добавлением новых данных. Ну да ладно, пора уже посчитать в качестве эксперимента контрольную сумму для каких-нибудь произвольных данных. 

 
 
#include "stm32f10x.h"
#include "stm32f10x_rcc.h"
 
//Функция для аппаратного подсчёта CRC32
//Принимает на вход указатель на массив uint32_t чисел и размер этого массива
//Возвращает CRC32 для этого массива
uint32_t crc_calc(uint32_t * buffer[], uint32_t buff_len) {
  uint32_t i;
  CRC->CR |= CRC_CR_RESET; //Делаем сброс...
  for(i = 0; i < buff_len; i++) {
    CRC->DR = buffer[i]; //Загоняем данные из буфера в регистр данных
  }
  return (CRC->DR); //Читаем контрольную сумму и возвращаем её
}
 

int main(void){
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE); //Включим модуль подсчета CRC
  uint32_t data[]= {0x5B27E2BE,0xFF2711BC,0xABA7EE00}; //Массив данных 
  uint32_t data_crc=crc_calc(&data,3); //Вычисляем CRC для массива данных
 
  while(1)
  {
  }
}

В результате после выполнения этого кода, в переменной data_crc значение стало 0x4b6b373e. Контрольная сумма посчиталась. При изменение любого байта контрольная сумма меняется тоже. На основании этого я сделал вывод что все работает как надо. Чисто с практической точки зрения применения этой штуковине я пока не нашел, но возможно оно понадобится мне в будущем.