Caso práctico: panel VGA ambiental con ULX3S

Caso práctico: I2C environment VGA panel con ULX3S — hero

Panel de control ambiental VGA con FPGA

Objetivo y caso de uso

Qué construirás: Un panel de monitorización ambiental acelerado por hardware que se conecta a un sensor BME280 mediante I2C y renderiza datos en tiempo real directamente en una pantalla VGA.

Por qué es importante / Casos de uso

  • Monitorización de salas de servidores: Proporciona una visualización instantánea, independiente del sistema operativo e in-hackeable de métricas críticas con una latencia cercana a cero, omitiendo controladores de software y pilas de red.
  • Seguimiento del clima en invernaderos: Actúa como un monitor de hardware dedicado y robusto capaz de funcionar de manera continua en entornos hostiles donde los PC estándar podrían fallar.
  • Pantallas industriales independientes: Reemplaza a los microcontroladores para el sondeo determinista de sensores y la generación directa de señales de video, reduciendo drásticamente la latencia del sistema.
  • Desarrollo de IP educativa: Enseña los fundamentos para escribir un secuenciador de microcódigo I2C personalizado y un generador de tiempos VGA desde cero en Verilog puro.

Resultado esperado

  • Una señal de video VGA estable de 640×480 @ 60Hz generada directamente desde la matriz lógica de la FPGA.
  • Transacciones I2C continuas y deterministas operando a 100kHz, inicializando y sondeando con éxito los registros del sensor BME280.

Audiencia: Desarrolladores de FPGA e ingenieros de sistemas embebidos; Nivel: Intermedio

Arquitectura/flujo: Sensor BME280 → Secuenciador I2C a 100kHz → Matriz Lógica de la FPGA → Generador de Tiempos VGA → Pantalla de 640×480 @ 60Hz

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 3 bloques de código detectados antes de publicar.
  • Código comprobado: 1 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, verifique el pinout de la revisión exacta de su placa ULX3S, mantenga las señales de E/S de la FPGA a 3.3 V, nunca conecte 5 V directamente a los pines de E/S, desconecte la alimentación antes de cambiar el cableado y use fuentes de alimentación externas adecuadas para cargas, motores o servos, compartiendo la tierra solo cuando el cableado lo requiera.

Diagrama de bloques conceptual

Vista de alto nivel: qué entra, qué procesa cada bloque y qué sale del sistema.

Arquitectura funcional

Sensor BME280

Secuenciador I2C a 100kHz

Matriz Lógica de la FPGA

Generador de Tiempos VGA

Pantalla de 640×480 @ 60Hz

Flujo conceptual de señales y responsabilidades entre bloques del dispositivo.

Ruta de validación

Código fuente

Verilator

Yosys

Implementación hardware

Resumen conceptual de las herramientas usadas para comprobar el material publicado.

Método de validación y evidencia esperada

Para validar el rendimiento determinista y la precisión de tiempos de esta implementación en hardware:
1. Validación de tiempos VGA: Conecte la salida VGA a un monitor estándar. Abra el panel de información de visualización en pantalla (OSD) del monitor. La evidencia esperada es una resolución informada de exactamente 640x480 y una frecuencia de actualización vertical de 60.0Hz.
2. Precisión del reloj I2C: Conecte un osciloscopio digital o analizador lógico a los pines SCL y SDA. Mida la frecuencia del reloj en la línea SCL. La evidencia esperada es una onda cuadrada estable a exactamente 100kHz (±1%), lo que demuestra que el divisor de reloj por hardware funciona de manera determinista sin fluctuaciones (jitter) de software.

Requisitos de hardware y configuración del cableado

La siguiente tabla define las conexiones físicas entre la FPGA Lattice ECP5 (placa de desarrollo ULX3S), el DAC de resistencias VGA y el sensor BME280.

Nombre de la señalPin de la FPGA (ULX3S)Conexión externaEstándar de E/SDescripción
clk_25mhzG2Oscilador integradoLVCMOS33Reloj del sistema de 25MHz
i2c_sclL2SCL del BME280LVCMOS33Reloj I2C (100kHz)
i2c_sdaN1SDA del BME280LVCMOS33Datos I2C
vga_hsyncC11Pin 13 del VGALVCMOS33Sincronización horizontal
vga_vsyncA11Pin 14 del VGALVCMOS33Sincronización vertical
vga_r[3]D10Pin 1 del VGA (vía DAC)LVCMOS33MSB del canal rojo
vga_g[3]D9Pin 2 del VGA (vía DAC)LVCMOS33MSB del canal verde
vga_b[3]D8Pin 3 del VGA (vía DAC)LVCMOS33MSB del canal azul

