工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Industrial programming >> VHDL

チュートリアル:初めての FPGA プログラム:LED ブリンカー

パート 1:VHDL または Verilog の設計

このチュートリアルでは、指定された周波数で LED を点滅させる VHDL および Verilog コードの構造を示します。 VHDL と Verilog の両方が表示され、どちらを先に学習するかを選択できます。 FPGA 設計者は、設計コードが記述されるたびに、それが意図したとおりに機能することを確認する必要があります。最善を尽くしても、最初の設計には必ず間違いがあります。これらの間違いを見つける最善の方法は、シミュレーション環境で行うことです。このチュートリアルは 2 つの段階に分かれています:

<オール>
  • HDL の設計
  • HDL のシミュレーション
  • これらのステップは両方とも、FPGA 開発を成功させるために不可欠です。時間に追われている FPGA 設計者は、コードのシミュレーションであるステップ 2 を省略しようとすることがあります。ただし、これは非常に重要なステップです。適切なシミュレーションがなければ、コードをハードウェア上でデバッグせざるを得なくなり、非常に困難で時間のかかる作業になる可能性があります。

    プロジェクトの要件:

    100 Hz、50 Hz、10 Hz、または 1 Hz の指定された周波数で LED を点滅させる HDL コードを設計します。点滅周波数ごとに、LED は 50% のデューティ サイクルに設定されます (半分の時間点灯します)。 LED 周波数は、FPGA への入力である 2 つのスイッチを介して選択されます。 LED をオンにするために「1」にする必要がある LED_EN と呼ばれる追加のスイッチがあります。 FPGA は 25 MHz 発振器によって駆動されます。

    まず、周波数セレクターの真理値表を作成しましょう:

    有効にする スイッチ 1 スイッチ 2 LED 駆動周波数 0 - - (無効) 1 0 0 100 Hz 1 0 1 50 Hz 1 1 0 10 Hz 1 1 1 1 Hz

    これが正しく機能するためには、4 つの入力と 1 つの出力があります。信号は次のようになります:

    信号名 方向 説明 i_clock 入力 25 MHz クロック i_enable 入力 イネーブル スイッチ (ロジック 0 =LED ドライブなし) i_switch_1 入力 上記の真理値表のスイッチ 1 i_switch_2 入力 上記の真理値表のスイッチ 2 o_led_drive 出力 LED を駆動する信号

    この設計では、同時に実行される 4 つのカウンター プロセスがあります。これは、すべてがまったく同時に実行されていることを意味します。彼らの仕事は、異なる周波数ごとに見られるクロック パルスの数を追跡することです。スイッチが特定の周波数を選択していなくても、カウンターは実行されています。これは、ハードウェア設計と並行性の美しさです。すべてが常に実行されます!これを最初に理解するのは難しいかもしれませんが、マスターする必要があるコアコンセプトです。

    スイッチは、使用する出力を選択するためだけに機能します。それらは、マルチプレクサと呼ばれるものを作成します。マルチプレクサまたは略してマルチプレクサは、多数の入力の 1 つを選択して伝播または出力に渡すセレクタです。これはロジックの組み合わせであり、動作にクロックを必要としません。以下は、設計のブロック図です。この設計をどのように実装するかについて、時間をかけて考えてください。自分でコードを書いてみてください。私が選択した方法を以下に示します。

    ブロック図 - LED 点滅プログラム

    デザインの VHDL コード、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;
    

    デザインの Verilog コード、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 - 初めての C# プログラム
    2. FPGAを使用した組み込み設計:プロジェクトの構築
    3. 組み込みFPGAテクノロジによる設計の簡素化
    4. 初めての VHDL プログラムの作成方法:Hello World!
    5. PMプログラムを最適化する方法
    6. 潤滑油分析プログラムを最大化する
    7. Verilog チュートリアル
    8. 機器の予防保守プログラムを設計する方法
    9. PM プログラムを改善する 10 のハック
    10. Ultiboard PCB 設計チュートリアル
    11. KiCAD PCB 設計チュートリアル