Caso práctico: alarma watchdog de pulsos con ULX3S

Alarma watchdog de pulsos con ULX3S

Objetivo y caso de uso

Qué construirás: Una alarma de perro guardián (watchdog) de pérdida de pulso basada en hardware que monitorea continuamente una señal periódica de latido (heartbeat). Activa un zumbador piezoeléctrico audible y un LED visual con latencia determinista de submilisegundos si la señal se interrumpe dentro de un período de tiempo predefinido.

Por qué es importante / Casos de uso

  • Supervisión de sistemas embebidos: Monitorea una onda cuadrada de «latido» de una MCU, alertando instantáneamente a los operadores si el procesador falla o entra en un bucle infinito.
  • Automatización industrial: Detecta cintas transportadoras atascadas o maquinaria bloqueada monitoreando los pulsos de codificadores ópticos o magnéticos en busca de paradas inesperadas.
  • Monitoreo de seguridad: Valida la integridad física de la línea, detectando inmediatamente cables cortados o cables de sensores desconectados cuando un pulso continuo se silencia.

Resultado esperado

  • Un temporizador watchdog sintetizado en FPGA con detección de fallos precisa por ciclo (cycle-accurate).
  • Activación inmediata de GPIO de un LED y un zumbador piezoeléctrico ante la pérdida de pulso.
  • Conciencia de seguridad: Comprender que esta implementación educativa debe ser reemplazada por hardware de seguridad a prueba de fallos (fail-safe) certificado y redundante en entornos de producción reales.

Audiencia: Ingenieros de sistemas embebidos, Desarrolladores de FPGA; Nivel: Intermedio

Arquitectura/flujo: Un flanco de señal entrante reinicia un contador descendente de hardware interno de la FPGA. Si el contador llega a cero (por ejemplo, han transcurrido >50ms sin un pulso), un latch de alarma activa los GPIO de salida para accionar el zumbador y el LED.

Nota educativa de validación

Antes de publicar este caso, el contenido pasó la puerta automática de validación de Prometeo con estado PASS. Para este perfil FPGA/ULX3S, los bloques de Verilog sintetizable se comprobaron con Yosys (read_verilog) y el conjunto Verilog de diseño/test se revisó con Verilator. El validador también comprobó la estructura de los bloques de código, que los comandos usen opciones copiables con guiones ASCII, que no aparezcan stacks no soportados y que esté disponible la toolchain ULX3S/ECP5 (yosys, nextpnr-ecp5, ecppack, openFPGALoader).

Evidencia de validación publicada

  • Resultado automático: PASS.
  • Estructura parseada: 3 apartados, 1 tablas y 4 bloques de código detectados antes de publicar.
  • Código comprobado: 2 Verilog/Yosys-Verilator, 1 Bash/copy-paste checks.
  • Catálogo soportado: el texto se contrastó contra los perfiles de dispositivo validables de Prometeo y los stacks no soportados bloquean la publicación.
  • Hallazgos del informe: sin hallazgos bloqueantes.

Esta validación confirma compatibilidad sintáctica y de herramientas para el código publicado, pero no sustituye la prueba física sobre tu revisión exacta de ULX3S, tu archivo de restricciones de pines y tu cableado real.

Nota educativa de seguridad

Este proyecto es un prototipo educativo, no un producto certificado. Antes de encender la configuración, verifica el mapa de pines (pinout) de tu revisión exacta de la placa ULX3S, mantén las señales de E/S de la FPGA a 3.3 V, nunca conectes 5 V directamente a los pines de E/S, desconecta la alimentación antes de cambiar el cableado y utiliza fuentes externas adecuadas para cargas, motores o servos, compartiendo la tierra solo cuando el cableado lo requiera.

Requisitos previos