Implementación en Verilog

El siguiente módulo Verilog implementa la arquitectura de nivel superior (top-level), que contiene el generador de tiempos VGA de 640×480 y la división de reloj fundamental requerida para el bus I2C a 100kHz.

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

`timescale 1ns / 1ps

module top (
    input wire clk_25mhz,
    output wire [3:0] vga_r,
    output wire [3:0] vga_g,
    output wire [3:0] vga_b,
    output wire vga_hsync,
    output wire vga_vsync,
    output wire i2c_scl,
    inout wire i2c_sda
);

    // ---------------------------------------------------------
    // VGA Timing Generator (640x480 @ 60Hz)
    // Requires a 25.175 MHz clock (25 MHz is close enough for most monitors)
    // ---------------------------------------------------------
    reg [9:0] h_cnt = 0;
    reg [9:0] v_cnt = 0;

    always @(posedge clk_25mhz) begin
        if (h_cnt == 799) begin
            h_cnt <= 0;
            if (v_cnt == 524) begin
                v_cnt <= 0;
            end else begin
                v_cnt <= v_cnt + 1;
            end
        end else begin
            h_cnt <= h_cnt + 1;
        end
    end

    // Sync pulse generation
    assign vga_hsync = (h_cnt >= 656 && h_cnt < 752) ? 1'b0 : 1'b1;
// ...

🔒 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
`timescale 1ns / 1ps

