Getting started with FPGA programming - controlling LEDs - Page 1
Forum section: electronics / beginners

author: Digitalio
author_rank: Contributor
timestamp: May 22, 2020, 07:38:11 pm
content: I'm totally new to FPGAs and I'm trying to create a minimal app that blinks an on-board LED (I have Zybo Z7-20). I've found an example from "The Zynq Book", but it looks unnecessarily complex as it uses the CPU and AXI and I'd prefer to keep it as simple as possible and use programmable logic only.Can anyone point me to the right direction?

author: 0xcart
author_rank: Contributor
timestamp: May 22, 2020, 10:08:29 pm
content: Blinks an LED at approximately 0.75 seconds with a 100MHz clock input [100,000,000 / (2^27) = ~0.75]. Use Vivado to establish inputs and outputs. I've tested this with a Z7-20.Code:`timescale 1ns / 1psmodule test_led(input clk,input n_enabled,output blink);reg [26:0]counter = 0;always @(posedge clk) beginif (~n_enabled) begincounter <= counter + 1;endendassign blink = counter;endmodule

author: Digitalio
author_rank: Contributor
timestamp: May 22, 2020, 11:10:42 pm
content: Quote from: 0xcart on May 22, 2020, 10:08:29 pmThanks, but how do I do that?

author: rstofer
author_rank: Super Contributor
timestamp: May 23, 2020, 03:05:54 pm
content: You need to create a constraints file that defines all inputs and outputs. For the Vivado suite, this is a huge PITA to learn, far more complex than the older ISE approach. Fortunately, Digilent does the work for you with their Boards package.See section 3 of this document and follow the yellow brick road to install the Boards packagehttps://reference.digilentinc.com/vivado/installing-vivado/startSee section 6 of this document to include an .xdc file (constraints file) in your projecthttps://reference.digilentinc.com/vivado/getting_started/startGiven the board file pin/signal definitions, it is easier to make your port declaration match what is given than the other way around.

author: rstofer
author_rank: Super Contributor
timestamp: May 23, 2020, 03:43:29 pm
content: If you want to learn VHDL (as opposed to Verilog or System Verilog), look athttps://vhdlwhiz.com/The author tends to use the Lattice ICEstick 40 because it is cheap but with a wee bit of transmorgifying (PORT pin names for the IO) the projects should work on any board. The latest tutorial involves PWM to make an LED 'breathe' (go bright and dim slowly over time). Most of the tutorials are free.I highly recommend his 2 'for pay' projects. The larger project is expensive but it is a graduate program in simulation. I had never worked with simulation so I learned a lot. The good news is that I can come back and do the program again when I can't quite figure something out.https://www.digikey.com/catalog/en/partgroup/icestick-evaluation-board/40913The author uses ModelSim for simulation and that package works extremely well. Again, with a wee bit of a learning curve, you can do the simulation in Vivado. You can use any board supported by Vivado.

author: 0xcart
author_rank: Contributor
timestamp: May 23, 2020, 07:54:04 pm
content: If you haven't already, download the Zynq Book Tutorials for Zybo:http://www.zynqbook.com/download-tuts.htmlIt steps you through the basic processes of using Vivado to define IP modules.As stated previously, you will need to define constraints. Digilents website points you to their github repository which contains all of that information. If you look at the constraints file for the Zybo board you'll find that everything is commented out by default. For the simple LED example I posted earlier you'll need to un-comment the lines associated with the clock and one LED. And make sure you un-comment the second half of the statements as well (e.g. IO_L12P_T1_MRCC_35...). For reference:Code:##Clock signal#set_property -dict { PACKAGE_PIN K17 IOSTANDARD LVCMOS33 } [get_ports { sysclk }]; #IO_L12P_T1_MRCC_35 Sch=sysclk#create_clock -add -name sys_clk_pin -period 8.00 -waveform {0 4} [get_ports { sysclk }];andCode:#set_property -dict { PACKAGE_PIN M14 IOSTANDARD LVCMOS33 } [get_ports { led }]; #IO_L23P_T3_35 Sch=ledThen in the Vivado window where you drag-n-drop IP blocks, just make sure you name the inputs/outputs of the clock (when using the clock wizard) and LED to match the names above. In this case 'sysclk' and 'led'

author: 0xcart
author_rank: Contributor
timestamp: May 23, 2020, 07:57:06 pm
content: For Verilog and/or SystemVerilog assistance use:https://www.chipverify.com/verilog/verilog-syntaxandhttps://www.chipverify.com/systemverilog/systemverilog-tutorialI prefer SystemVerilog (and do not care for VHDL at all). But to each their own (like any language). Both serve their purpose well.

