Manufactura industrial
Internet industrial de las cosas | Materiales industriales | Mantenimiento y reparación de equipos | Programación industrial |
home  MfgRobots >> Manufactura industrial >  >> Industrial programming >> VHDL

Tutorial:su primer programa FPGA:un LED intermitente

Parte 1:Diseño de VHDL o Verilog

Este tutorial muestra la construcción de código VHDL y Verilog que hace parpadear un LED a una frecuencia específica. Se muestran tanto VHDL como Verilog, y puede elegir cuál desea aprender primero. Cada vez que se escribe código de diseño, el diseñador de FPGA debe asegurarse de que funcione de la manera prevista. A pesar de sus mejores esfuerzos, siempre habrá errores en su diseño inicial. La mejor manera de encontrar estos errores es en un entorno de simulación. Este tutorial se divide en 2 etapas:

  1. Diseño de HDL
  2. Simulación de HDL

Ambos pasos son cruciales para el desarrollo exitoso de FPGA. A veces, los diseñadores de FPGA que tienen poco tiempo intentarán saltarse el paso dos, la simulación de su código. ¡Sin embargo, este es un paso extremadamente importante! Sin una simulación adecuada, se verá obligado a depurar su código en el hardware, lo que puede ser un esfuerzo muy difícil y lento.

Requisitos del proyecto:

Diseñe un código HDL que hará parpadear un LED a una frecuencia específica de 100 Hz, 50 Hz, 10 Hz o 1 Hz. Para cada una de las frecuencias de parpadeo, el LED se establecerá en un ciclo de trabajo del 50 % (estará encendido la mitad del tiempo). La frecuencia del LED se elegirá a través de dos interruptores que son entradas a la FPGA. Hay un interruptor adicional llamado LED_EN que debe ser '1' para encender el LED. El FPGA será impulsado por un oscilador de 25 MHz.

Primero dibujemos la tabla de verdad para el selector de frecuencia:

Habilitar Interruptor 1 Interruptor 2 Frecuencia de accionamiento de LED 0 - - (deshabilitado) 1 0 0 100 Hz 1 0 1 50 Hz 1 1 0 10 Hz 1 1 1 1 Hz

Para que esto funcione correctamente habrá 4 entradas y 1 salida. Las señales serán:

Nombre de la señal Dirección Descripción Entrada i_clock Reloj de 25 MHz Entrada i_enable El interruptor de habilitación (0 lógico =sin controlador de LED) i_switch_1 Interruptor de entrada 1 en la tabla de verdad anterior i_switch_2 Interruptor de entrada 2 en la tabla de verdad anterior o_led_drive Salida La señal que activa el LED

Para el diseño hay cuatro procesos contrarios que se ejecutan simultáneamente. Esto significa que todos se están ejecutando al mismo tiempo. Su trabajo es realizar un seguimiento de la cantidad de pulsos de reloj vistos para cada una de las diferentes frecuencias. Incluso si los interruptores no están seleccionando esa frecuencia en particular, ¡los contadores siguen funcionando! Esta es la belleza del diseño de hardware y la concurrencia. ¡Todo funciona todo el tiempo! Puede ser un desafío entender esto inicialmente, pero es el concepto central que debe dominar.

Los interruptores solo sirven para seleccionar qué salida usar. Crean lo que se conoce como un multiplexor. Un multiplexor o mux para abreviar es un selector que seleccionará una de varias entradas para propagar o pasar a la salida. Es una pieza de lógica combinatoria, lo que significa que no requiere un reloj para funcionar. A continuación se muestra un diagrama de bloques del diseño. Dedique algún tiempo a pensar en cómo podría implementar este diseño. Intente escribir el código usted mismo. La forma en que elegí hacerlo se puede encontrar a continuación.

Diagrama de bloques - Programa de parpadeo de LED

Código VHDL para el diseño, tutorial_led_blink.vhd:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity tutorial_led_blink is
  port (
    i_clock      : in  std_logic;
    i_enable     : in  std_logic;
    i_switch_1   : in  std_logic;
    i_switch_2   : in  std_logic;
    o_led_drive  : out std_logic
    );
end tutorial_led_blink;

