A diferencia de un Checksum (que solo suma los bytes), el CRC interpreta todo el mensaje como un gigantesco número binario y realiza una División Polinómica Módulo-2. El "residuo" de esa división es la firma CRC. Si un solo bit cambia en el viaje, la división matemática arroja un residuo completamente distinto, garantizando una tasa de detección de errores del 99.998%.
En el mundo físico, el CRC no se calcula con divisiones largas de CPU; se calcula con un circuito electrónico llamado LFSR. Es una cascada de Flip-Flops (Registro de desplazamiento) interconectados con compuertas XOR en posiciones específicas dictadas por un "Polinomio".
0x4C11DB7). Es brutalmente rápido y lo usaremos para verificar que todo nuestro Firmware OTA (Día 147) no se corrompió al guardarlo en la Flash.0x8005). Como el hardware del STM32F4 está fijo a 32-bits, tenemos que simular las compuertas lógicas XOR y los desplazamientos (Shifts) del circuito LFSR directamente en nuestro código C.Ejercicio 1: Implementaremos dos funciones. Primero, encenderemos el hardware CRC-32 del STM32 (que se alimenta del bus AHB1) para calcular la integridad de un sector de memoria Flash de forma instantánea. Segundo, escribiremos la función de software puro CRC-16 Modbus iterando bits y aplicando máscaras de bits (^= 0xA001) para blindar nuestras tramas RS485.
/**
* @file crc_integrity.c
* @brief Validación de Integridad mediante Hardware CRC32 y Software CRC16 (Modbus)
*/
#include "stm32f401xe.h"
#include <stdint.h>
#include <stdbool.h>
// =========================================================================
// 1. HARDWARE CRC-32 (Para integridad de Firmware OTA y Memoria Flash)
// =========================================================================
/**
* @brief Inicializa el Periférico de Hardware CRC interno del STM32
*/
void inicializar_crc_hardware(void) {
// El periférico CRC vive en el bus de alta velocidad AHB1
RCC->AHB1ENR |= RCC_AHB1ENR_CRCEN;
}
/**
* @brief Calcula el CRC-32 de un bloque de memoria usando silicio puro.
* ¡Es cientos de veces más rápido que hacerlo por software!
* @param data_ptr Puntero al arreglo de Palabras de 32 bits (Memoria Flash o RAM)
* @param length Cantidad de palabras de 32 bits a procesar
* @return uint32_t Firma CRC-32 resultante
*/
uint32_t calcular_crc32_hardware(uint32_t *data_ptr, uint32_t length) {
// 1. Resetear la unidad matemática del CRC a su valor inicial (0xFFFFFFFF)
CRC->CR |= CRC_CR_RESET;
// 2. Alimentar el monstruo matemático
// Inyectamos las palabras directamente en el registro de Datos (DR)
for (uint32_t i = 0; i < length; i++) {
CRC->DR = data_ptr[i];
}
// 3. El hardware ya hizo los cientos de shifts y XORs en 1 ciclo de reloj por palabra.
return CRC->DR;
}
// =========================================================================
// 2. SOFTWARE CRC-16 (Para protocolo industrial RS485 Modbus RTU)
// =========================================================================
/**
* @brief Simulación en Software del registro de desplazamiento LFSR para Modbus.
* Polinomio oficial: 0x8005. Como Modbus procesa el LSB primero,
* el algoritmo desplaza a la derecha y usa el polinomio reflejado: 0xA001.
*
* @param buffer Puntero a la trama de bytes (ej. [01][03][00][00][00][02])
* @param longitud Cantidad de bytes en la trama
* @return uint16_t Firma CRC-16
*/
uint16_t calcular_crc16_modbus(uint8_t *buffer, uint16_t longitud) {
// El estándar Modbus dicta que el registro inicie en puros '1's
uint16_t crc = 0xFFFF;
// Recorremos cada byte del mensaje
for (uint16_t pos = 0; pos < longitud; pos++) {
// 1. XOR del byte entrante contra el byte bajo del registro CRC
crc ^= (uint16_t)buffer[pos];
// 2. Desplazamos los 8 bits, simulando el reloj del hardware
for (int i = 8; i != 0; i--) {
// Si el bit menos significativo (el que va a "caerse") es 1
if ((crc & 0x0001) != 0) {
// Desplazamos y aplicamos la compuerta XOR polinómica (Feedback)
crc >>= 1;
crc ^= 0xA001;
}
else {
// Si es 0, simplemente desplazamos (No hay feedback)
crc >>= 1;
}
}
}
// Al terminar todos los bytes, la variable "crc" contiene el residuo (Firma)
return crc;
}
/**
* @brief Validador de Tramas Entrantes (Para usarse en Día 139)
*/
bool Modbus_Validar_CRC(uint8_t* paquete, uint16_t longitud_total) {
if (longitud_total < 4) return false; // Demasiado corto
// En una trama recibida, los últimos 2 bytes son el CRC que envió el Maestro.
// Calculamos el CRC de todos los bytes EXCEPTO los últimos dos.
uint16_t crc_calculado = calcular_crc16_modbus(paquete, longitud_total - 2);
// Extraemos el CRC que venía adjunto (Ojo: Modbus envía el CRC LSB primero)
uint16_t crc_recibido = (paquete[longitud_total - 1] << 8) | paquete[longitud_total - 2];
// Si la firma matemática encaja perfecto, el mensaje es 100% íntegro.
return (crc_calculado == crc_recibido);
}
int main(void) {
// inicializar_crc_hardware();
// Ejemplo de verificación de integridad al arrancar (Día 147 OTA)
// El sector 4 de la Flash almacena nuestra App. El primer valor es el tamaño, el segundo el CRC original.
// uint32_t *app_flash = (uint32_t*)0x08010000;
// uint32_t crc_calculado = calcular_crc32_hardware(&app_flash[2], app_flash[0]);
// if (crc_calculado != app_flash[1]) {
// // FIRMWARE CORRUPTO! Bloquear máquina.
// }
while(1) {
// Recepción Modbus...
// if (bandera_trama_rs485) {
// if (Modbus_Validar_CRC(rx_buffer, longitud)) {
// procesar_comando_modbus();
// } else {
// // LOG_WARN("Trama Modbus Corrupta - Ruido detectado");
// }
// }
}
return 0;
}
Objetivo del día: Certificación Criptográfica y Rechazo de Ruido Eléctrico.
El estándar RS485 (Día 138) protege tu red contra el ruido analógico usando voltajes diferenciales, pero siempre existe la posibilidad de que un rayo cercano o el chispazo gigante de un contactor electromagnético logre corromper la señal y cambiar un `0` por un `1` en pleno vuelo. En sistemas críticos (donde se mueve dinero o gas a presión), no puedes ejecutar una orden de apertura de válvula si tienes el más mínimo porcentaje de duda sobre la instrucción recibida.
Al dotar a tu software del algoritmo **Modbus CRC-16**, has cerrado la bóveda de la telecomunicación. Ahora, tu Despachador procesa cada mensaje entrante en su simulador matemático interno. Si el cálculo difiere del sello que venía al final del paquete, la máquina destruye el mensaje silenciosamente, evadiendo una orden potencialmente desastrosa. Adicionalmente, al activar el bloque de **Hardware CRC-32** del STM32, garantizas que si los transistores de tu memoria Flash envejecen (Wear-out) y un bit se corrompe mientras la máquina duerme, el equipo lo detectará al despertar y se negará a arrancar con código corrupto.
CRC-32. Esto descarga al CPU de miles de operaciones y es vital para verificar memorias Flash y rutinas de Bootloader (OTA).0x8005). Dado que la trama Modbus se transmite invirtiendo los bits (LSB first), el cálculo en software (C) se realiza desplazando el registro a la derecha (>> 1) y haciendo XOR contra el polinomio reflejado (0xA001).