Women's Day Gift by FPGA
Hello! On the eve of March 8, I decided to make my beloved a small gift using the tools that I most often have to use at work. Having a little free time, I thought, why not write a small article on the topic about it. This is a great opportunity to congratulate all the ladies and, in particular, the few female members of the community habrahabr. Article written by " just for fun"and has no scientific contribution, does not carry much semantic load, but it may be useful for novice developers in the field of FPGAs. I will tell you what tools are used to get the final result and what came of it. In the article you will see flickering hearts and running text on 8x8 LED matrix, which is controlled by a small old FPGA. At the end of the article you will find a video demonstration of FPGA collaboration and a matrix of LEDs.


The project is implemented on a debug board with FPGA Spartan3E. It contains the simplest strapping by various interfaces (VGA, PS / 2), it has LEDs and an LED display, as well as flip-flops, buttons and various other outputs for connecting something third-party. The fee is very cheap, ordered from ebay at one of the Chinese stores. Price - $ 135.00 including shipping (~ 4000r at old prices).
The official website of the manufacturer is currently dead , which is not surprising.
The main features of the board:
The resources of the Spartan3E XC3S500E FPGA crystal are shown in the table:

For simple projects and an initial acquaintance with the FPGA design, this is more than enough.
A matrix of LED8x8 LEDs is connected to the FPGA. Obviously, each LED does not connect directly, because it will require the use of 64 FPGA pins, which is very expensive and unwise! Below is a diagram of the Chinese datasheet on the debug board. It can be seen that the LEDs are connected in columns and rows of 8 pieces, and the connection is not directly, but through PNP-transistors. The emitter of the transistor is connected to the supply voltage, the base to the FPGA contacts, and the collector to the matrix of LEDs. In total, 16 contacts are connected to the FPGA. The control logic of the LED matrix is negative , that is, the LEDs are lit with a low logic level (log. 0).