Para completar con éxito este tutorial, necesitas:
* Comprensión básica de lógica digital (flip-flops, contadores y dominios de reloj).
* Una instalación funcional de la cadena de herramientas de código abierto para FPGA Lattice ECP5:
* Verilator (versión 5.0 o posterior recomendada para soporte de --binary) para análisis estático (linting) y simulación.
* Yosys para síntesis lógica.
* nextpnr-ecp5 para ubicación y enrutamiento (place and route).
* Project Trellis (ecppack) para la generación del bitstream.
* openFPGALoader para programar el dispositivo.
* Un editor de texto para crear archivos fuente Verilog, bancos de pruebas (testbenches) y archivos de restricciones.
* Familiaridad básica con el uso de una interfaz de línea de comandos (CLI) para ejecutar comandos de compilación.

Materiales

  • Placa de desarrollo FPGA Radiona ULX3S (Lattice ECP5-85F).
  • Cable puente (jumper) para entrada de pulso: Un cable puente Dupont estándar macho a macho (usado para simular pulsos manualmente tocando un pin de 3.3V, o para conectar un generador de señales externo).
  • Zumbador piezoeléctrico: Un módulo de zumbador (buzzer) piezoeléctrico pasivo estándar (capaz de producir sonido cuando es accionado por una onda cuadrada).
  • LED de estado: Usaremos uno de los LED rojos integrados provistos en la placa ULX3S.
  • Protoboard y cables puente adicionales (opcional, para asegurar el zumbador piezoeléctrico).

Configuración/Conexión

El Radiona ULX3S proporciona conectores GPIO versátiles (J1 y J2) que operan a niveles lógicos de 3.3V. Usaremos el conector J1 para nuestras conexiones externas.

Componente / FunciónConexión físicaPin de la FPGAEstándar de E/SNotas
Reloj del sistemaOscilador integrado de 25 MHzG2LVCMOS33Acciona toda la lógica síncrona.
Entrada de pulsoConector J1, Pin gp[0]B11LVCMOS33Con resistencia pull-down interna (pulled DOWN). Conecta un puente entre 3.3V y este pin para simular un pulso.
Zumbador piezoeléctricoConector J1, Pin gp[1]A10LVCMOS33Conecta el positivo del zumbador a gp[1] y el negativo a GND en el conector J1.
LED de estadoLED 0 integradoB2LVCMOS33Se ilumina cuando el watchdog agota el tiempo (timeout).

Instrucciones de cableado:
1. Localiza el conector J1 en la ULX3S.
2. Conecta la pata positiva de tu zumbador piezoeléctrico pasivo al pin etiquetado gp[1] (pin A10 de la FPGA).
3. Conecta la pata negativa del zumbador piezoeléctrico a un pin GND en la ULX3S.
4. Toma tu cable puente de entrada de pulso y conecta un extremo en el pin etiquetado gp[0] (pin B11 de la FPGA). Deja el otro extremo suelto por ahora; lo tocarás contra un pin de 3.3V en el conector J1 para simular los pulsos de latido (heartbeat) entrantes.

Código validado

El proyecto consta de tres archivos: el módulo Verilog principal sintetizable, el banco de pruebas (testbench) Verilog para simulación y el Archivo de Preferencias Lógicas (LPF) para restricciones de pines. Guarda estos archivos en el mismo directorio de trabajo.

1. Módulo principal (watchdog.v)

Este módulo sincroniza la entrada asíncrona, detecta flancos de subida, cuenta los ciclos de reloj para medir el tiempo de espera (timeout) y genera un tono de 2 kHz si se alcanza dicho tiempo.

Vista pública parcial del archivo validado. El código completo se muestra a miembros y en PDF/Print.

/*
 * Module: watchdog
 * Description: Missing-pulse watchdog alarm. Triggers an LED and a 2 kHz 
 * piezo buzzer tone if a rising edge is not detected within the timeout period.
 */
