Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

VHDL LCD programming on xilinx processor 1

Status
Not open for further replies.

Zentan

Programmer
Jan 13, 2004
7
0
0
SG
I am currently doing a mini-project on LCD programming using VHDL. I need some assistant in display character on the LCD.

Now I in a difficulty of wondering where and how to start.
I hope to have a skeleton or a struncture on displaying character on LCD.

Thanks!
 
A generate statement creates statements that will be replicated into multiple hardware blocks.

A loop is simply a statement that is repeatedly executed. In most cases that means it is not synthesizable.

I believe only 'for' loops can be synthesized, and the bounds must be constant.

For example:
for i in 0 to 3 loop
a(i) <= b(i) xor y;
x <= a(i) xor b(i);
end loop;

Generate statements are really very similar to for loops, but you can also use them in other ways.

I could do the above example:

gen_label : for i in 0 to 3 generate
begin
a(i) <= b(i) xor y;
x <= a(i) xor b(i);
end generate gen_label;

In this case the only difference with the generate statement is that you can put anything inside the block. like processes etc:

gen_label1 : for i in 0 to 3 generate
begin
process_label : process is
begin
wait until clock'event and clock = '1';
if reset = '0' then
y <= '0';
else
y <= a and b;
end if;
end process process_label;
end generate gen_label1;

you can also do things like create different logic for different versions of your block. For example you can create a generic for your block and then have a conditional generate statement. Then when you instantiate your block you can set the generic to the correct value and end up with different hardware.

Say you have two functions to implement that are almost the same but not quite. Then you simply implement two generates with the differing parts of the code, and the common code interacts with either of your generate's depending on what you set the generic too.

the generate would look like:

gen_label2 : if generic_name = "and" generate
begin
x <= a and b;
end generate gen_label2;

gen_label3 : if generic_name = "or" generate
begin
x <= a or b;
end generate gen_label3;

of course this is a very simple example that could probably be done differently, but for larger chunks of code this is useful.



--
 
If I'm trying to make a counter for example:


process
variable count:integer range 0 to 1000;
begin
if (reset='1') then
count:=0;
elsif (clk'event and clk='1') then
if count=1000 then
count:=0
else count:=count+1
end if;
end if;
end process;

How can I make it stop after 1 sec of working, and get its value with a chance of restarting it after again.

count:=count after 1 sec;

that statement doesn't work (even I make count a signal)
 
You could do it a few ways.

First you will need another counter that counts to 1 sec. For example a 26 bit counter at 50Mhz will work for you (just stop when it gets to 50M).

When you see it get to 50M, set a signal as a flag. Then you can do something like:

if (reset='1') then
count:=0;
elsif (clk'event and clk='1') then
if count=1000 then
count:=0
elsif onesec_flag = '1' then
count := count;
else
count:=count+1
end if;
end if;

Then have some code to detect when you read the count, and reset the onesec_flag.

if reset = '1' then
onesec_count <= 0;
onesec_flag <= '0';
elsif (clk'event and clk='1') then
if counter_read = '1' then
onesec_count <= 0;
onesec_flag <= '0';
elsif onesec_count = 50M then -- not valid VHDL,
-- but you get the idea
onesec_count <= onesec_count;
onesec_flag <= '1';
else
onesec_count <= onesec_count + 1;
onesec_flag <= '0';
end if;
end if;


or you could simply have a second register to read the count. and when you go to read the count just copy it to a different register and let count keep going on its merry way.

It just depends on what you need to read it for, and what you expect to happen while you are reading it.

I assume you mean 'read' it from a users point of view, ie some kind of CPU operation, or maybe displaying it to the screen until some button is pressed. Cause if you mean 'read' it from the point of view of using it in a different process (say in a conditional statement), then you can just do it at any time.

--
 
Thank you very much, Vhdl guy, I figured it out :)

Zentan, there is another, much simplier way to program the LCD, not making the code 1000 lines. Here is a quick, simple eexample of using arrays of vectors for that purpose. It's just an example, you can change the clock divider, if your lcd doesn't work with 1 KHz,


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
library UNISIM;
use UNISIM.VComponents.all;

entity lcdnevergiveup is
Port (reset:in std_logic;
clkin:in std_logic;
EN:eek:ut std_logic;
LCD: out std_logic_vector (9 downto 0) );
end lcdnevergiveup;
architecture Behavioral of lcdnevergiveup is
type mem_data is array (0 to 22) of std_logic_vector (9 downto 0);
constant rom_data: mem_data :=
(("0000110000"),--init1
("0000110000"),--init2
("0000111000"),--init3
("0000001100"),--init4
("0000000110"),--init5
("0000000001"),--init6
("1001001110"),--N
("1001000101"),--E
("1001010110"),--V
("1001000101"),--E
("1001010010"),--R
("1011111110"),--SP
("1001000111"),--G
("1001001001"),--I
("0011000000"), --second line
("1001010110"),--V
("1001000101"),--E
("1011111110"),--SP
("1001010101"),--U
("1001010000"),--P
("1011111110"),--SP
("1000100001"),--!
("1011111110")--SP
);
signal CLK_COUNT : std_logic_vector(15 downto 0);
signal INT_CLK : std_logic;
signal clk:std_logic;
constant CLK_STOP : std_logic_vector(15 downto 0) := X"C350";
signal count:integer range 0 to 22 ;
signal count2:integer range 1 to 3;
begin
clk <= INT_CLK;
DIVIDE_CLOCK: process (CLKIN)
begin
if rising_edge(CLKIN) then
-- Check to see if the count value has been met
if (CLK_COUNT = CLK_STOP) then
-- Flip the output clock signal
INT_CLK <= not INT_CLK;

-- Reset the count
CLK_COUNT <= X"0000";
else
-- Add 1 to the count
CLK_COUNT <= CLK_COUNT + X"0001";
end if;
end if;
end process DIVIDE_CLOCK; --Clock div 1KHz
process(clk)
begin
if (clk'event and clk='1') then
if (count=22) then
count<=22;
elsif (count2=3) then
count<=count+1;
end if;
if (count2=3) then
count2<=1;
else count2
<=count2+1;
end if;
case count2 is
when 1=> EN<='0';
when 2 => EN<='1';
when 3 =>
LCD<=rom_data (count);
end case;
end if;
if (reset='1') then
count<=0;
count2<=1;
end if;
end process;
end Behavioral;
 
Vhdl guy, thanks for ur help, i got my project running. The problem was prolly the hot plug thing. so now i download my program first then power up the lcd and it seems to be working great....thanks yall!!!!!!!!!!
 
hi vhdl guy;
could you give an idea how to implement counters that counts 1000 times on five states. I am trying to using state diagram for this process.
 
I'm not entirely sure what you mean, but here is some info:

create a process with a case statement, your 5 states are all your cases. You can declare them as enumerations (only 5 states total) or simply as a 3 bit vector (8 states total, so you need a when others to get you out of the other unused states).

in each case you have an if statement saying if change_state = '1' then
inside that statement change your state to the next state.

Enumerations:
case state_sig is
when state_0 =>
if change_state = '1' then
state_sig <= state_1;
else
-- anything else?
end if;
when state_1 =>
...

end case;

vector:
case state_sig is
when "000" =>
if change_state = '1' then
state_sig <= "001";
else
-- anything else?
end if;
when "001" =>
...

end case;


Then create another process. In it have a counter from 0 to 1000, at which point assert change_state to 1 (and then back to 0 on the next clock.

Writing short hand:
-- process stuff
-- begin
-- reset signals
-- clock'event
if count = X"3E8" then
change_state <= '1';
count <= X"0";
else
count <= count + 1;
change_state <= '0';
end if;
-- whatever else
-- end process


of course you may want different signals and therefore different conditions to move from state to state, in which case just change your case statement as required.

Or you may know that your state change condition is always the same, and you states always move in a circular pattern. In this case you could skip the case and use another counter.

if change_state = '1' then
if state_counter =X"5" then
state_counter <= X"0";
else
state_counter <= state_count + 1;
end if;
end if;

You then have a state that can be used in another process to do/create certain events.

--
 
Hi, I'm trying to make a frequency counter with displaying the result on LCD. I've been breaking my head on this one for almost a month now, can anybody take a look at it "from the side" and maybe see what mistakes I made. I shortened the program a bit so only 3 digits are supposed to be displayed(without the units), and this one does not work still.


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
library UNISIM;
use UNISIM.VComponents.all;

entity fr_counter is
Port (
fr_in: in std_logic;
clkin:in std_logic;
EN:eek:ut std_logic;
LCD: out std_logic_vector (9 downto 0) );
end fr_counter;

architecture Behavioral of fr_counter is
signal fr_in:std_logic;

type mem_data_init is array (0 to 5) of std_logic_vector (9 downto 0);
type mem_data_out is array (0 to 9) of std_logic_vector (9 downto 0);
type mem_show is array (0 to 11) of std_logic_vector (9 downto 0);

constant init: mem_data_init :=
( ("0000110000"),
("0000110000"),
("0000111000"),
("0000001100"),
("0000000110"),
("0000000001"));

constant num1: mem_data_out:=
(("1000110000"),--0
("1000110001"),--1
("1000110010"),--2
("1000110011"),--3
("1000110100"),--4
("1000110101"),--5
("1000110110"),--6
("1000110111"),--7
("1000111000"),--8
("1000111001") --9
);

constant num2: mem_data_out:=
(("1000110000"),--0
("1000110001"),--1
("1000110010"),--2
("1000110011"),--3
("1000110100"),--4
("1000110101"),--5
("1000110110"),--6
("1000110111"),--7
("1000111000"),--8
("1000111001") --9
);

constant num3: mem_data_out:=
(("1000110000"),--0
("1000110001"),--1
("1000110010"),--2
("1000110011"),--3
("1000110100"),--4
("1000110101"),--5
("1000110110"),--6
("1000110111"),--7
("1000111000"),--8
("1000111001") --9
);
-----------------------------------------------------------
signal count_bin:integer range 0 to 11;
signal timer: integer range 0 to 1011;
signal count_init: integer range 0 to 5;
signal count_ones: integer range 0 to 9;
signal count_tens: integer range 0 to 9;
signal count_hundreds: integer range 0 to 9;

signal count_show: integer range 1 to 3;
------------------------------------------------------------
signal CLK_COUNT : std_logic_vector(15 downto 0);
signal INT_CLK : std_logic;
signal clk:std_logic;
constant CLK_STOP : std_logic_vector(15 downto 0) := X"C350";
-------------------------------------------------------------
signal bin:mem_show;
begin

clk <= INT_CLK;




DIVIDE_CLOCK: process (CLKIN,count_bin)
begin
if rising_edge(CLKIN) then
-- Check to see if the count value has been met
if (CLK_COUNT = CLK_STOP) then
-- Flip the output clock signal
INT_CLK <= not INT_CLK;

-- Reset the count
CLK_COUNT <= X"0000";
else
-- Add 1 to the count
CLK_COUNT <= CLK_COUNT + X"0001";
end if;
end if;
if (count_bin=11) then
INT_CLK<='0';
end if;
end process DIVIDE_CLOCK; --Clock div 1KHz

process (clk,timer,count_show,count_bin)
begin

if rising_edge(clk) then

if (timer=1011) then
timer<=timer;

if (count_show=3) then
count_show<=1;
if (count_bin=11) then
count_bin<=11;
else count_bin<=count_bin+1;
end if;
else count_show<=count_show+1;
end if;


else timer<=timer+1;
end if;


case count_show is
when 1=> EN<='0';
when 2=> EN<='1';
when 3=>
LCD<=bin(count_bin);

end case;


end if;

end process;

process (fr_in,timer,count_ones,count_tens,count_hundreds)
begin

if rising_edge(FR_IN) then


if (timer=1000) then

count_ones<=count_ones;
count_tens<=count_tens;
count_hundreds<=count_hundreds;
end if;
if (count_ones=9 and count_tens=9 and count_hundreds=9) then
count_hundreds<=0;
count_tens<=0;
count_ones<=1;
elsif (count_ones=9) then
count_tens<=count_tens+1;
count_ones<=0;
elsif (count_tens=9) then
count_hundreds<=count_hundreds+1;
count_tens<=0;
else count_ones<=count_ones+1;
end if;

end if;

end process;

process (timer)
begin

if (timer=1000)then
bin(0)<= "0000110000";
bin(1)<= "0000110000";
bin(2)<= "0000111000";
bin(3)<= "0000001100";
bin(4)<= "0000000110";
bin(5)<= "0000000001";
bin(6)<= "0010000000";
bin(7)<= num1(count_hundreds);
bin(8)<= "0010000001";
bin(9)<=num2 (count_tens);
bin(10)<= "0010000010";
bin(11)<=num3 (count_ones);
end if;

end process;
end Behavioral;
 
there is no need to have num1 num2 and num3 since they are all the same. but your synthesizer might work that out for you.

when you increment your count tens because the ones got to nine you also need to check to see if the tens got to 9 in which case you need to increment hundreds.

same deal goes when you inc hundreds.

you should maybe not use one big elsif and rather do something like:

if (count_ones=9 and count_tens=9 and count_hundreds=9) then
count_ones<=1;
elsif (count_ones = 9) then
count_ones <= 0;
else
count_ones <= count_ones + 1;
end if;

if (count_ones=9 and count_tens=9 and count_hundreds=9) then
count_tens<=0;
elsif (count_ones =9 and count_tens = 9) then
count_tens <= 0;
elsif (count_ones = 9) then
count_tens <= count_tens + 1;
end if;

if (count_ones=9 and count_tens=9 and count_hundreds=9) then
count_hundreds<=0;
elsif (count_ones = 9 and count_tens = 9) then
count_hundreds <= count_hundreds + 1;
end if;

I think thats right, you should check it.

--
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top