Introduction: FPGA LED Control Project
For our final project in Digital Design at Cal Poly, we were tasked with creating a project which conserved natural resources using an FPGA (field programmable gate array) board.
Our project is a simulation of a room in which lights are switched on/off based on the amount of people in the room. The switches of the FPGA board correspond to how many people are in the room (3 bits, or up to 7 people). The seven segment display of the board is used as a countdown timer in which the final light shut off after one minute when the room in vacated. The number of lights on will correlate to the amount of perceived people in the room (1 LED for 1 person, 2 LEDs for 2 people, 3 LEDs for 3 people, etc). The timer will reset to 60 seconds once the room is occupied again.
Step 1: Materials
- 8 Wires
- 7 LEDS
- 7 resistors (330 Ω)
- 1 MicroUSB cable
- 1 FPGA Basys 3 board
- 1 Breadboard
- 1 Computer with VHDL (not pictured)
Step 2: Setup
The hardware output of the project is the breadboard with the connected LEDs. The output on the LEDs are the result of the inputs on the FPGA Basys 3 board. Construct a simple LED resistor circuit on the breadboard as pictured above. The grounding of the circuit goes to GND of the PMOD port on the Basys 3. Repeat the process six more times in order to have seven separate LED resistor circuits. If there is any confusion as to how to make an LED resistor circuit, here is a great instructable by wrcoakle for reference:
It is very important to have a resistor of an appropriate value in each circuit as it will prevent the LEDs from being short-circuited and burnt out. The resistance of the LED alone is not enough to impede the voltage from the source. We used 330 Ωresistors.
Step 3: Clock Divider Module
Our clock module is nearly the same as the one provided to us in lab, with the exception of a different frequency. The purpose of the clock is to provide an oscillating signal which a circuit can utilize. Our intention was to use the clock divider module as a clock which counted actual seconds. In order to slow down the oscillating signal that the clock outputted, we had to change the frequency of the clock in order to output a signal every second.
entity clk_div2 is<br> Port ( clk : in std_logic; sclk : out std_logic); end clk_div2;
architecture my_clk_div of clk_div2 is constant max_count : integer := (50000000); signal tmp_clk : std_logic := '0'; begin my_div: process (clk,tmp_clk) variable div_cnt : integer := 0; begin if (rising_edge(clk)) then if (div_cnt = MAX_COUNT) then tmp_clk <= not tmp_clk; div_cnt := 0; else div_cnt := div_cnt + 1; end if; end if; sclk <= tmp_clk; end process my_div; end my_clk_div;
Step 4: LED Control Module
We create a little LED controller in VHDL using behavioral modelling. The LED control maps the switches to the seven segment display through the down counter module. If the enable switch is on and any other switches are on, the LED Control module will send a reset signal of 1 through the down counter module. The down counter module will then hold or reset the seven segment display to sixty seconds. If the enable switch is on and all other switches are off, the LED Control module will send a reset signal of 0 to the down counter module to start the countdown from sixty seconds. Turning on any of the switches during the countdown will send a signal of 1 to the down counter module which will reset the counter to sixty seconds. The LED control module acts as the signal producer while the down counter module executes the command to display the desired output.
entity LED_ctrl is<br> Port ( sw : in STD_LOGIC_VECTOR (2 downto 0); Reset : out STD_LOGIC); end LED_ctrl; architecture Behavioral of LED_ctrl is begin process (sw) begin if (sw /= "000") then Reset <= '1'; else Reset <= '0'; end if; end process; end Behavioral;
Step 5: Down Counter Module
The down counter is tied to the LED control and the clock in order to control the timing and the LED. The down counter starts at 60 seconds(in order to change the counting to seconds, we changed the frequency of the clock) and will begin counting down once there are no more people in the room. The counter will decrement by 1 in every clock cycle until it reaches 0 seconds. Once the down counter reaches down to 0 second, LED enable signal becomes 0 and all LEDs will be off. While the counter is counting down, if anyone enters the room during the time, the corresponding LED will turn on and the down counter will reset back to 60 seconds.
architecture Behavioral of counter is signal num: std_logic_vector(5 downto 0); begin process (en, reset, clk) begin if (en = '0') then LED_en <= '0'; else LED_en <= '1'; if(reset = '1') then num <= "111100"; else if (rising_edge(clk)) then if (num > 0) then num <= num - 1; end if; if (num = 0) then LED_en <= '0'; end if; end if; end if; end if; end process; Q <= num; end Behavioral;
Step 6: Seven Segment Display Module
The seven segment display is the same one we made from our lab earlier in the year. This is the mapping so that the seven segment display can display numbers converted from binary to decimal on the Basys 3 Board. The module takes in the 6 bit binary number from the counter and converts to decimal using a decoder with six multiplexers . Since our maximum display is only sixty seconds, only two of the four displays were necessary. And because we only need 6 bits to count up to 60, we added two zeros in the front in order to connect it with the 8 bit seven segment display module.
(The seven segment display VHDL file will be provided at the end of the instructable, as it is too long to include here)
Step 7: LED Decoder Module
The LED Decoder takes input signals from the switches and the LED enable signal from the down counter. The LED decoder's function is to convert the binary signals mapped from the switches to a BUS of LED signals. The BUS will then determine the corresponding amount of LEDs that are on. Our decoder is implemented with case statements and it does not actually convert binary inputs to decimal outputs, but the functionality of the circuit appears to do so, as the amount of LEDs on in decimal correlate to the binary number inputted.
entity LED_dec is<br> Port ( LED_en : in STD_LOGIC; sw : in STD_LOGIC_VECTOR (2 downto 0); ppl : out STD_LOGIC_VECTOR (6 downto 0)); end LED_dec;
architecture Behavioral of LED_dec is
begin process (LED_en, sw) begin if (LED_en = '1') then case sw is when "000" => ppl <= "0000001"; when "001" => ppl <= "0000001"; when "010" => ppl <= "0000011"; when "011" => ppl <= "0000111"; when "100" => ppl <= "0001111"; when "101" => ppl <= "0011111"; when "110" => ppl <= "0111111"; when "111" => ppl <= "1111111"; when others => ppl <= "0000000"; end case; end if;
The LED signals all become 0 when LED signal is 0.
if (LED_en = '0') then ppl <= "0000000"; end if; end process;
Step 8: Main Module
This is where it all comes together. As you can see, there are 5 blocks in the schematic which correspond to the 5 modules of our design. The inputs of a clock, an enable signal, and 3 switches correspond to outputs on the seven segment display and 7 LEDs.
The first two modules the signals must go through are the clock divider and the LED control modules. The clock is almost identical to the one we are given in lab, with the exception of a changed frequency. This allows the counter to count down from sixty seconds accurately. The LED control takes the inputs of the switches and converts them into signals for the Down Counter to use. The LED Control determines whether or not a reset signal is sent to the Down Counter.
The Down Counter module takes the revised clock signal along with the enable and reset signals and uses these values to do most of the calculations in our circuit. The Down Counter takes these signals and puts them through a behavioral circuit. The outputs of the Down Counter input into the seven segment display and the LED Decoder.
The output of the Down Counter determines what is display on the seven segment display, such as whether or not it is reset to 60 seconds or if it is counting down. The Down Counter also outputs signals to the LED decoder, which decides how many LEDs are on based on the signals,
entity sixty_sec_counter is Port ( SW: in STD_LOGIC_VECTOR (2 downto 0); CLK, EN: in STD_LOGIC; SEG : out STD_LOGIC_VECTOR (7 downto 0); AN : out STD_LOGIC_VECTOR (3 downto 0); LED_EN : out STD_LOGIC_VECTOR (6 downto 0)); end sixty_sec_counter;
architecture Behavioral of sixty_sec_counter is component clk_div2 Port (clk : in std_logic; sclk : out std_logic); end component clk_div2;
component counter Port(en, reset, clk : in std_logic; LED_en: out std_logic; Q : out std_logic_vector(5 downto 0)); end component counter;
component sseg_dec Port (ALU_VAL : in std_logic_vector(7 downto 0); SIGN : in std_logic; VALID : in std_logic; CLK : in std_logic; DISP_EN : out std_logic_vector(3 downto 0); SEGMENTS : out std_logic_vector(7 downto 0)); end component sseg_dec; component LED_ctrl Port ( sw : in STD_LOGIC_VECTOR (2 downto 0); Reset : out STD_LOGIC); end component LED_ctrl; component LED_dec Port ( LED_en : in STD_LOGIC; sw : in STD_LOGIC_VECTOR (2 downto 0); ppl : out STD_LOGIC_VECTOR (6 downto 0)); end component LED_dec; signal c_temp: std_logic_vector (7 downto 0); signal s_clk: std_logic; signal s_reset: std_logic; signal s_en: std_logic; begin
--we added two zeros in the front in order to connect it with the 8 bit seven segment display module. c_temp(6) <= '0'; c_temp(7) <= '0'; display: sseg_dec Port Map (CLK => clk, VALID => '1', SIGN => '0', SEGMENTS => SEG, DISP_EN = > AN, ALU_VAL => c_temp); d: counter Port Map (en => EN, reset => s_reset , Q => c_temp(5 downto 0), clk => s_clk, LED_ en => s_en ); clock: clk_div2 Port Map (sclk => s_clk, clk => CLK); control: LED_ctrl Port Map (sw => SW, Reset => s_reset); decoder: LED_dec Port Map (LED_en => s_en, sw => SW, ppl => LED_EN); end Behavioral;
Step 9: Upload the VHDL Files to Your FPGA
Attached in this step is a zip file including all of the VHDL modules.
Below is the demonstration of the project.