Многим известно что для защиты целостности передачи данных используется контрольная сумма. В общем случае используют известные методы CRC8,CRC16,CRC32 с разными полиномами. В некоторых контроллерах есть уже встроенные блоки подсчета CRC, но часто нужно самому софтово ее считать. И мне тоже понадобилось.
Физический смысл CRC - циклическая сумма остатков от деления байта (слова) на известный полином (8,16,32 бит). Википедия все красиво описывает. Когда-то я при передаче пакетов USART по воздуху так и писал
crc = (crc+data)%POLINOM;
и в конце пакета добавлял в передачу CRC.
Сам расчет контрольной суммы занимает определенное время, особенно деление. Для ускорения процесса используют таблицы с частным для нужного полинома. Я сейчас использую STM32. Там тоже тратится время на деление, но вот умножение делается за один такт!
Пришла идея заменить деление умножением с отбрасыванием "целой" части и приведением результата к нужному типу данных.
Получилась такая строка для CRC8:
crc = (uint8_t)(0xff & (((uint8_t)(0xff & (crc+data)))*POL));
где POL полином контрольной суммы,задается в дефайнах, у меня 0х31.
Все это компилируется в 5 ассемблерных команд и выполняется примерно за 8 тактов.
Передача проходит четко.Добавлено (15.02.2019, 07:45)
---------------------------------------------
Вот так выглядит обработчик прерывания USART для захвата пакета в 80 байт с преамбулой
void USART1_IRQHandler (void)
{
if (USART1->ISR & USART_ISR_RXNE) data = USART1->RDR;
if (rf_stat == 2)
{
rx_buf[r_ptr] = data;r_ptr++;
if(r_ptr > 80)
{
if (crc == rx_buf[80])rx_buf_rdy = 1; else rx_buf_rdy = 0;
crc = 0,r_ptr = 0,rf_stat = 0;
} else crc = (uint8_t)(0xff & (((uint8_t)(0xff & (crc+data)))*POL));
} else
if ((rf_stat == 1) && (data == 0xD4)) rf_stat++; else
if ((rf_stat == 0) && (data == 0x2D)) rf_stat++;
};
0x2D и 0xD4 старт пакета,rx_buf_rdy-флаг готовности,rf_stat - статус разбора пакета.