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ón | Conexión física | Pin de la FPGA | Estándar de E/S | Notas |
|---|---|---|---|---|
| Reloj del sistema | Oscilador integrado de 25 MHz | G2 | LVCMOS33 | Acciona toda la lógica síncrona. |
| Entrada de pulso | Conector J1, Pin gp[0] | B11 | LVCMOS33 | Con resistencia pull-down interna (pulled DOWN). Conecta un puente entre 3.3V y este pin para simular un pulso. |
| Zumbador piezoeléctrico | Conector J1, Pin gp[1] | A10 | LVCMOS33 | Conecta el positivo del zumbador a gp[1] y el negativo a GND en el conector J1. |
| LED de estado | LED 0 integrado | B2 | LVCMOS33 | Se 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;
// .../*
* 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;
// .../*
* 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
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.




