El cálculo de redundancia cíclica (CRC) es fundamental para garantizar la integridad de los datos en protocolos de comunicación serie como el 1-Wire, utilizado por los sensores DS18B20 y DS18B22. Aunque habitualmente se explica este proceso mediante implementaciones en lenguaje C, es posible comprender profundamente su funcionamiento analizando la arquitectura de hardware subyacente basada en Registros de Desplazamiento con Retroalimentación Lineal (LFSR).
Para el polinomio utilizado por Maxim ($X^8 + X^5 + X^4 + 1$), la estructura de hardware consiste en una serie de flip-flops y compuertas XOR dispuestas estratégicamente. A continuación, se presenta una implementación en Verilog que modela este comportamiento de forma estructural.
// Módulo de Flip-Flop tipo D básico con reset asíncrono
module d_flip_flop (
input wire clk,
input wire rst_n,
input wire d_in,
output reg q_out
);
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
q_out <= 1'b0;
else
q_out <= d_in;
end
endmodule
// Calculador de CRC-8 basado en la arquitectura de hardware de Maxim
module crc8_engine (
input wire serial_in,
input wire clk,
input wire rst_n,
output wire [7:0] crc_state
);
wire fb; // Bit de retroalimentación
wire node_tap1, node_tap2;
// El bit de feedback se genera mediante la XOR entre la entrada y el bit menos significativo
assign fb = serial_in ^ crc_state[0];
// Conexiones de los nodos XOR según el polinomio X^8 + X^5 + X^4 + 1
assign node_tap1 = fb ^ crc_state[3]; // Tap en la posición del bit 2
assign node_tap2 = fb ^ crc_state[4]; // Tap en la posición del bit 3
// Instanciación de la cadena de registros
d_flip_flop ff7 (.clk(clk), .rst_n(rst_n), .d_in(fb), .q_out(crc_state[7]));
d_flip_flop ff6 (.clk(clk), .rst_n(rst_n), .d_in(crc_state[7]), .q_out(crc_state[6]));
d_flip_flop ff5 (.clk(clk), .rst_n(rst_n), .d_in(crc_state[6]), .q_out(crc_state[5]));
d_flip_flop ff4 (.clk(clk), .rst_n(rst_n), .d_in(crc_state[5]), .q_out(crc_state[4]));
d_flip_flop ff3 (.clk(clk), .rst_n(rst_n), .d_in(node_tap2), .q_out(crc_state[3]));
d_flip_flop ff2 (.clk(clk), .rst_n(rst_n), .d_in(node_tap1), .q_out(crc_state[2]));
d_flip_flop ff1 (.clk(clk), .rst_n(rst_n), .d_in(crc_state[2]), .q_out(crc_state[1]));
d_flip_flop ff0 (.clk(clk), .rst_n(rst_n), .d_in(crc_state[1]), .q_out(crc_state[0]));
endmodule
En esta implementación, el diseño refleja fielmente el flujo de datos serie. Dado que los dispositivos 1-Wire transmiten el bit menos significativo (LSB) primero, el banco de pruebas debe manejar la secuencia de entrada respetando este orden. Al procesar una trama de datos que incluye su propio CRC al final, el estado resultante de los registros debe ser exactamente cero si no existen erores de transmisión.
Para verificar el diseño, se puede utilizar el siguiente banco de pruebas (testbench) que inyecta una trama de 64 bits (típica en la lectura de la ROM o del scratchpad de un DS18B20):
module tb_crc_maxim;
reg clk_sys;
reg reset_n;
reg data_bit;
wire [7:0] current_crc;
// Trama de ejemplo (incluyendo el byte de CRC al final)
// Representada de LSB a MSB
reg [0:63] stream_data = 64'b0100010011110000110110111110010000000000000000000000000010010110;
crc8_engine dut (
.serial_in(data_bit),
.clk(clk_sys),
.rst_n(reset_n),
.crc_state(current_crc)
);
// Generación de reloj
always #5 clk_sys = ~clk_sys;
integer idx;
initial begin
clk_sys = 0;
reset_n = 0;
data_bit = 0;
#15 reset_n = 1;
for (idx = 0; idx < 64; idx = idx + 1) begin
@(posedge clk_sys);
data_bit = stream_data[idx];
$display("Tiempo: %t | Bit: %b | CRC: %b", $time, data_bit, current_crc);
end
#20;
if (current_crc == 8'h00)
$display("Verificación exitosa: El CRC es válido.");
else
$display("Error detectado: El CRC no coincide.");
$stop;
end
endmodule
Al ejecutar la simulación, se observa cómo el registro evoluciona bit a bit. Si la secuencia de entrada es correcta y el último byte procesado corresponde al CRC generado por el transmisor, el sistema de hardware convergerá a cero. Este enfoque no solo es eficiente en términos de recursos para implementaciones en FPGA o ASIC, sino que también elimina la necesidad de tablas de búsqueda (Look-up Tables) extensas que suelen requerirse en implementaciones de software optimizadas.
La visualización de este circuito en herramientas de síntesis permite confirmar que la estructura de registros de desplazamiento se mapea correctamente a los recursos lógicos del silicio, manteniendo la coherencia con el diagrama lógico del fabricante.