module watchdog #(
    // Defaults for 25 MHz clock
    parameter TIMEOUT_CYCLES = 25000000, // 1 second timeout
    parameter TONE_CYCLES    = 12500     // 2 kHz tone period (25M / 2k)
)(
    input  wire clk_25mhz,
    input  wire pulse_in,
    output wire buzzer_out,
    output wire led_out
);

    // --------------------------------------------------------
    // 1. Metastability Synchronizer
    // --------------------------------------------------------
    // The input pulse comes from the outside world and is asynchronous.
    // We use a 2-stage shift register to synchronize it to the 25MHz clock.
    reg [1:0] sync_reg = 2'b00;

    always @(posedge clk_25mhz) begin
        sync_reg <= {sync_reg[0], pulse_in};
    end

    // --------------------------------------------------------
    // 2. Edge Detector
    // --------------------------------------------------------
    // Compare the current synchronized state with the previous state
    // to generate a single-cycle pulse on the rising edge.
    reg pulse_prev = 1'b0;
    wire pulse_edge;

    always @(posedge clk_25mhz) begin
        pulse_prev <= sync_reg[1];
    end

    assign pulse_edge = (sync_reg[1] && !pulse_prev);

    // --------------------------------------------------------
    // 3. Watchdog Timer
    // --------------------------------------------------------
    reg [24:0] timer_cnt = 25'd0;
// ...

🔒 Este contenido es premium. Con la suscripción mensual (7 días gratis) podrás desbloquear el material didáctico completo y el pack PDF listo para imprimir.🔓 Desbloquéalo — 7 días gratis
/*
 * Module: watchdog
 * Description: Missing-pulse watchdog alarm. Triggers an LED and a 2 kHz 
 * piezo buzzer tone if a rising edge is not detected within the timeout period.
 */
module watchdog #(
    // Defaults for 25 MHz clock
    parameter TIMEOUT_CYCLES = 25000000, // 1 second timeout
    parameter TONE_CYCLES    = 12500     // 2 kHz tone period (25M / 2k)
)(
    input  wire clk_25mhz,
    input  wire pulse_in,
    output wire buzzer_out,
    output wire led_out
);

    // --------------------------------------------------------
    // 1. Metastability Synchronizer
    // --------------------------------------------------------
    // The input pulse comes from the outside world and is asynchronous.
    // We use a 2-stage shift register to synchronize it to the 25MHz clock.
    reg [1:0] sync_reg = 2'b00;

    always @(posedge clk_25mhz) begin
        sync_reg <= {sync_reg[0], pulse_in};
    end

    // --------------------------------------------------------
    // 2. Edge Detector
    // --------------------------------------------------------
    // Compare the current synchronized state with the previous state
    // to generate a single-cycle pulse on the rising edge.
    reg pulse_prev = 1'b0;
    wire pulse_edge;

    always @(posedge clk_25mhz) begin
        pulse_prev <= sync_reg[1];
    end

    assign pulse_edge = (sync_reg[1] && !pulse_prev);

    // --------------------------------------------------------
    // 3. Watchdog Timer
    // --------------------------------------------------------
    reg [24:0] timer_cnt = 25'd0;
    reg alarm_state = 1'b0;

    always @(posedge clk_25mhz) begin
        if (pulse_edge) begin
            // Valid pulse received: reset timer and clear alarm
            timer_cnt <= 25'd0;
            alarm_state <= 1'b0;
        end else if (timer_cnt < TIMEOUT_CYCLES) begin
            // No pulse, but timeout not yet reached: increment timer
            timer_cnt <= timer_cnt + 1'b1;
        end else begin
            // Timeout reached: trigger alarm
            alarm_state <= 1'b1;
        end
    end

    // --------------------------------------------------------
    // 4. Tone Generator (2 kHz Square Wave)
    // --------------------------------------------------------
    reg [13:0] tone_cnt = 14'd0;
    reg tone_out = 1'b0;

    always @(posedge clk_25mhz) begin
        if (alarm_state) begin
            // Toggle the buzzer state every half-period
            if (tone_cnt >= (TONE_CYCLES / 2) - 1) begin
                tone_cnt <= 14'd0;
                tone_out <= ~tone_out;
            end else begin
                tone_cnt <= tone_cnt + 1'b1;
            end
        end else begin
            // Ensure buzzer is silent when alarm is inactive
            tone_cnt <= 14'd0;
            tone_out <= 1'b0;
        end
    end

    // --------------------------------------------------------
    // 5. Output Assignments
    // --------------------------------------------------------
    assign buzzer_out = tone_out;
    assign led_out    = alarm_state;