author: Digitalio
author_rank: Contributor
timestamp: May 24, 2020, 08:26:47 pm
content: Quote from: 0xcart on May 23, 2020, 07:54:04 pmI'm getting these critical warnings in the constraint file:Code:Synthesis[Vivado 12-4739] create_clock:No valid object(s) found for '-objects [get_ports sysclk]'. ["D:/Projects/LedTest/LedTest.srcs/constrs_1/new/Zybo-Z7-Master.xdc":9][Common 17-55] 'set_property' expects at least one object. ["D:/Projects/LedTest/LedTest.srcs/constrs_1/new/Zybo-Z7-Master.xdc":8]The lines looks like this:Code:##Clock signalset_property -dict { PACKAGE_PIN K17 IOSTANDARD LVCMOS33 } [get_ports { sysclk }]; IO_L12P_T1_MRCC_35 Sch=sysclkcreate_clock -add -name sys_clk_pin -period 8.00 -waveform {0 4} [get_ports { sysclk }];Any ideas what I'm doing wrong?

author: rstofer
author_rank: Super Contributor
timestamp: May 24, 2020, 09:09:55 pm
content: What's the name of your clock in the top level PORT block. Is it 'sysclk'?They all need to match. You can change them all to 'clk' but they all have to match.You probably can't uncomment things you aren't using. I haven't done that in a while but I think it is an error. So, uncomment just one of the LEDs, not all of them.

author: Digitalio
author_rank: Contributor
timestamp: May 25, 2020, 03:12:12 am
content: Quote from: rstofer on May 24, 2020, 09:09:55 pmI see, thanks. Now I can finish synthesis and run behavioral simulation, but nothing seems to happen. I ran it for 10 seconds but the counter doesn't increment and nothing changes at all. Any ideas how to make it work?

author: james_s
author_rank: Super Contributor
timestamp: May 25, 2020, 04:11:28 am
content: You mean in the simulator?I had a problem like that using the simulator in ISE, seems like the issue was that I had not assigned initial states to some of the signals.

author: Digitalio
author_rank: Contributor
timestamp: May 25, 2020, 04:34:41 am
content: Quote from: james_s on May 25, 2020, 04:11:28 amYes, in the simulator. The only input that I have in my Verilog file is clock, do I need to assign any initial state to it?

author: rstofer
author_rank: Super Contributor
timestamp: May 25, 2020, 03:06:01 pm
content: Simulation is an entirely separate subject. You need to write a 'testbench' (more VHDL code) that creates a virtual clock signal and connects it to your device under test (DUT). You link the testbench to the DUT with the same signals you already have in your PORT block.I'm not a fan of StackOverflow but this link seems to cover the materialhttps://stackoverflow.com/questions/17904514/vhdl-how-should-i-create-a-clock-in-a-testbenchTry VHDLwhiz.com and look at the free tutorials.If you are using Vivado, you need to create a VHDL file (testbench) in the simulations sources tree.You should be posting these questions in the FPGA forum where some really knowledgeable FPGA folks hang out.

author: Digitalio
author_rank: Contributor
timestamp: May 25, 2020, 04:10:01 pm
content: Quote from: rstofer on May 25, 2020, 03:06:01 pmThanks a lot.

author: rstofer
author_rank: Super Contributor
timestamp: May 25, 2020, 06:34:03 pm
content: Here's a testbench for a simple 7 segment display (which I gutted). The counter file is named top.vhd and you can see where work.top(rtl) is instantiated as the DUT.Fix up the port map to match your synthesis code and rename things as required.Code:library ieee;use ieee.std_logic_1164.all;use ieee.numeric_std.all;entity top_tb isend top_tb;architecture sim of top_tb isconstant clk_hz : integer := 100; -- simulation clock is 100 hzconstant clk_period : time := 1 sec / clk_hz;signal clk : std_logic := '1';signal rst_n : std_logic := '0';beginDUT : entity work.top(rtl)port map (clk => clk,rst_n => rst_n);CLOCK_PROC : processbeginwait for clk_period / 2;clk <= not clk;end process;RESET_PROC : processbeginfor count in 1 to 10 loopwait until clk = '1';end loop;rst_n <= '1';wait;end process;end architecture;I have gutted most of top.vhd as irrelevant to your project;Code:library ieee;use ieee.std_logic_1164.all;use ieee.numeric_std.all;entity top isport (clk : in std_logic;rst_n : in std_logic -- put a semicolon and add your LED port as an out.);end top;architecture rtl of top is-- put your port map and declarations here map clk, rst_n and LEDbegin-- put your code hereend architecture;Don't forget, the clk and rst signal need to match the constraints name if you intend to synthesize the code in top.vhdIMPORTANT! I did not test the code after I butched it. It used to work, now it may need some fixes. But the idea is right!The important stuff is in the testbench. Since you have the working code, all you need to do is bash over the testbench to make it fit signal names and such. Among other things, you need to carry the LED output through the port maps into the testbench and out on the testbench port map. It needs to be a real IO, just like clk and rst_n.