This means that if you set the required logical level on a particular row and column, then a certain LED will light up.
Examples:
A) if the vector LEDY = “11111110”, and the vector LEDX = “11111110”, the single LED in the lower right corner will light up.
11111111
11111111
11111111
11111111
11111111
11111111
11111111
11111110
B) if the vector LEDY = “11111110” and the vector LEDX = “00000000”, then the entire bottom line will light up.
11111111
11111111
11111111
11111111
11111111
11111111
11111111
00000000
V) if the vector LEDY = "00000000" and the vector LEDX = "11111110", then the entire right column will light up.
11111110
11111110
11111110
11111110
11111110
11111110
11111110
11111110
D) if the vector LEDY = “00000000” and the vector LEDX = “00000000”, then the whole array of LEDs will light up.
In this regard, there is a certain difficulty . How to light a matrix of LEDs in such a way that a certain character in the form of a letter or number is displayed on it? In fact, it is not difficult.
The process of displaying characters on a matrix of LEDs is quite simple. First, it is necessary to organize a counter of a certain digit capacity and use its three most significant digits to switch the LEDY vector. Why three digits? Switching 8-bit vector can be described using a finite state machine using 3 control bits. In VHDL, it is done like this:
Counter
The first reset (rst) is global. The second reset (rst_reg) is software and is controlled by a trigger.
State machine for LEDY
Changing the state of the counter includes one bit in the LEDY column of LEDs. Thus, the running zero scheme is organized .
Next, we need two more state machines with exactly the same logic for organizing the vector of lines LEDX . In principle, one can do without one, but it is clearer to do it in a manner similar to the column vector.
Intermediate Spacecraft
KA for vector LEDX
As a result of these actions, the LEDX vector is formed . It is this vector that draws the symbols on the LED matrix, and the LEDY vector is responsible for the timely shutdown of unnecessary LEDs. In this example, the cross or the symbol “X” should light up on the LED matrix , which can be visually observed if you look closely at the last state machine. Thus, the column vector becomes auxiliary, and the row vector draws characters and with its help you can “write” anything on the LED matrix.
The project made two files of the same type of generation of symbols on a matrix of LEDs. In the first block, the heart is displayed, and in the second, the text “MARCH 8!” Is displayed using the ROM-memory design. Symbols of the text are in memory and they must be properly addressed. Since the display process is fast enough, it is necessary to adjust the output frequency so that the characters can be read. To do this, you need to create an additional counter for 27 bits, which will divide the input frequency 50 MHz by 2 ^ 27 and allow our eye to observe the change of characters on the matrix of LEDs.
Character codes are stored in memory as a two-dimensional array. 8-bit numbers vary depending on the logic of the finite state machine (for outputting the character to the LEDs), and also depending on the address (in order to change the character on the matrix of LEDs):
Agree that if you just light a symbol on the matrix, is it a bit boring? In the project you need to add special effects in the form of blinking and running lights. Make it very easy. This requires the well-known PWM algorithm (pulse width modulation). With its help, you can control the power that is supplied to the load (that is, regulate the current). This is done by varying the pulse duty cycle at a constant signal frequency.
I will not tell you how to make PWM on the FPGA, many articles have been written about it. The basic principle is that the change in the pulse duration of zeros and ones is organized on several controlled meters. In my project, you can control both the PWM itself (by changing the speed of the counters by increasing the count), and changing the speed of data output to the LED matrix, changing the counter width for the LEDY column vector (by selecting the required bit fields). Taken together, this allows you to get various effects of twinkling, fading and running lights, which can be seen in the final video.
The FPGA project consists of several parts: these are the source code files in the VHDL language, which describe the algorithm of the microcircuit operation, and the UCF restriction file, which defines the connection of the FPGA contacts, their standard, output current, speed, limits on clock frequencies in the project, etc.
Pinout contacts in UCF
Top-level vhdl file
Port Description:
The schematic view of the project after the synthesis process is shown in the figure below. It contains input and output buffers, a DCM node, three knockout bounce contacts for buttons and three functional nodes: PWM control, a generator of symbols on a LED8x8 LED array, and a heart output on the matrix.

After synthesis, placement and tracing the project in the FPGA looks like this:

As you can see, the FPGA is generally empty. For the resources used, the results are also shown in the figure above.
So, after the correct firmware has been loaded into the FPGA and the necessary buttons are pressed, and the switches are in the correct position, the LED matrix should “come to life” and show the following features:
Picture: heart

Video: Shimmering and running heart
Video: Text “MARCH 8!”:
The project was created in the VHDL language in Xilinx ISE CAD. Work: 1 evening (project creation) + 2 pm (writing article). The source code is posted on github , if someone is interested in doing something like this.
Once again I want to congratulate all women on the upcoming holiday. I wish you all happiness, warmth and love! In particular, I convey greetings to my beloved wife.
Thanks for attention!


Tool
The project is implemented on a debug board with FPGA Spartan3E. It contains the simplest strapping by various interfaces (VGA, PS / 2), it has LEDs and an LED display, as well as flip-flops, buttons and various other outputs for connecting something third-party. The fee is very cheap, ordered from ebay at one of the Chinese stores. Price - $ 135.00 including shipping (~ 4000r at old prices).
The official website of the manufacturer is currently dead , which is not surprising.
The main features of the board:
- FPGA Spartan3E ( XC3S500E-4PQ208C ) - 500K logic gates,
- Clock source CLK = 50 MHz,
- 64M SDRAM external memory,
- SPI Flash (M25P80) for storing FPGA firmware,
- LED matrix LED 8x8, LED line 8 pcs.,
- 8 trigger switches and 5 buttons
- Connectors for two LED displays,
- VGA connector for connecting a monitor,
- PS / 2 connectors, etc.
The resources of the Spartan3E XC3S500E FPGA crystal are shown in the table:

For simple projects and an initial acquaintance with the FPGA design, this is more than enough.
LED matrix
A matrix of LED8x8 LEDs is connected to the FPGA. Obviously, each LED does not connect directly, because it will require the use of 64 FPGA pins, which is very expensive and unwise! Below is a diagram of the Chinese datasheet on the debug board. It can be seen that the LEDs are connected in columns and rows of 8 pieces, and the connection is not directly, but through PNP-transistors. The emitter of the transistor is connected to the supply voltage, the base to the FPGA contacts, and the collector to the matrix of LEDs. In total, 16 contacts are connected to the FPGA. The control logic of the LED matrix is negative , that is, the LEDs are lit with a low logic level (log. 0).

This means that if you set the required logical level on a particular row and column, then a certain LED will light up.
Examples:
A) if the vector LEDY = “11111110”, and the vector LEDX = “11111110”, the single LED in the lower right corner will light up.
11111111
11111111
11111111
11111111
11111111
11111111
11111111
11111110
B) if the vector LEDY = “11111110” and the vector LEDX = “00000000”, then the entire bottom line will light up.
11111111
11111111
11111111
11111111
11111111
11111111
11111111
00000000
V) if the vector LEDY = "00000000" and the vector LEDX = "11111110", then the entire right column will light up.
11111110
11111110
11111110
11111110
11111110
11111110
11111110
11111110
D) if the vector LEDY = “00000000” and the vector LEDX = “00000000”, then the whole array of LEDs will light up.
In this regard, there is a certain difficulty . How to light a matrix of LEDs in such a way that a certain character in the form of a letter or number is displayed on it? In fact, it is not difficult.
Display characters on LEDs
The process of displaying characters on a matrix of LEDs is quite simple. First, it is necessary to organize a counter of a certain digit capacity and use its three most significant digits to switch the LEDY vector. Why three digits? Switching 8-bit vector can be described using a finite state machine using 3 control bits. In VHDL, it is done like this:
Counter
pr_cnt: process(clk, rst) isbeginif (rst = '0') then
cnt_led <= (others => '0');
elsif rising_edge(clk) thenif (rst_reg = '0') then
cnt_led <= (others => '0');
else
cnt_led <= cnt_led + '1';
endif;
endif;
endprocess;The first reset (rst) is global. The second reset (rst_reg) is software and is controlled by a trigger.
State machine for LEDY
pr_3x8: process(cnt_cmd) isbegincase cnt_cmd iswhen"000" => en_xhdl <= "11111110";
when"001" => en_xhdl <= "11111101";
when"010" => en_xhdl <= "11111011";
when"011" => en_xhdl <= "11110111";
when"100" => en_xhdl <= "11101111";
when"101" => en_xhdl <= "11011111";
when"110" => en_xhdl <= "10111111";
whenothers => en_xhdl <= "01111111";
endcase;
endprocess;Changing the state of the counter includes one bit in the LEDY column of LEDs. Thus, the running zero scheme is organized .
Next, we need two more state machines with exactly the same logic for organizing the vector of lines LEDX . In principle, one can do without one, but it is clearer to do it in a manner similar to the column vector.
Intermediate Spacecraft
pr_8x4: process(en_xhdl) isbegincase en_xhdl iswhen"11111110" => led_cmd <= "000";
when"11111101" => led_cmd <= "001";
when"11111011" => led_cmd <= "010";
when"11110111" => led_cmd <= "011";
when"11101111" => led_cmd <= "100";
when"11011111" => led_cmd <= "101";
when"10111111" => led_cmd <= "110";
whenothers => led_cmd <= "111";
endcase;
endprocess;KA for vector LEDX
pr_ledx: process(led_cmd) isbegincase led_cmd iswhen"000" => ledx <= "01111110";
when"001" => ledx <= "10111101";
when"010" => ledx <= "11011011";
when"011" => ledx <= "11100111";
when"100" => ledx <= "11100111";
when"101" => ledx <= "11011011";
when"110" => ledx <= "10111101";
whenothers =>ledx <= "01111110";
endcase;
endprocess;As a result of these actions, the LEDX vector is formed . It is this vector that draws the symbols on the LED matrix, and the LEDY vector is responsible for the timely shutdown of unnecessary LEDs. In this example, the cross or the symbol “X” should light up on the LED matrix , which can be visually observed if you look closely at the last state machine. Thus, the column vector becomes auxiliary, and the row vector draws characters and with its help you can “write” anything on the LED matrix.
The project made two files of the same type of generation of symbols on a matrix of LEDs. In the first block, the heart is displayed, and in the second, the text “MARCH 8!” Is displayed using the ROM-memory design. Symbols of the text are in memory and they must be properly addressed. Since the display process is fast enough, it is necessary to adjust the output frequency so that the characters can be read. To do this, you need to create an additional counter for 27 bits, which will divide the input frequency 50 MHz by 2 ^ 27 and allow our eye to observe the change of characters on the matrix of LEDs.
Character codes are stored in memory as a two-dimensional array. 8-bit numbers vary depending on the logic of the finite state machine (for outputting the character to the LEDs), and also depending on the address (in order to change the character on the matrix of LEDs):
type rom_type isarray (7downto0) ofstd_logic_vector(7downto0);
type rom_8x8 isarray (0to7) of rom_type;
constant ROM_TEXT: rom_8x8:=(
(
"11000011",
"10011001",
"00111101",
"00111111",
"00111111",
"00111101",
"10011001",
"11000011")
... /cut
-- вывод данных на матрицу из 2D-массива:
pr_8x8: process(clk, rst) isbeginif (rst = '0') then
data_led <= (others => '0');
elsif rising_edge(clk) then
data_led <= ROM_TEXT(CONV_INTEGER(addr_txt(Na-1downto Na-3)))(CONV_INTEGER(led_cmd));
endif;
endprocess;
Special effects
Agree that if you just light a symbol on the matrix, is it a bit boring? In the project you need to add special effects in the form of blinking and running lights. Make it very easy. This requires the well-known PWM algorithm (pulse width modulation). With its help, you can control the power that is supplied to the load (that is, regulate the current). This is done by varying the pulse duty cycle at a constant signal frequency.
I will not tell you how to make PWM on the FPGA, many articles have been written about it. The basic principle is that the change in the pulse duration of zeros and ones is organized on several controlled meters. In my project, you can control both the PWM itself (by changing the speed of the counters by increasing the count), and changing the speed of data output to the LED matrix, changing the counter width for the LEDY column vector (by selecting the required bit fields). Taken together, this allows you to get various effects of twinkling, fading and running lights, which can be seen in the final video.
FPGA Project
The FPGA project consists of several parts: these are the source code files in the VHDL language, which describe the algorithm of the microcircuit operation, and the UCF restriction file, which defines the connection of the FPGA contacts, their standard, output current, speed, limits on clock frequencies in the project, etc.
Pinout contacts in UCF
## BUTTONS = ## K1-K5
NET "KB[5]" LOC = P54;
NET "KB[4]" LOC = P58;
NET "KB[3]" LOC = P57;
NET "KB[2]" LOC = P159;
NET "KB[1]" LOC = P154;
## LEDS = ## LED_MATRIX
NET "LED_X<7>" LOC = "P49"| IOSTANDARD = LVTTL | DRIVE = 8;
NET "LED_X<6>" LOC = "P48"| IOSTANDARD = LVTTL | DRIVE = 8;
NET "LED_X<5>" LOC = "P40"| IOSTANDARD = LVTTL | DRIVE = 8;
NET "LED_X<4>" LOC = "P50"| IOSTANDARD = LVTTL | DRIVE = 8;
NET "LED_X<3>" LOC = "P62"| IOSTANDARD = LVTTL | DRIVE = 8;
NET "LED_X<2>" LOC = "P98"| IOSTANDARD = LVTTL | DRIVE = 8;
NET "LED_X<1>" LOC = "P64"| IOSTANDARD = LVTTL | DRIVE = 8;
NET "LED_X<0>" LOC = "P63"| IOSTANDARD = LVTTL | DRIVE = 8;
NET "LED_Y<7>" LOC = "P75"| IOSTANDARD = LVTTL | DRIVE = 8;
NET "LED_Y<6>" LOC = "P78"| IOSTANDARD = LVTTL | DRIVE = 8;
NET "LED_Y<5>" LOC = "P76"| IOSTANDARD = LVTTL | DRIVE = 8;
NET "LED_Y<4>" LOC = "P69"| IOSTANDARD = LVTTL | DRIVE = 8;
NET "LED_Y<3>" LOC = "P74"| IOSTANDARD = LVTTL | DRIVE = 8;
NET "LED_Y<2>" LOC = "P65"| IOSTANDARD = LVTTL | DRIVE = 8;
NET "LED_Y<1>" LOC = "P68"| IOSTANDARD = LVTTL | DRIVE = 8;
NET "LED_Y<0>" LOC = "P77"| IOSTANDARD = LVTTL | DRIVE = 8;
NET "RESET" LOC = P148 | IOSTANDARD = LVTTL;
NET "CLK" LOC = P183 | IOSTANDARD = LVCMOS33;
NET "CLK_IN" TNM_NET = "CLK_TN";
TIMESPEC TS_CLK = PERIOD "CLK_TN"20 ns HIGH 50 %;
Top-level vhdl file
entity top_xc3s500e_heart isport(
---- SWITCHES ----
RESET : instd_logic; --! asycnchronous reset: SW(0)
SW : instd_logic_vector(7downto1); --! other switches---- CLOCK 50 MHz ----
CLK : instd_logic; --! main clock 50 MHz---- LED DISPLAY ----
LED_X : outstd_logic_vector(7downto0); --! LEDs Y
LED_Y : outstd_logic_vector(7downto0); --! LEDs X ---- BUTTONS ----
KB : instd_logic_vector(5downto1); --! Five Buttons
);
end top_xc3s500e_heart;Port Description:
- RESET - global reset (switch SW [0]),
- CLK - 50 MHz clock speed,
- SW <1> is the PWM resolution,
- SW <2> - heart control mode,
- SW <3> - 8x8 matrix reset,
- SW <4> - switching blocks HEART / TEXT,
- KB <1> - PWM master counter speed control (total period),
- KB <2> - Control the speed of the secondary PWM counter (pulse duty cycle),
- KB <3> - Change control of the 8x8 matrix counter (for the LEDY vector).
- LED_X is the vector of rows of the LED matrix,
- LED_Y is a vector of LED matrix columns,
The schematic view of the project after the synthesis process is shown in the figure below. It contains input and output buffers, a DCM node, three knockout bounce contacts for buttons and three functional nodes: PWM control, a generator of symbols on a LED8x8 LED array, and a heart output on the matrix.

After synthesis, placement and tracing the project in the FPGA looks like this:

As you can see, the FPGA is generally empty. For the resources used, the results are also shown in the figure above.
Result
So, after the correct firmware has been loaded into the FPGA and the necessary buttons are pressed, and the switches are in the correct position, the LED matrix should “come to life” and show the following features:
Picture: heart

Video: Shimmering and running heart
Video: Text “MARCH 8!”:
The project was created in the VHDL language in Xilinx ISE CAD. Work: 1 evening (project creation) + 2 pm (writing article). The source code is posted on github , if someone is interested in doing something like this.
Once again I want to congratulate all women on the upcoming holiday. I wish you all happiness, warmth and love! In particular, I convey greetings to my beloved wife.
Thanks for attention!