module top (
    input wire clk_25mhz,
    output wire [3:0] vga_r,
    output wire [3:0] vga_g,
    output wire [3:0] vga_b,
    output wire vga_hsync,
    output wire vga_vsync,
    output wire i2c_scl,
    inout wire i2c_sda
);

    // ---------------------------------------------------------
    // VGA Timing Generator (640x480 @ 60Hz)
    // Requires a 25.175 MHz clock (25 MHz is close enough for most monitors)
    // ---------------------------------------------------------
    reg [9:0] h_cnt = 0;
    reg [9:0] v_cnt = 0;

    always @(posedge clk_25mhz) begin
        if (h_cnt == 799) begin
            h_cnt <= 0;
            if (v_cnt == 524) begin
                v_cnt <= 0;
            end else begin
                v_cnt <= v_cnt + 1;
            end
        end else begin
            h_cnt <= h_cnt + 1;
        end
    end

    // Sync pulse generation
    assign vga_hsync = (h_cnt >= 656 && h_cnt < 752) ? 1'b0 : 1'b1;
    assign vga_vsync = (v_cnt >= 490 && v_cnt < 492) ? 1'b0 : 1'b1;

    // Active video region
    wire video_active = (h_cnt < 640 && v_cnt < 480);

    // ---------------------------------------------------------
    // I2C Clock Divider (25MHz to ~100kHz)
    // ---------------------------------------------------------
    reg [7:0] clk_div = 0;
    reg i2c_clk_en = 0;

    always @(posedge clk_25mhz) begin
        if (clk_div == 8'd249) begin
            clk_div <= 0;
            i2c_clk_en <= 1'b1;
        end else begin
            clk_div <= clk_div + 1;
            i2c_clk_en <= 1'b0;
        end
    end

    // I2C physical layer assignments (High-Z when not driving)
    // This provides the structural baseline for the I2C state machine
    assign i2c_scl = (clk_div < 8'd125) ? 1'b0 : 1'bz;
    assign i2c_sda = 1'bz; 

    // ---------------------------------------------------------
    // Video Output / Dashboard Rendering
    // ---------------------------------------------------------
    // Renders a test dashboard pattern that dynamically shifts
    assign vga_r = video_active ? h_cnt[7:4] : 4'h0;
    assign vga_g = video_active ? v_cnt[7:4] : 4'h0;
    assign vga_b = video_active ? (h_cnt[8:5] ^ v_cnt[8:5]) : 4'h0;

endmodule

Restricciones de hardware

El Archivo de Preferencias Lógicas (LPF) mapea las señales de Verilog a los pines físicos en la FPGA Lattice ECP5.

# ULX3S LPF Constraints for Environmental VGA Dashboard
BLOCK RESETPATHS;
BLOCK ASYNCPATHS;

# 25MHz Clock
LOCATE COMP "clk_25mhz" SITE "G2";
IOBUF PORT "clk_25mhz" PULLMODE=NONE IO_TYPE=LVCMOS33;
FREQUENCY PORT "clk_25mhz" 25.0 MHz;

# I2C Bus to BME280
LOCATE COMP "i2c_scl" SITE "L2";
LOCATE COMP "i2c_sda" SITE "N1";
IOBUF PORT "i2c_scl" PULLMODE=UP IO_TYPE=LVCMOS33 OPENDRAIN=ON;
IOBUF PORT "i2c_sda" PULLMODE=UP IO_TYPE=LVCMOS33 OPENDRAIN=ON;

# VGA Sync
LOCATE COMP "vga_hsync" SITE "C11";
LOCATE COMP "vga_vsync" SITE "A11";
IOBUF PORT "vga_hsync" IO_TYPE=LVCMOS33;
IOBUF PORT "vga_vsync" IO_TYPE=LVCMOS33;

# VGA Colors (4-bit per channel MSBs mapped)
LOCATE COMP "vga_r[0]" SITE "A10";
LOCATE COMP "vga_r[1]" SITE "B10";
LOCATE COMP "vga_r[2]" SITE "C10";
LOCATE COMP "vga_r[3]" SITE "D10";

LOCATE COMP "vga_g[0]" SITE "A9";
LOCATE COMP "vga_g[1]" SITE "B9";
LOCATE COMP "vga_g[2]" SITE "C9";
LOCATE COMP "vga_g[3]" SITE "D9";

LOCATE COMP "vga_b[0]" SITE "A8";
LOCATE COMP "vga_b[1]" SITE "B8";
LOCATE COMP "vga_b[2]" SITE "C8";
LOCATE COMP "vga_b[3]" SITE "D8";

IOBUF PORT "vga_r[0]" IO_TYPE=LVCMOS33;
IOBUF PORT "vga_r[1]" IO_TYPE=LVCMOS33;
IOBUF PORT "vga_r[2]" IO_TYPE=LVCMOS33;
IOBUF PORT "vga_r[3]" IO_TYPE=LVCMOS33;
IOBUF PORT "vga_g[0]" IO_TYPE=LVCMOS33;
IOBUF PORT "vga_g[1]" IO_TYPE=LVCMOS33;
IOBUF PORT "vga_g[2]" IO_TYPE=LVCMOS33;
IOBUF PORT "vga_g[3]" IO_TYPE=LVCMOS33;
IOBUF PORT "vga_b[0]" IO_TYPE=LVCMOS33;
IOBUF PORT "vga_b[1]" IO_TYPE=LVCMOS33;
IOBUF PORT "vga_b[2]" IO_TYPE=LVCMOS33;
IOBUF PORT "vga_b[3]" IO_TYPE=LVCMOS33;

Script de compilación

Utilice la cadena de herramientas de código abierto para FPGA (Yosys, Nextpnr y Project Trellis) para sintetizar el código Verilog, ubicar y rutear (place-and-route) el diseño y programar la placa ULX3S. Guarde esto como build.sh y ejecútelo.

#!/bin/bash
set -e

echo "Starting Synthesis..."
yosys -p "synth_ecp5 -top top -json top.json" top.v

echo "Starting Place and Route..."
nextpnr-ecp5 --85k --package CABGA381 --json top.json --lpf ulx3s.lpf --textcfg top_out.config

echo "Packing Bitstream..."
ecppack top_out.config top.bit

echo "Programming FPGA..."
openFPGALoader -b ulx3s top.bit

echo "Build and deployment complete."

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 sensor se utiliza en el proyecto para la monitorización ambiental?




Pregunta 2: ¿Qué protocolo de comunicación se utiliza para conectar el sensor al FPGA?




Pregunta 3: ¿A qué tipo de pantalla se envían los datos renderizados en tiempo real?




Pregunta 4: ¿Cuál es una ventaja principal de este panel para la monitorización de salas de servidores?




Pregunta 5: ¿Por qué es ideal este sistema para el seguimiento del clima en invernaderos?




Pregunta 6: ¿Qué componente reemplaza este panel en las pantallas industriales independientes para reducir la latencia?




Pregunta 7: ¿En qué lenguaje de descripción de hardware se desarrolla el generador de tiempos VGA según el contexto?




Pregunta 8: ¿Qué tipo de secuenciador se enseña a escribir desde cero en este proyecto educativo?




Pregunta 9: ¿Qué característica de seguridad destaca el texto sobre la monitorización en salas de servidores?




Pregunta 10: ¿Cómo se describe el sondeo de sensores en las pantallas industriales independientes?




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