endmodule

2. Banco de pruebas (watchdog_tb.v)

El banco de pruebas sobrescribe los parámetros de tiempo predeterminados para acelerar la simulación. Simular 25 millones de ciclos sería computacionalmente costoso e innecesario para verificar la lógica. El banco de pruebas comprueba automáticamente si la salida se activa y se restablece correctamente.

Vista pública parcial del archivo validado. El código completo se muestra a miembros y en PDF/Print.

/*
 * Module: watchdog_tb
 * Description: Simulation testbench for the missing-pulse watchdog.
 */
`timescale 1ns/1ps

module watchdog_tb;

    reg clk;
    reg pulse_in;
    wire buzzer_out;
    wire led_out;

    // Instantiate the Device Under Test (DUT)
    // Override parameters for faster simulation:
    // Timeout = 100 cycles, Tone period = 10 cycles
    watchdog #(
        .TIMEOUT_CYCLES(100),
        .TONE_CYCLES(10)
    ) dut (
        .clk_25mhz(clk),
        .pulse_in(pulse_in),
        .buzzer_out(buzzer_out),
        .led_out(led_out)
    );

    // Clock generation (25 MHz = 40ns period)
    initial clk = 0;
    always #20 clk = ~clk;

    initial begin
        $dumpfile("watchdog_tb.vcd");
        $dumpvars(0, watchdog_tb);

        // Initialize inputs
        pulse_in = 0;
// ...

🔒 Este contenido es premium. Con la suscripción mensual (7 días gratis) podrás desbloquear el material didáctico completo y el pack PDF listo para imprimir.🔓 Desbloquéalo — 7 días gratis
/*
 * Module: watchdog_tb
 * Description: Simulation testbench for the missing-pulse watchdog.
 */
`timescale 1ns/1ps

