In my last few columns, I've taken an existing command-line tutorial and brought it up in the Xilinx ISE development environment. That's an important first step, but now it's time to start doing something of my own. I'll begin simply, borrowing heavily from the example we just completed. Basically, I'm going to edit the counter back to four light-emitting diodes (LEDs) -- the way it was before we modified it -- and then add in some logic to "Start" and "Stop" the count sequence being displayed on the LEDs.
Today, we are going to:
Create a new project called "led_input"
Use most of the code from our prior example
Change a few names to better fit what we're doing
Take the two extra LEDs out of the register and turn them into independent outputs
Add two switch inputs
See what happens next...
You will need:
Your Spartan-6 LX9 development board plugged into your computer
The two LEDs with pigtail wires that we created in our earlier columns
Two switches with pigtail wires soldered to them so they can be plugged into the header block on the FPGA board
The old code from "ledflash_ISE_ver" (or the "led_input.v" file from this blog) opened in a text editor
To start, we need to follow the steps I outlined in an earlier column. (See: Discovering FPGAs: Bringing Up the IDE.) Start up ISE and create your empty project (Steps 1 through 4 in that prior column). The only difference so far is that this one will be named "led_input." Next, when you open the New Source Wizard, we'll start to see some differences. Define your ports as shown in the following image:
Define module
"CLK_66MHZ" and "USER_RESET" are the same as in our last project. The inputs "START_COUNT" and "STOP_COUNT" will be our new switch inputs. I changed the name of the port from plain "LED" to "COUNTING_LEDS" because non-descriptive names kind of drive me nuts. This is especially true in the case of something like "LED" when I also have to reference the physical light emitting diodes. "COUNTING_LEDS" is still marked as a bus, but the MSB is now 3 instead of 5.
"LED_STARTED" and "LED_STOPPED" will be the extra LEDs (you see -- now I can just say "LEDs," instead of spelling out the acronym, and not get confused) that we stuck into the header J5 in an earlier column. This time, however, they aren't assigned to be part of the main port; instead, they will be used as visual indicators displaying the status of the two switches we are going to add.
Re: "because non-descriptive names kind of drive me nuts"
I am 100% with you on that statement!
Re: "(you see -- now I can just say "LEDs," instead of spelling out the acronym, and not get confused)"
In the sentence above, I think you meant to say can't just say...
Re: "but is this all starting to make sense?"
Yuuup! I am still following you perfectly and I don't even have the Spartan-6 LX9 development board. :-) Your photos and screen shots make it very easy to follow.
Max Maxfield 7/23/2012 5:30:58 PM User Rank Blogger
Re: Excellent post!
@Brian: Actually, I think Duane meant what he said ... now he can just say "LEDs" when he wants to use that in a sentence without it being confused with "LEDS" as a signal name ... but I may be wrong :-)
Duane Benson 7/23/2012 5:44:56 PM User Rank Blogger
Re: Excellent post!
Thanks! I'm glad you like the post.
I think the confusion surrounding my wording in the sentence: "now I can just say 'LEDs,' instead of spelling out the acronym" pretty much makes my point about the confusion. I suppose I should have said something more like: "now rather than spelling out the word 'light emitting diode', I can use the acronym 'LED' to refer to the physical component."
@Duane Benson, your posts are really helping me along with FPGA basics.
2 questions (wishes, perhaps):
1) Is there a way to magnify the text graphics so text is more easily readable?
2) Actually addressing this to Xilinx, is there anyway to lower the cost of a Spartan 6 LX-9 for members so as to actually be able to replicate Duane's blogs at hand?
@Brian, as you say, this is understandable without the board and for that I am grateful. Having a board to work with, though, greatly increases my comprehension and retained memory. Guess it is just the way I learn.
@Bill: Re: "2) Actually addressing this to Xilinx"
I think your question might need to be addressed to Avnet. According to the website, the Xilinx Spartan-6 FPGA LX9 MicroBoard is designed by Avnet. And, it is also sold by Avnet.
@Brian, thank you kindly; you are correct--the Avnet route is the way to pursue this. I can no way represent speaking for APP, but it is worth it to put in a request. Thanks for the info!
@Bill: welcome. I bet Max either knows someone at Avnet or knows someone who knows someone at Avnet :-) We'll have to wait for Max's response to your request...
Max Maxfield 7/24/2012 9:43:03 AM User Rank Blogger
Re: Excellent post!
@Bill: Re the text on the graphics -- that's my bad -- Duane gave me full-size images and I shrank them to fit in the space provided -- and to save time I didn't bother uploading the full-size versions to my server and linking to them (obviously I ended up not saving myself any time at all -- grin).
It's too late to go back to change the article, but here are links to the full-size versions of the two images:
Max Maxfield 7/24/2012 9:45:10 AM User Rank Blogger
Re: Excellent post!
@Bill: I agree that having the board really does help the leading process -- I think these boards are $89 -- I have no idea if we can get a special deal for members of All Programmable Planet, but I can certainly ask :-)
Paul Clarke 7/24/2012 8:49:56 AM User Rank Blogger
UCF file
Great post!
I have a question about the UCF file however. So far I've only used it to map pin locations in ISE. Comming from 'other' tools I've set clock speeds etc via the GUI as part of the project.
I'd be intrested to see one of Max's spin off posts telling us more about the 'stuff' in a UCF file. Like setting the clock speeds, types of IO, pull ups or pull downs etc.
I had a look following your post at the Xilinx UCF documention and its quite heavy, would be nice to see a 'All you need to know' summary for people comming into FPGAs.
Duane Benson 7/24/2012 1:45:14 PM User Rank Blogger
Re: UCF file
Paul - That's a good idea. I'm pretty much through my run through getting the basics going so now might be a very good time to go back, fill in a few blanks and get a better understanding of some of the things I just glossed over. I'll try and incorporate this into one or more future blogs.
I recently bought and started playing with the Papilio FPGA board that Max wrote about. I've gotten my simple Spartan 6 examples to work on it (It uses a Spartan 3E). I think some of the differences between the two boards will help me to gain a better undestanding of some of the things you're asking for more information on.
I am new to FPGA programming and have succesfully completed the programming with the switches and the LEDS, but now I want to try something more difficult. I have a xilinx virtex 5 ml507 education platform and there is a 16-character x2-line LCD on the board. I have found some information about these LCD's on: http://www.xilinx.com/support/documentation/boards_and_kits/ug230.pdf and I have written my vhdl code (see below). There are no errors in the code itself but when I program it into the fpga, it does not display my message, the LCD screen only tells what it always tells: "choose demo <-+-> 1. slideshow. " Somehow the code doesn't seem to work, could someone give me a little help with this?
many thanks in advance,
Simon
This is the code I wrote:
library IEEE; use IEEE.STD_LOGIC_1164.ALL;
entity circuit1 is Port ( clk : in STD_LOGIC; -- 33 MHz clock input e : out STD_LOGIC; rs : out STD_LOGIC; rw : out STD_LOGIC; a : out STD_LOGIC; b : out STD_LOGIC; c : out STD_LOGIC; d : out STD_LOGIC); end circuit1;
architecture Behavioral of circuit1 is signal code : STD_LOGIC_VECTOR(5 downto 0);
signal co : STD_LOGIC;
begin
process(clk) variable initial : STD_LOGIC := '0'; variable counter : integer range 0 to 21 := 0; begin if (clk'EVENT) and (clk = '1') then counter := counter + 1 ; end if;
case counter is
-- power on when 0 => --e <= '1'; code <= "000011"; when 1 => --e <= '1'; code <= "000011"; when 2 => --e <= '1'; code <= "000011"; when 3 => --e <= '1'; code <= "000010";
-- set when 4 => --e <= '1'; code <= "000010"; when 5 => --e <= '1'; code <= "001000"; -- entry mode when 6 => --e <= '1'; code <= "000000"; when 7 => --e <= '1'; code <= "000110";
-- character input when 12 => -- h code <= "100100"; --e <= '1'; when 13 => code <= "101000"; --e <= '1'; when 14 => -- e code <= "100110"; --e <= '1'; when 15 => code <= "100101"; --e <= '1'; when 16 => -- l code <= "100110"; --e <= '1'; when 17 => code <= "101100"; --e <= '1'; when 18 => -- l code <= "100110"; --e <= '1'; when 19 => code <= "101100"; --e <= '1'; when 20 => -- 0 code <= "100110"; --e <= '1'; when 21 => code <= "101111";
end case; end process;
lol: process(clk) -- dit process concurrent met vorige variable prescaler: integer range 0 to 55999999 := 0; -- with 33 MHz to create 2 s switch from co = '0' to '1' and from '1' to '0' begin if rising_edge(clk) then if prescaler < 55999999 then prescaler := prescaler +1; else prescaler := 0; co <= not(co); end if; end if; end process;
--output, concurrent with the other processes e <= co; rs <= code(0); rw <= code(1); a <= code(2); b <= code(3); c <= code(4); d <= code(5);
This confirms i'm quite new to FPGA programming and totally new to programming with this LCD ;-)
I did not simulate the code yet, I still have to write a testbench. I have already found now that some of the processes need precise timing. I will try to add this timing to the code and will reply the updated code then.
Adam Taylor 7/25/2012 9:13:54 AM User Rank Blogger
Re: fpga to 16-character x2-line LCD (vhdl)
Having just run a quick simulation you need to look at the follwoing
first process, counter, its range is declared as 0 to 21, however you never detect when it reaches 21 and reset it back to 0. This will fail in simulation (in modelsim it does, in reality it willl be implmented as a five bit counter (0 to 31) which just loops around.
As you say you need to have a look at the commands and timing to ensure they are correct for the LCD you are driving.
Simulation is key prior to synthesis and trying it in the target as you can debug it easier
I was wondering, when you have a clock frequency of 50 MHz, and you let a counter run for 2000 loops (i use the following code for this: if clock'EVENT and clock = '1' then counter := counter +1;), then it will take 2000 * 1/50 000 000 = 40 microseconds before the counter has done running.
Adam Taylor 7/25/2012 1:56:11 PM User Rank Blogger
Re: fpga to 16-character x2-line LCD (vhdl)
Sorry I got caught up at work
Yes this is correct however you normally need to do something when a terminal count is reached for example
if count = target valeu then
count = 0
op = 1
else
count = count +1
end
You shoud be using if rising_edge really as opposed to the older clk'event and clk = '1'
Also the counter does not run for 2000 loops but it counts to 2000 a slight difference.
hope this makes sense I will be doing a Ask Adam column soon on counters and sizing them correctly. i.e. how to just define the clock speed and the delay required but we have a few more basic topics to cover to get to that point
I would also recommend NOT using variables in VHDL except for simulation only constructs such as File I/O or in synthesizable constructs ONLY for readability, such as if the right side of an assignment is extremely long due to multiple functions/casts/vector slices/long signal names etc.
example:
cross_sum_loop : for j in 0 to 3 loop f_inph_sum_arr(j) <= resize(f_ac_arr(j), f_inph_sum_arr(j)'length) - resize(f_bd_arr(j), f_inph_sum_arr(j)'length); f_quad_sum_arr(j) <= resize(f_bc_arr(j), f_quad_sum_arr(j)'length) + resize(f_ad_arr(j), f_quad_sum_arr(j)'length); end loop cross_sum_loop;
in some editors the above would wrap around to the next line and make reading a PITA.
Adam Taylor 7/25/2012 1:59:17 PM User Rank Blogger
Re: variables
Variables are always an interestinf area, if they are used correctly they cause no issues however you can easily get into a mess with them with differences betwenn simulation and reality.
Most of the safety critical / high reliability work I have done has not allowed variables in RTL only signals
If you are going to use variables remember there scope is local only (process which it is currently in) also a good rule of thumb is if you want a register then read / use the variable prior to storing anything in it. if you want a peice of wire then set it before you read it.
Duane Benson 7/25/2012 2:01:08 PM User Rank Blogger
Simulation
This is one of many areas where my MCU background may be doing me a disservice in my process of learning to use FPGAs. MCUs certainly use debugger, but I'm gathering that using a debugger isn't the same thing as simulation. I think one of my next few blogs will have to cover my exploration of simulation.
well some simulators allow breakpoints, similar to SW debugging, but in general a simulator waveform shows you all of the signals you have logged for the duration of the simulation run time. or you can dump to VCD and view later.
you can also use assert statements in your source code (well VHDL anyway) that can print things to the simulator shell/terminal/etc a la printf.
Duane Benson 7/25/2012 2:12:29 PM User Rank Blogger
Re: Simulation
Thrakkor - I've been using Verilog so far. It does have an assert statement as well, but I'm not totally sure if has the same functionality as the statement in VHDL.
I'm trying to make a serial rs232 interfase from my computer to my virtex 5 ml507 FPGA. I'm trying to light some LEDs depending on the character I type in HYPERTERMINAL on the computer. I think there is nothing wrong with the serial connection, because when I switch the non-configured FPGA on, the words of the display appear in hyperterminal.
So the problem should be in the code (see below), I think. The problem could be in the baud speed, I calculated this as 3437 because I have 9600 bits/s (done by the configuration of the hyperterminal) and use a 33 MHz clock signal. What would be my mistake?
Thanks in advance,
Simon
LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.STD_LOGIC_ARITH.ALL; USE IEEE.STD_LOGIC_UNSIGNED.ALL;
--SIMONS RS232 project ENTITY RS232 IS PORT( CLK : IN STD_LOGIC; RS232_IN : IN STD_LOGIC; LED_DISPLAY : OUT STD_LOGIC_VECTOR(6 DOWNTO 0)); end RS232;
ARCHITECTURE behavior of RS232 IS
--Numbers CONSTANT zero : STD_LOGIC_VECTOR := "0000001"; CONSTANT one : STD_LOGIC_VECTOR := "0111101"; CONSTANT two : STD_LOGIC_VECTOR := "0010010"; CONSTANT three : STD_LOGIC_VECTOR := "0011000"; CONSTANT four : STD_LOGIC_VECTOR := "0101100"; CONSTANT five : STD_LOGIC_VECTOR := "1001000"; CONSTANT six : STD_LOGIC_VECTOR := "1000000"; CONSTANT seven : STD_LOGIC_VECTOR := "0011101"; CONSTANT eight : STD_LOGIC_VECTOR := "0000000"; CONSTANT nine : STD_LOGIC_VECTOR := "0001000";
Adam Taylor 7/27/2012 10:05:02 AM User Rank Blogger
Re: RS 232 and LEDS
Simon, when receiveing RS232 you need to sample the line and detect the falling edge of the start bit. you then have a reference point to determine when to sample the next bits. For a simple and easy method you can count half a bit period following the falling edge of the start bit to place you approaximately in the center of the start bit. You can then count for a bit period again which will result in you being in the middle of the 1st data bit which you can shift into your register. count another bit period and you are in the middle (ish) of the next bit repeat until the end. This is a very simple method of capturing over rs232. you do not want to sample near the nominal positions due to tolerances which is why the centre of the bit is best.
Simon, The serial bit stream coming will need to by captured by a clock much higher than the transmitter baud clock - typically 16x. You'll need to sync to the edge of the start bit and then count 8 clock cycles, then capture the first bit. Then each 16 cycles will capture each consecutive bit.
if I understand this good, I have to multiply my BAUD constant in my code with 16, then wait until the startbitedge comes, in the middle of the startbit (8 BAUD clock cycles further) capture the startbit then 16 cycles further capture the first databit, etc.?
Is my calculation OK for the BAUD constant? I did 33 000 000/9600 to get to that constant.
Sorry for all the beginners-mistakes by the way ;-)
If I understand the code right, the bit_period variable is the number of clockcounts in a bit of 'rx', right? What would you suggest for a 33 MHz clock input in a 9600 bits per second 'rx' input? I would take 3437 counts/bit.
Made some code today for interfacing the PS/2 keyboard to some LEDs, tested it out and it works. Yeah!! ;)
There is one strange thing though, I have noticed that a few LEDs that are 'low', blink up for a very short time in between two characters I type with the keyboard.
Duane Benson 7/30/2012 2:04:38 PM User Rank Blogger
Communications
This has been a very interesting discussion around RS232. I expect that conceptially it will help with the implementation of a few other protocols that I'll need to figure out at some point.
I 'm trying another home-made exercice ;) . I have connected a VGA input (another PC) to my FPGA and i'm trying to light some LEDs depending on the color of a pixel somewhere in the middle of a frame. I am using 800 X 600 @ 72 Hz resolution. I have read about VGA and I know I think I need 1040 pixels on a row and 666 pixelrows on a frame. (The pixelfrequency is 50 MHz. )
The VGA input on my FPGA delivers 8 bit for blue, 8 bit for red and 8 bit for green. a horizontal and vertical synchronisation signal. However when I make a colored frame (for example in 'paint' opening a black screen) , input this to VGA and assign for example the blue 8 bit vector on a specific pixel of the frame to the 8 LEDs, I get always '0' on my LEDs, even when I input a white or a blue frame.
I use the following principle: the first data that enters is a vertical blanc signal, followed by a horizontal blanc signal, followed by a row of screen-pixels, followed by a horizontal blanc signal, followed by a horizontal synchronisation signal (end of row 1). Then again a horizontal blanc signal, a row of screen pixels, a horizontal blanc signal and a horizontal sync (end of row 2),... etc. Every frame is concluded by a vertical blanc signal and a vertical synchronisation.
if you are using the ML507 virtex board still then I would recommend reading the AD9980 datasheet to see what the timing on your FPGA interface will be
I think there is a problem with the AD9980 (see http://www.analog.com/static/imported-files/data_sheets/AD9980.pdf) because when I switch the resolution of a computer on 800 x 600 or on 1680 x 1050 , both at 60 Hz and feed this in the AD9980, the AD9980 keeps on outputting a dataclock with a period of 20 ns to the FPGA. While this period should be 6.79 ns for the 1680 x 1050 @ 60 Hz and 25 ns at 800 X 600 @ 60 Hz.
I'm trying to configure the registers of the AD9980 using the I2C bus and my FPGA. I'm writing on the SDA and the SCL pins with a SCL-frequency of 100 kHz. However it doesn't seem to work. I'm trying but I don't think I wrote in the registers.
Duane has decided that the time is ripe to get his ZedBoard bolted onto his robot with a Linux distribution up and running. That was the ultimate plan anyway, so why wait?
To save this item to your list of favorite All Programmable Planet content so you can find it later in your Profile page, click the "Save It" button next to the item.
If you found this interesting or useful, please use the links to the services below to share it with other readers. You will need a free account with each service to share an item via that service.