첫 FPGA 프로젝트: LED 블링크 튜토리얼 (VHDL & Verilog)
소개
VHDL 또는 Verilog로 FPGA에서 간단한 LED 블링커를 만드는 실습 가이드에 오신 것을 환영합니다. 이 예제는 동시 프로세스, 주파수 합성, 멀티플렉서 로직 등 25MHz 클록으로 구동되는 핵심 FPGA 개념을 보여줍니다.
프로젝트 개요
- 선택 가능한 4가지 블링크 주파수 생성: 100Hz, 50Hz, 10Hz, 1Hz.
- 각 주파수 50% 듀티 사이클 유지.
LED_EN 스위치 어서트 시에만 LED 활성화.
- 두 독립 스위치로 원하는 주파수 선택.
- 하드웨어 배포 전 시뮬레이션 필수로 조기 오류 포착.
주파수 선택 진리표
| Enable | Switch 1 | Switch 2 | LED 구동 주파수 |
| 0 | - | - | (비활성화) |
| 1 | 0 | 0 | 100 Hz |
| 1 | 0 | 1 | 50 Hz |
| 1 | 1 | 0 | 10 Hz |
| 1 | 1 | 1 | 1 Hz |
신호 정의
| 신호명 | 방향 | 설명 |
| i_clock | 입력 | 25 MHz 시스템 클록 |
| i_enable | 입력 | LED 활성화 스위치 (로직 0 = 끔) |
| i_switch_1 | 입력 | 주파수 선택 비트 1 |
| i_switch_2 | 입력 | 주파수 선택 비트 0 |
| o_led_drive | 출력 | LED 구동 신호 |
설계 철학
네 개의 독립적인 카운터 프로세스가 동시에 실행되며, 각각 로컬 신호를 목표 주파수로 토글합니다. 특정 주파수가 선택되지 않아도 해당 카운터는 계속 실행됩니다. 이것이 FPGA 동시성의 특징입니다.
스위치는 원하는 토글 신호를 LED 드라이버로 라우팅하는 조합 멀티플렉서를 구현합니다. LED_EN 스위치는 활성 하이 게이트 역할을 해 활성화 낮으면 LED가 꺼지도록 합니다.
블록 다이어그램
VHDL 구현
아래는 사양을 만족하는 완전 주석 달린 VHDL 모듈입니다. 카운터 상수는 다음 공식으로 계산:
count = (클록 주파수 / 목표 주파수) × 0.5로 50% 듀티 사이클 달성.
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 -- 주파수 상수 (반주기 카운트) constant c_CNT_100HZ : natural := 125000; -- 25 MHz / 100 Hz × 0.5 constant c_CNT_50HZ : natural := 250000; -- 25 MHz / 50 Hz × 0.5 constant c_CNT_10HZ : natural := 1250000; -- 25 MHz / 10 Hz × 0.5 constant c_CNT_1HZ : natural := 12500000; -- 25 MHz / 1 Hz × 0.5 -- 카운터 신호 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; -- 토글 출력 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'; -- 멀티플렉서 선택 signal w_LED_SELECT : std_logic; begin -- 100 Hz 토글 프로세스 p_100_HZ : process (i_clock) is begin if rising_edge(i_clock) then if r_CNT_100HZ = c_CNT_100HZ-1 then 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; -- 50 Hz 토글 프로세스 p_50_HZ : process (i_clock) is begin if rising_edge(i_clock) then if r_CNT_50HZ = c_CNT_50HZ-1 then 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; -- 10 Hz 토글 프로세스 p_10_HZ : process (i_clock) is begin if rising_edge(i_clock) then if r_CNT_10HZ = c_CNT_10HZ-1 then 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; -- 1 Hz 토글 프로세스 p_1_HZ : process (i_clock) is begin if rising_edge(i_clock) then if r_CNT_1HZ = c_CNT_1HZ-1 then 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; -- 스위치 입력 기반 멀티플렉서 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; -- 활성화 스위치로 LED 구동 게이팅 o_led_drive <= w_LED_SELECT and i_enable; end rtl;
Verilog 구현
아래는 동등한 Verilog 모듈입니다. 설계 철학은 동일—네 독립적 always 블록이 각 주파수로 토글, 스위치로 구동되는 조합 멀티플렉서.
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; // 주파수 파라미터 (반주기 카운트) parameter c_CNT_100HZ = 125000; parameter c_CNT_50HZ = 250000; parameter c_CNT_10HZ = 1250000; parameter c_CNT_1HZ = 12500000; // 카운터 레지스터 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; // 토글 레지스터 reg r_TOGGLE_100HZ = 1'b0; reg r_TOGGLE_50HZ = 1'b0; reg r_TOGGLE_10HZ = 1'b0; reg r_TOGGLE_1HZ = 1'b0; // 멀티플렉서 선택 reg r_LED_SELECT; wire w_LED_SELECT; // 100 Hz 토글 블록 always @(posedge i_clock) begin if (r_CNT_100HZ == c_CNT_100HZ-1) begin r_TOGGLE_100HZ <= ~r_TOGGLE_100HZ; r_CNT_100HZ <= 0; end else r_CNT_100HZ <= r_CNT_100HZ + 1; end // 50 Hz 토글 블록 always @(posedge i_clock) begin if (r_CNT_50HZ == c_CNT_50HZ-1) begin r_TOGGLE_50HZ <= ~r_TOGGLE_50HZ; r_CNT_50HZ <= 0; end else r_CNT_50HZ <= r_CNT_50HZ + 1; end // 10 Hz 토글 블록 always @(posedge i_clock) begin if (r_CNT_10HZ == c_CNT_10HZ-1) begin r_TOGGLE_10HZ <= ~r_TOGGLE_10HZ; r_CNT_10HZ <= 0; end else r_CNT_10HZ <= r_CNT_10HZ + 1; end // 1 Hz 토글 블록 always @(posedge i_clock) begin if (r_CNT_1HZ == c_CNT_1HZ-1) begin r_TOGGLE_1HZ <= ~r_TOGGLE_1HZ; r_CNT_1HZ <= 0; end else r_CNT_1HZ <= r_CNT_1HZ + 1; end // 조합 멀티플렉서 always @(*) begin case ({i_switch_1, i_switch_2}) 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 // 활성화 게이팅으로 LED 구동 assign o_led_drive = r_LED_SELECT & i_enable; endmodule
시뮬레이션 & 검증
FPGA 프로그래밍 전 행동 시뮬레이션(ModelSim, VCS, Vivado Simulator 등) 실행. 각 토글 신호가 예상 주기와 일치하는지, 멀티플렉서가 스위치 조합에 따라 신호를 올바르게 라우팅하는지 검증. 조기 시뮬레이션으로 비용 큰 하드웨어 디버깅 방지, 50% 듀티 사이클 유지 확인.
결론
이 튜토리얼은 다른 타이밍 작업에 적용 가능한 콤팩트하고 재사용 가능한 LED 블링커 구축법을 보여줍니다. 같은 카운터 기반 주파수 합성 패턴이 더 복잡한 상태 머신으로 확장돼 FPGA 개발자의 기초 기술이 됩니다.