module watchdog_tb;

    reg clk;
    reg pulse_in;
    wire buzzer_out;
    wire led_out;

    // Instantiate the Device Under Test (DUT)
    // Override parameters for faster simulation:
    // Timeout = 100 cycles, Tone period = 10 cycles
    watchdog #(
        .TIMEOUT_CYCLES(100),
        .TONE_CYCLES(10)
    ) dut (
        .clk_25mhz(clk),
        .pulse_in(pulse_in),
        .buzzer_out(buzzer_out),
        .led_out(led_out)
    );

    // Clock generation (25 MHz = 40ns period)
    initial clk = 0;
    always #20 clk = ~clk;

    initial begin
        $dumpfile("watchdog_tb.vcd");
        $dumpvars(0, watchdog_tb);

        // Initialize inputs
        pulse_in = 0;

        // Wait for reset/initialization
        #100;

        // Apply a pulse
        pulse_in = 1;
        #40;
        pulse_in = 0;

        // Wait for timeout (100 cycles * 40ns = 4000ns)
        #5000;

        if (led_out !== 1'b1) begin
            $display("FAIL: Alarm did not trigger after timeout.");
        end else begin
            $display("PASS: Alarm triggered successfully.");
        end

        // Apply another pulse to reset alarm
        pulse_in = 1;
        #40;
        pulse_in = 0;

        #100;
        if (led_out !== 1'b0) begin
            $display("FAIL: Alarm did not clear after new pulse.");
        end else begin
            $display("PASS: Alarm cleared successfully.");
        end

        #1000;
        $finish;
    end

endmodule

3. Archivo de restricciones (ulx3s.lpf)

Este archivo mapea los puertos Verilog de nivel superior a los pines físicos de la placa Radiona ULX3S ECP5-85F.

LOCATE COMP "clk_25mhz" SITE "G2";
IOBUF COMP "clk_25mhz" IO_TYPE=LVCMOS33;

LOCATE COMP "pulse_in" SITE "B11";
IOBUF COMP "pulse_in" IO_TYPE=LVCMOS33 PULLMODE=DOWN;

LOCATE COMP "buzzer_out" SITE "A10";
IOBUF COMP "buzzer_out" IO_TYPE=LVCMOS33;

LOCATE COMP "led_out" SITE "B2";
IOBUF COMP "led_out" IO_TYPE=LVCMOS33;

Compilación y validación

Ejecuta los siguientes comandos en tu terminal para simular la lógica, sintetizar el diseño y programar la placa FPGA ULX3S.

# 1. Lint and simulate with Verilator to validate logic
verilator --binary --trace watchdog.v watchdog_tb.v
./obj_dir/Vwatchdog_tb

# 2. Synthesize with Yosys
yosys -p "synth_ecp5 -top watchdog -json watchdog.json" watchdog.v

# 3. Place and Route with nextpnr
nextpnr-ecp5 --85k --package CABGA381 --json watchdog.json --lpf ulx3s.lpf --textcfg watchdog.config

# 4. Pack bitstream
ecppack watchdog.config watchdog.bit

# 5. Program the ULX3S via openFPGALoader
openFPGALoader --board ulx3s watchdog.bit

Evidencia de validación esperada:
1. Fase de simulación: La ejecución de Verilator (./obj_dir/Vwatchdog_tb) debería imprimir PASS: Alarm triggered successfully. seguido de PASS: Alarm cleared successfully. en la consola, confirmando un recuento de ciclos preciso.
2. Fase de hardware: Al flashear, el LED rojo se encenderá inmediatamente y el zumbador emitirá un tono de 2 kHz porque no llegan pulsos.
3. Prueba manual: Toca con el cable puente suelto el pin de 3.3V en el conector J1. El LED y el zumbador se apagarán al instante. Si dejas de tocar, exactamente 1.0 segundos después, la alarma se reanudará.

Encuentra este producto y/o libros sobre este tema en Amazon

Ir a Amazon

Como afiliado de Amazon, gano con las compras que cumplan los requisitos. Si compras a través de este enlace, ayudas a mantener este proyecto.

Quiz rápido

Pregunta 1: ¿Qué tipo de dispositivo se construye en el proyecto descrito?




Pregunta 2: ¿Qué tipo de señal monitorea continuamente la alarma?




Pregunta 3: ¿Qué componentes se activan si la señal se interrumpe?




Pregunta 4: ¿Cuál es la latencia de activación de la alarma al detectar la interrupción?




Pregunta 5: En la supervisión de sistemas embebidos, ¿qué indica la interrupción de la onda cuadrada de 'latido'?




Pregunta 6: ¿Cómo se utiliza este sistema en la automatización industrial?




Pregunta 7: En el contexto de monitoreo de seguridad, ¿qué permite detectar este sistema?




Pregunta 8: ¿En qué tecnología se sintetiza el temporizador watchdog según el resultado esperado?




Pregunta 9: ¿Qué nivel de precisión tiene la detección de fallos del temporizador watchdog sintetizado?




Pregunta 10: ¿Qué tipo de activación se produce en el LED y el zumbador piezoeléctrico?




Carlos Núñez Zorrilla
Carlos Núñez Zorrilla
Electronics & Computer Engineer

Ingeniero Superior en Electrónica de Telecomunicaciones e Ingeniero en Informática (titulaciones oficiales en España).

Sígueme:
Scroll al inicio