architecture rtl of tutorial_led_blink is

  -- Constants to create the frequencies needed:
  -- Formula is: (25 MHz / 100 Hz * 50% duty cycle)
  -- So for 100 Hz: 25,000,000 / 100 * 0.5 = 125,000
  constant c_CNT_100HZ : natural := 125000;
  constant c_CNT_50HZ  : natural := 250000;
  constant c_CNT_10HZ  : natural := 1250000;
  constant c_CNT_1HZ   : natural := 12500000;


  -- These signals will be the counters:
  signal r_CNT_100HZ : natural range 0 to c_CNT_100HZ;
  signal r_CNT_50HZ  : natural range 0 to c_CNT_50HZ;
  signal r_CNT_10HZ  : natural range 0 to c_CNT_10HZ;
  signal r_CNT_1HZ   : natural range 0 to c_CNT_1HZ;
  
  -- These signals will toggle at the frequencies needed:
  signal r_TOGGLE_100HZ : std_logic := '0';
  signal r_TOGGLE_50HZ  : std_logic := '0';
  signal r_TOGGLE_10HZ  : std_logic := '0';
  signal r_TOGGLE_1HZ   : std_logic := '0';

  -- One bit select wire.
  signal w_LED_SELECT : std_logic;
  
begin

  -- All processes toggle a specific signal at a different frequency.
  -- They all run continuously even if the switches are
  -- not selecting their particular output.
  
  p_100_HZ : process (i_clock) is
  begin
    if rising_edge(i_clock) then
      if r_CNT_100HZ = c_CNT_100HZ-1 then  -- -1, since counter starts at 0
        r_TOGGLE_100HZ <= not r_TOGGLE_100HZ;
        r_CNT_100HZ    <= 0;
      else
        r_CNT_100HZ <= r_CNT_100HZ + 1;
      end if;
    end if;
  end process p_100_HZ;


  p_50_HZ : process (i_clock) is
  begin
    if rising_edge(i_clock) then
      if r_CNT_50HZ = c_CNT_50HZ-1 then  -- -1, since counter starts at 0
        r_TOGGLE_50HZ <= not r_TOGGLE_50HZ;
        r_CNT_50HZ    <= 0;
      else
        r_CNT_50HZ <= r_CNT_50HZ + 1;
      end if;
    end if;
  end process p_50_HZ;

  
  p_10_HZ : process (i_clock) is
  begin
    if rising_edge(i_clock) then
      if r_CNT_10HZ = c_CNT_10HZ-1 then  -- -1, since counter starts at 0
        r_TOGGLE_10HZ <= not r_TOGGLE_10HZ;
        r_CNT_10HZ    <= 0;
      else
        r_CNT_10HZ <= r_CNT_10HZ + 1;
      end if;
    end if;
  end process p_10_HZ;

  
  p_1_HZ : process (i_clock) is
  begin
    if rising_edge(i_clock) then
      if r_CNT_1HZ = c_CNT_1HZ-1 then  -- -1, since counter starts at 0
        r_TOGGLE_1HZ <= not r_TOGGLE_1HZ;
        r_CNT_1HZ    <= 0;
      else
        r_CNT_1HZ <= r_CNT_1HZ + 1;
      end if;
    end if;
  end process p_1_HZ;

  
  -- Create a multiplexor based on switch inputs
  w_LED_SELECT <= r_TOGGLE_100HZ when (i_switch_1 = '0' and i_switch_2 = '0') else
                  r_TOGGLE_50HZ  when (i_switch_1 = '0' and i_switch_2 = '1') else
                  r_TOGGLE_10HZ  when (i_switch_1 = '1' and i_switch_2 = '0') else
                  r_TOGGLE_1HZ;

  
  -- Only allow o_led_drive to drive when i_enable is high (and gate).
  o_led_drive <= w_LED_SELECT and i_enable;

end rtl;

Código Verilog para el diseño, tutorial_led_blink.v:

