Código VHDL para un generador de onda cuadrada parametrizable

Generador de onda cuadrada sintetizable en VHDL

A continuación se muestra una implementación limpia y parametrizable utilizando un enfoque basado en contador. Soporta ajuste de frecuencia en tiempo de ejecución a través de un puerto de entrada e incluye un reinicio síncrono activo en alto.

library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity square_wave_gen is generic ( CLK_FREQ_HZ : positive := 50_000_000; -- Frecuencia de reloj de entrada CNT_WIDTH : positive := 24 -- Ancho de bits del contador (período máximo) ); port ( clk : in std_logic; rst_n : in std_logic; -- Reinicio síncrono activo en bajo freq_hz : in positive range 1 to CLK_FREQ_HZ/2; -- Frecuencia de salida wave_out : out std_logic ); end entity square_wave_gen; architecture rtl of square_wave_gen is constant MAX_CNT : natural := CLK_FREQ_HZ / 2; -- Medio período máximo a 1 Hz signal half_period : natural range 1 to MAX_CNT; signal ctr : natural range 0 to MAX_CNT; begin -- Cálculo combinacional de medio período (sintetiza a divisor o LUT) half_period <= CLK_FREQ_HZ / (2 * freq_hz); process (clk) begin if rising_edge(clk) then if rst_n = '0' then ctr <= 0; wave_out <= '0'; elsif ctr = half_period - 1 then ctr <= 0; wave_out <= not wave_out; else ctr <= ctr + 1; end if; end if; end process; end architecture rtl; 

Notas de diseño

  • Genéricos: CLK_FREQ_HZ y CNT_WIDTH lo hacen portable entre dominios de reloj (p. ej., 50 MHz, 100 MHz, 125 MHz).
  • Frecuencia en tiempo de ejecución: la entrada freq_hz permite reconfiguración dinámica (p. ej., desde CPU, UART, interruptores DIP). Rango restringido a valores válidos.
  • Reinicio activo en bajo: rst_n sigue la convención común de FPGA; síncrono para cierre de temporización.
  • Ciclo de trabajo 50 %: El contador conmutan la salida en half_period → onda cuadrada simétrica.
  • Sin latches: Totalmente síncrono, un solo proceso de reloj.
  • Uso de recursos: ~1 registro de contador + comparador + sumador + 1 FF. Mínimas LUT/FF.

Fragmento de banco de pruebas

-- Estímulo: reloj 50 MHz, generar 1 kHz → 10 kHz → 100 kHz freq_hz <= 1_000; wait for 5 ms; freq_hz <= 10_000; wait for 5 ms; freq_hz <= 100_000; wait for 5 ms; 

Errores comunes a evitar

  • Usar std_logic_vector para frecuencia sin conversión unsigned.
  • Codificar la frecuencia de reloj de forma fija (use genérico).
  • Reinicio asíncrono sin manejo adecuado de CDC.
  • Olvidar la comparación half_period - 1 (error de uno → error de frecuencia).
  • No restringir el rango de freq_hz → la síntesis infiere un divisor enorme.

Extensiones

  • Agregar duty_cycle genérico/entrada para PWM (contadores separados alto/bajo).
  • Agregar phase_offset para generación multifásica.
  • Usar rebanada DSP para división si CLK_FREQ_HZ es grande y el rango dinámico es amplio.