VHDL has always interested me, and having just received my new Arty S7-25 FPGA board from Digilent, I had a chance to try it out! I wanted to do something with the LEDs for my first project, so I made a few different patterns, and tied them together in the code so they display one after another.
Being new to VHDL, the code might not be up to par, but I will explain the best I can, and I hope you can get these cool patterns lighting up your FPGA board too!
We will be using the four standard LEDs located here on the board (not the RGB LEDs)
The general idea with the code is to have different counters controlling lengths of patterns that have enable signals. These enable signals are driven by a state machine. Another process
block decodes the enable signals, and determines what pattern should be shown on the LEDs.
The github repo can be found here. Take a look at the "src" folder to find the main entity.
To start, I have some signal declarations
-- enables for different patterns/counters
signal r_patt1_en : std_logic := '1';
signal r_patt2_en : std_logic := '0';
signal r_patt3_en : std_logic := '0';
signal r_patt4_en : std_logic := '0';
-- pattern counters
signal r_patt1_cntr : integer range 0 to 1e6 := 0;
signal r_patt1_light_LED : integer range 0 to 4 := 0;
signal r_patt2_cntr : integer range 0 to 2e6 := 0;
signal r_patt3_cntr : integer range 0 to 2e6 := 0;
signal r_patt3_alt_cntr : integer range 0 to 5 := 0;
signal r_patt4_duty : integer range 0 to 1e5 := 0;
signal r_patt4_cntr : integer range 0 to 1e5 := 0;
signal r_patt4_incr_duty : std_logic := '0';
The top section of the above code contains the enable signals for each pattern. Only one can be active per any given time. These signals help determine what pattern the LEDs should be following, as well as enabling counters specific to that pattern.
These are a few more of the other signals
-- indicates if pattern should be changed
signal r_change_pattern : std_logic := '0';
signal r_clk_cntr : integer range 0 to 36e6 := 0;
-- FSM
type t_state is (PATT1, PATT2, PATT3, PATT4);
signal STATE : t_state;
The entity needs to know when to change patterns (in this case, once every 3 seconds, or when r_clk_cntr
turns over), so r_change_pattern
is created. Additionally, the states for the state machine are declared here.
Lets get into one of the patterns.
Pattern 1 switches each LED one by one, like a shift register with a single 1 and the rest are zeros (hopefully that makes sense :p). The "on" LED is kept on for 83.333 ms (1/12th of a second was easy to implement with the 12 MHz system clock), and then a new LED is switched on every 83.333 ms. I created two separate processes for these counters.
-- pattern 1 counter keeps each LED on in pattern 1 for 83.333 ms
PATT1_CNTR_PROC : process(i_clk)
begin
if rising_edge(i_clk) then
if r_patt1_en = '0' then
r_patt1_cntr <= 0;
else
if r_patt1_cntr < 1e6 then
r_patt1_cntr <= r_patt1_cntr + 1;
else
r_patt1_cntr <= 0;
end if;
end if;
end if;
end process;
With a 12 MHz system clock, 1/12th of a second (or 1 million clk cycle counts), is a easy measure of time to use. r_patt1_cntr
counts up to this number before flipping over to 0, resulting in 1/12th of a second or 83.333 ms.
-- pattern 1 alt counter signals when to switch LEDs every 83.333 ms
PATT1_ALT_CNTR_PROC : process(i_clk)
begin
if rising_edge(i_clk) then
if r_patt1_en = '0' then
r_patt1_light_LED <= 0;
else
if r_patt1_cntr = 1e6 then
if r_patt1_light_LED < 4 then
r_patt1_light_LED <= r_patt1_light_LED + 1;
else
r_patt1_light_LED <= 0;
end if;
end if;
end if;
end if;
end process;
PATT1_ALT_CNTR_PROC
monitors r_patt1_cntr
and looks for the max value of 1e6. once this is done, r_patt1_light_LED
is incremented. This will determine which LED is on.
Further down in the code, we see PATT_DECODE_PROC.
This process (below) determines what should happen during a pattern when it is enabled.
PATT_DECODE_PROC : process(i_clk)
variable r_patt_en : std_logic_vector(3 downto 0);
begin
if rising_edge(i_clk) then
r_patt_en := r_patt1_en & r_patt2_en & r_patt3_en & r_patt4_en; -- cnct into vect
if r_patt_en = "1000" then -- blink LEDS in circle
case r_patt1_light_LED is
when 0 =>
r_LEDs <= "0001";
when 1 =>
r_LEDs <= "0010";
when 2 =>
r_LEDs <= "0100";
when 3 =>
r_LEDs <= "1000";
when 4 =>
r_LEDs <= "0000";
end case;
First, all the different pattern enables are concatenated into a single vector (r_patt_en
) for easy reading. Then, this is checked. If r_patt_en = "1000"
, meaning r_patt1_en
is active, pattern 1 will be shown on the LEDs. But, what happens during pattern 1?
Remember PATT1_ALT_CNTR_PROC
? That process incremented a signal named r_patt1_light_LED
, this signal is read by PATT_DECODE_PROC
(above) with a case statement, and lights up each LED corresponding to the value of r_patt1_light_LED
.
The rest of the patterns are coded in this way, with counters and enables, then the case statement in PATT_DECODE_PROC
lights up the LEDs. In addition to the example pattern above, there is a toggle pattern, a heart beat pattern, and a dimming pattern that uses PWM.
There is a testbench in the "sim" file on the github repo. If you choose to run a sim, just know it might take about 8 min (depending on your machine). Each pattern is displayed for 3 seconds, so the minimum sim time should be 12 seconds to see all 4 patterns.
Here is a picture of what my sim looked like at the end of a few min:
You can clearly see the shift-register-like behavior of the first pattern, and the heart beat pattern. The PWM dimming pattern at the end can only be viewed by zooming in.
Building the ProjectOpen Vivado and create a project. When prompted, select the "Arty S7-25" from the "Boards" menu.
If you don't see this, please update your board files with the Digilent ones found here.
Add the source, sim, and constraints files from the github repo, and generate the bitstream.
Program your board and you should see some neat patterns on the 4 LEDs :)
ConclusionThanks for following along with my first VHDL/Arty S7 project! Please modify the code to create your own patterns! Post any new patterns or questions in the comments. I would like to see what you create :)
Comments
Please log in or sign up to comment.