module tutorial_led_blink 
  (
   i_clock,
   i_enable,
   i_switch_1,
   i_switch_2,
   o_led_drive
   );

  input i_clock;
  input i_enable;
  input i_switch_1;
  input i_switch_2;
  output o_led_drive;
   
  // Constants (parameters) to create the frequencies needed:
  // Input clock is 25 kHz, chosen arbitrarily.
  // Formula is: (25 kHz / 100 Hz * 50% duty cycle)
  // So for 100 Hz: 25,000 / 100 * 0.5 = 125
  parameter c_CNT_100HZ = 125;
  parameter c_CNT_50HZ  = 250;
  parameter c_CNT_10HZ  = 1250;
  parameter c_CNT_1HZ   = 12500;

  // These signals will be the counters:
  reg [31:0] r_CNT_100HZ = 0;
  reg [31:0] r_CNT_50HZ = 0;
  reg [31:0] r_CNT_10HZ = 0;
  reg [31:0] r_CNT_1HZ = 0;
  
  // These signals will toggle at the frequencies needed:
  reg 	     r_TOGGLE_100HZ = 1'b0;
  reg 	     r_TOGGLE_50HZ  = 1'b0;
  reg 	     r_TOGGLE_10HZ  = 1'b0;
  reg 	     r_TOGGLE_1HZ   = 1'b0;
  
  // One bit select
  reg 	     r_LED_SELECT;
  wire 	     w_LED_SELECT;
  
    
begin

  // All always blocks toggle a specific signal at a different frequency.
  // They all run continuously even if the switches are
  // not selecting their particular output.

  always @ (posedge i_clock)
    begin
      if (r_CNT_100HZ == c_CNT_100HZ-1) // -1, since counter starts at 0
        begin	      
          r_TOGGLE_100HZ <= !r_TOGGLE_100HZ;
          r_CNT_100HZ    <= 0;
        end
      else
        r_CNT_100HZ <= r_CNT_100HZ + 1;
    end

  
  always @ (posedge i_clock)
    begin
      if (r_CNT_50HZ == c_CNT_50HZ-1) // -1, since counter starts at 0
        begin	      
          r_TOGGLE_50HZ <= !r_TOGGLE_50HZ;
          r_CNT_50HZ    <= 0;
        end
      else
        r_CNT_50HZ <= r_CNT_50HZ + 1;
    end


  always @ (posedge i_clock)
    begin
      if (r_CNT_10HZ == c_CNT_10HZ-1) // -1, since counter starts at 0
        begin	      
          r_TOGGLE_10HZ <= !r_TOGGLE_10HZ;
          r_CNT_10HZ    <= 0;
        end
      else
        r_CNT_10HZ <= r_CNT_10HZ + 1;
    end

  
  always @ (posedge i_clock)
    begin
      if (r_CNT_1HZ == c_CNT_1HZ-1) // -1, since counter starts at 0
        begin	      
          r_TOGGLE_1HZ <= !r_TOGGLE_1HZ;
          r_CNT_1HZ    <= 0;
        end
      else
        r_CNT_1HZ <= r_CNT_1HZ + 1;
    end

  // Create a multiplexer based on switch inputs
  always @ (*)
  begin
    case ({i_switch_1, i_switch_2}) // Concatenation Operator { }
      2'b11 : r_LED_SELECT <= r_TOGGLE_1HZ;
      2'b10 : r_LED_SELECT <= r_TOGGLE_10HZ;
      2'b01 : r_LED_SELECT <= r_TOGGLE_50HZ;
      2'b00 : r_LED_SELECT <= r_TOGGLE_100HZ;
    endcase      
  end

  assign o_led_drive = r_LED_SELECT & i_enable;

  // Alternative way to design multiplexer (same as above):
  // More compact, but harder to read, especially to those new to Verilog
  // assign w_LED_SELECT = i_switch_1 ? (i_switch_2 ? r_TOGGLE_1HZ : r_TOGGLE_10HZ) : 
                                        (i_switch_2 ? r_TOGGLE_50HZ : r_TOGGLE_100HZ);
  // assign o_led_drive = w_LED_SELECT & i_enable;
    
  
end 
  
endmodule


VHDL

  1. C# Hello World:su primer programa en C#
  2. Diseño embebido con FPGA:Construyendo un proyecto
  3. Simplificación del diseño con tecnología FPGA incorporada
  4. Cómo crear tu primer programa VHDL:¡Hola mundo!
  5. Cómo optimizar su programa de MP
  6. Maximice su programa de análisis de lubricación
  7. Tutorial de Verilog
  8. Cómo diseñar un programa de mantenimiento preventivo para su equipo
  9. 10 trucos para mejorar su programa PM
  10. Tutorial de diseño de placa de circuito impreso de placa base
  11. Tutorial de diseño de PCB de KiCAD