UPGRADE YOUR BROWSER

We have detected your current browser version is not the latest one. Xilinx.com uses the latest web technologies to bring you the best online experience possible. Please upgrade to a Xilinx.com supported browser:Chrome, Firefox, Internet Explorer 11, Safari. Thank you!

cancel
Showing results for 
Search instead for 
Did you mean: 
Visitor semiavas
Visitor
268 Views
Registered: ‎08-08-2018

KC705 (Kintex-7) Evaluation Board LCD code help

Hi,

I'm trying to implement this module on a Kintex-7. It takes a 64 bit - input, turns it into a hex array that can then be processed/used by the LCD to then display the input on the LCD screen.

64 bit input examples : x"EEDBA5216D8F4B15", x"5E3D7E580B86114B"

 

This code sort of works, I used a .do to check the waveform on modelsim and it properly creates the char array before moving into the init_delay. The clr (clear/reset) does properly have it go back to the start state and it proceeds to cycle through again. And it does output to the LCD.

 

The problems:

1. The output on the LCD isn't completely right, it looks like it is shifted to the left by 1 and maybe some hex is off, like 3 of the characters were not what they were supposed to be.

2. Using clr, does clear the LCD, but instead of displaying all of the characters it displays just the first character and continuing to press it shows the other characters.

I.e. instead of this: [EEDBA5216D8F4B15], I get [E __________] <clear button press> [E__________] <clear button press> [D__________] etc...

 

Notes:

1. The clock is coming from a generated clock from the ip clocking wizard that is taking in 200 MHz and outputing 156.250 MHz. I plan to use a 50 Mhz clock later on, but that should be an easy fix by just changing the delays. 

2. I exaggerated the delays a fair amount from calculated just to make absolutely sure I met the LCD wait times.

Documentation:

https://www.xilinx.com/support/documentation/boards_and_kits/kc705/ug810_KC705_Eval_Bd.pdf

https://cdn.displaytech-us.com/sites/default/files/driver-ic-data-sheet/Sitronix-ST7066U.pdf

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;


entity RC5_LCD is
   port (     
      clk       : in  std_logic;
      clr       : in std_logic;
	  data_in   : in std_logic_vector(63 downto 0);
	  data_rdy  : in std_logic;
      lcd_rw    : out std_logic := '0'; 
      lcd_e     : out std_logic := '0'; 
      lcd_rs    : out std_logic := '0'; 
	  data      : out std_logic_vector(3 downto 0));
end RC5_LCD;

architecture meat of RC5_LCD is
	-- FSM states
	type state_type is (startup, data_set, init_delay,
						func_set_upper,func_set_upper_delay,func_set_lower,func_set_lower_delay,
						disp_set_upper,disp_set_upper_delay,disp_set_lower,disp_set_lower_delay,
						lcd_clear_upper,lcd_clear_upper_delay,lcd_clear_lower,lcd_clear_lower_delay,
						lcd_home_upper,lcd_home_upper_delay,lcd_home_lower,lcd_home_lower_delay,
		set_ddram_addr_upper,set_ddram_addr_upper_delay,set_ddram_addr_lower,set_ddram_addr_lower_delay,
		display_data_onLCD_upper,display_data_onLCD_upper_delay,display_data_onLCD_lower,display_data_onLCD_lower_delay,
						done_state);
						
	signal NS : state_type;		-- we only want the process to be evaluated every clock cycle to update the count
								-- we don't want to add PS as a state type because that would ignore the count
								-- and go to the next state on every clock cycle
	
	-- array containing the hex values of characters (Data register) we want to display on LCD
	constant max_chars : integer := 16; 
	type arr is array (0 to max_chars - 1) of std_logic_vector(7 downto 0); 
	signal char : arr;

    --array for cutting up data_in into 4 bit sections
    type arr_two is array (0 to max_chars -1) of std_logic_vector (3 downto 0);
    signal data_array : arr_two;
	
	-- counting/timing signals
	signal s_delay_value     : std_logic_vector(23 downto 0);
	signal max_count 	 : unsigned(23 downto 0);
	signal count     	 : unsigned(23 downto 0) := (others => '0');

	
	-- ADDED SIGNALS --

	signal j_cnt         : unsigned (3 downto 0);

	-- Instruction register constants
	constant Function_Set : std_logic_vector(7 downto 0) := x"28";	    --set to 4-bit,2 lines,5x8 pixel size
	constant Display_Set  : std_logic_vector(7 downto 0) := x"0F"; 		--set to entire display on,cursor/blinking on
	constant Clear_LCD    : std_logic_vector(7 downto 0) := x"01"; 
	constant Return_Home  : std_logic_vector(7 downto 0) := x"02";
	constant DDRAM_Addr   : std_logic_vector(7 downto 0) := x"80";
	
	-- clock on board is 156.250 MHz
	constant delay_40us   : std_logic_vector(23 downto 0) := x"20186A";		-- hex value is equal to 40 us
	constant delay_40ms   : std_logic_vector(23 downto 0) := x"973594";
	constant delay_2ms    : std_logic_vector(23 downto 0) := x"24C4B4";
	
	-- DCM is putting out 50 MHz
--	constant delay_40us   : std_logic_vector(23 downto 0) := x"0007D0";		-- hex value is equal to 40 us
--	constant delay_40ms   : std_logic_vector(23 downto 0) := x"2625A0";     -- hex value from converting from example lcd file
--	constant delay_2ms    : std_logic_vector(23 downto 0) := x"0186A0";     -- hex value is equal to  2 ms
	
	--constant delay_40us   : std_logic_vector(23 downto 0) := x"0117D0";		-- hex value is equal to 40 us
	--constant delay_40ms   : std_logic_vector(23 downto 0) := x"2735A0";     -- hex value from converting from example lcd file
	--constant delay_2ms    : std_logic_vector(23 downto 0) := x"0296A0";     -- hex value is equal to  2 ms

begin	
	
	lcd_rw <= '0';					-- lcd is always writing (hence, this command is always zero)
	max_count <= unsigned(s_delay_value);

data_array <= (data_in(63 downto 60),data_in(59 downto 56),data_in(55 downto 52),data_in(51 downto 48),data_in(47 downto 44),
               data_in(43 downto 40),data_in(39 downto 36),data_in(35 downto 32),data_in(31 downto 28),data_in(27 downto 24),
               data_in(23 downto 20),data_in(19 downto 16),data_in(15 downto 12),data_in(11 downto 8),data_in(7 downto 4),
               data_in(3 downto 0));

--with data_in (to_integer(n_cnt)+2 downto to_integer(n_cnt)-1) select
with data_array(to_integer(j_cnt)) select
		     char(to_integer(j_cnt)) <= x"30" when "0000", --Input is 0, assign hex ASCII 0 to char
			                            x"31" when "0001", --Input is 1, assign hex ASCII 1 to char
			                            x"32" when "0010", --Input is 2, assign hex ASCII 2 to char
						                x"33" when "0011", --Input is 3, assign hex ASCII 3 to char
					                 	x"34" when "0100", --Input is 4, assign hex ASCII 4 to char
					                 	x"35" when "0101", --Input is 5, assign hex ASCII 5 to char
					                	x"36" when "0110", --Input is 6, assign hex ASCII 6 to char
					                   	x"37" when "0111", --Input is 7, assign hex ASCII 7 to char
					                	x"38" when "1000", --Input is 8, assign hex ASCII 8 to char
					                   	x"39" when "1001", --Input is 9, assign hex ASCII 9 to char
					                   	x"41" when "1010", --Input is A, assign hex ASCII A to char
				                		x"42" when "1011", --Input is B, assign hex ASCII B to char
				                		x"43" when "1100", --Input is C, assign hex ASCII C to char
					                	x"44" when "1101", --Input is D, assign hex ASCII D to char
					                  	x"45" when "1110", --Input is E, assign hex ASCII E to char
					                 	x"46" when "1111", --Input is F, assign hex ASCII F to char
					                 	x"20" when others; --sets to [space] if anything else
						
data_proc : process (clk) begin
    if (rising_edge(clk)) then
	   if (NS = startup) then
		  j_cnt <= "0000";
           elsif (NS = data_set) then
	         if (j_cnt = "1111") then
		     j_cnt <= "0000";
	         else
		     j_cnt <= j_cnt + 1;
	         end if;
	   end if;
     end if;
end process;
	    
comb_proc : process (clk)
		variable j : integer := 0;            -- this variable stores the index value of the char array 
	begin
	if (rising_edge(clk)) then
	   if (clr = '1') then
	       NS <= startup;
	       count <= (others => '0');
	       lcd_e  <= '0';
	       lcd_rs <= '0';
	   else
		case NS is
                        when startup =>
                                --If (data_rdy = '1') then 
                                NS <= data_set;
                               -- end if;
                        when data_set =>
                                If (j_cnt = "1111") then
                                NS <= init_delay;
                                end if;
			when init_delay =>							-- this state sets up signals for next state
				s_delay_value <= delay_40ms;				-- value equals to 40 ms
				if (count = max_count) then
					lcd_e <= '1';						-- set enable high since it serves in the next state
					lcd_rs <= '0';
					data <= Function_Set(7 downto 4);
					s_delay_value <= delay_40us;			-- value equals 40 us
					count <= (others => '0');				-- reset count before going into next state
					NS <= func_set_upper;
				else
					count <= count + 1;
				end if;
----------------------------------------------------------------------------------------------------------------
-------------------------------- Function Set Command ----------------------------------------------------------
----------------------------------------------------------------------------------------------------------------
			when func_set_upper =>					-- refers to upper 4 bits
				if (count = max_count) then
					lcd_e <= '0';					-- next state will serve as the delay in between func_set delay
					lcd_rs <= '0';					-- as upper high bits sit on data for a while
					data <= Function_Set(7 downto 4);
					s_delay_value <= delay_40us;		
					count <= (others => '0');				
					NS <= func_set_upper_delay;
				else
					count <= count + 1;
				end if;
				
			when func_set_upper_delay =>
				if (count = max_count) then
					lcd_e <= '1';
					lcd_rs <= '0';
					data <= Function_Set(3 downto 0);
					s_delay_value <= delay_40us;
					count <= (others => '0');				
					NS <= func_set_lower;
				else
					count <= count + 1;
				end if;
				
			when func_set_lower =>
				if (count = max_count) then
					lcd_e <= '0';
					lcd_rs <= '0';
					data <= Function_Set(3 downto 0);
					s_delay_value <= delay_40us;	
					count <= (others => '0');				
					NS <= func_set_lower_delay;
				else
					count <= count + 1;
				end if;
				
			when func_set_lower_delay =>
				if (count = max_count) then
					lcd_e <= '1';
					lcd_rs <= '0';
					data <= Display_Set(7 downto 4);
					s_delay_value <= delay_40us;
					count <= (others => '0');				
					NS <= disp_set_upper;
				else
					count <= count + 1;
				end if;

----------------------------------------------------------------------------------------------------------------
-------------------------------- Display Set Command -----------------------------------------------------------
---------------------------------------------------------------------------------------------------------------- 

			when disp_set_upper =>					-- refers to upper 4 bits
				if (count = max_count) then
					lcd_e <= '0';					-- next state will serve as the delay in between func_set delay
					lcd_rs <= '0';					-- as upper high bits sit on data for a while
					data <= Display_Set(7 downto 4);
					s_delay_value <= delay_40us;	
					count <= (others => '0');				
					NS <= disp_set_upper_delay;
				else
					count <= count + 1;
				end if;
				
			when disp_set_upper_delay =>
				if (count = max_count) then
					lcd_e <= '1';
					lcd_rs <= '0';
					data <= Display_Set(3 downto 0);
					s_delay_value <= delay_40us;
					count <= (others => '0');				
					NS <= disp_set_lower;
				else
					count <= count + 1;
				end if;
				
			when disp_set_lower =>
				if (count = max_count) then
					lcd_e <= '0';
					lcd_rs <= '0';
					data <= Display_Set(3 downto 0);
					s_delay_value <= delay_40us;	
					count <= (others => '0');				
					NS <= disp_set_lower_delay;
				else
					count <= count + 1;
				end if;
				
			when disp_set_lower_delay =>
				if (count = max_count) then
					lcd_e <= '1';
					lcd_rs <= '0';
					data <= Clear_LCD(7 downto 4);
					s_delay_value <= delay_2ms;				-- equal to 2 ms
					count <= (others => '0');				
					NS <= lcd_clear_upper;
				else
					count <= count + 1;
				end if;

----------------------------------------------------------------------------------------------------------------
-------------------------------- LCD Clear Command -------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------

			when lcd_clear_upper =>					-- refers to upper 4 bits
				if (count = max_count) then
					lcd_e <= '0';					-- next state will serve as the delay
					lcd_rs <= '0';					-- as upper high bits sit on data for a while
					data <= Clear_LCD(7 downto 4);
					s_delay_value <= delay_2ms;		
					count <= (others => '0');				
					NS <= lcd_clear_upper_delay;
				else
					count <= count + 1;
				end if;
				
			when lcd_clear_upper_delay =>
				if (count = max_count) then
					lcd_e <= '1';
					lcd_rs <= '0';
					data <= Clear_LCD(3 downto 0);
					s_delay_value <= delay_2ms;	
					count <= (others => '0');				
					NS <= lcd_clear_lower;
				else
					count <= count + 1;
				end if;
				
			when lcd_clear_lower =>
				if (count = max_count) then
					lcd_e <= '0';
					lcd_rs <= '0';
					data <= Clear_LCD(3 downto 0);
					s_delay_value <= delay_2ms;	
					count <= (others => '0');				
					NS <= lcd_clear_lower_delay;
				else
					count <= count + 1;
				end if;
				
			when lcd_clear_lower_delay =>
				if (count = max_count) then
					lcd_e <= '1';
					lcd_rs <= '0';
					data <= Return_Home(7 downto 4);
					s_delay_value <= delay_2ms;		
					count <= (others => '0');				
					NS <= lcd_home_upper;
				else
					count <= count + 1;
				end if;

----------------------------------------------------------------------------------------------------------------
-------------------------------- Return Home Command -----------------------------------------------------------
----------------------------------------------------------------------------------------------------------------

			when lcd_home_upper =>					-- refers to upper 4 bits
				if (count = max_count) then
					lcd_e <= '0';					-- next state will serve as the delay
					lcd_rs <= '0';					-- as upper high bits sit on data for a while
					data <= Return_Home(7 downto 4);
					s_delay_value <= delay_2ms;			
					count <= (others => '0');				
					NS <= lcd_home_upper_delay;
				else
					count <= count + 1;
				end if;
				
			when lcd_home_upper_delay =>
				if (count = max_count) then
					lcd_e <= '1';
					lcd_rs <= '0';
					data <= Return_Home(3 downto 0);
					s_delay_value <= delay_2ms;		
					count <= (others => '0');				
					NS <= lcd_home_lower;
				else
					count <= count + 1;
				end if;
				
			when lcd_home_lower =>
				if (count = max_count) then
					lcd_e <= '0';
					lcd_rs <= '0';
					data <= Return_Home(3 downto 0);
					s_delay_value <= delay_2ms;		
					count <= (others => '0');				
					NS <= lcd_home_lower_delay;
				else
					count <= count + 1;
				end if;
				
			when lcd_home_lower_delay =>
				if (count = max_count) then
					lcd_e <= '1';
					lcd_rs <= '0';							-- data command, not instruction command
					data <= DDRAM_Addr(7 downto 4);
					s_delay_value <= delay_40us;	
					count <= (others => '0');				
					NS <= set_ddram_addr_upper;
				else
					count <= count + 1;
				end if;

----------------------------------------------------------------------------------------------------------------
-------------------------------- Set DDRAM_Addr ----------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------

			when set_ddram_addr_upper =>					-- refers to upper 4 bits
				if (count = max_count) then
					lcd_e <= '0';					-- next state will serve as the delay in between func_set delay
					lcd_rs <= '0';					-- as upper high bits sit on data for a while
					data <= DDRAM_Addr(7 downto 4);
					s_delay_value <= delay_40us;			
					count <= (others => '0');				
					NS <= set_ddram_addr_upper_delay;
				else
					count <= count + 1;
				end if;
				
			when set_ddram_addr_upper_delay =>
				if (count = max_count) then
					lcd_e <= '1';
					lcd_rs <= '0';
					data <= DDRAM_Addr(3 downto 0);
					s_delay_value <= delay_40us;
					count <= (others => '0');				
					NS <= set_ddram_addr_lower;
				else
					count <= count + 1;
				end if;
				
			when set_ddram_addr_lower =>
				if (count = max_count) then
					lcd_e <= '0';
					lcd_rs <= '0';
					data <= DDRAM_Addr(3 downto 0);
					s_delay_value <= delay_40us;	
					count <= (others => '0');				
					NS <= set_ddram_addr_lower_delay;
				else
					count <= count + 1;
				end if;
				
			when set_ddram_addr_lower_delay =>
				if (count = max_count) then
					lcd_e <= '1';
					lcd_rs <= '1';
					data <= char(j)(7 downto 4);					-- upper 4 bits of letter 'C'
					s_delay_value <= delay_40us;
					count <= (others => '0');				
					NS <= display_data_onLCD_upper;
				else
					count <= count + 1;
				end if;
----------------------------------------------------------------------------------------------------------------
-------------------------------- Display Data on LCD -----------------------------------------------------------
----------------------------------------------------------------------------------------------------------------

			when display_data_onLCD_upper =>					-- refers to upper 4 bits
				if (count = max_count) then
					lcd_e <= '0';					-- next state will serve as the delay in between func_set delay
					lcd_rs <= '0';					-- as upper high bits sit on data for a while
					data <= char(j)(7 downto 4);
					s_delay_value <= delay_40us;	
					count <= (others => '0');				
					NS <= display_data_onLCD_upper_delay;
				else
					count <= count + 1;
				end if;
				
			when display_data_onLCD_upper_delay =>
				if (count = max_count) then
					lcd_e <= '1';
					lcd_rs <= '1';
					data <= char(j)(3 downto 0);				-- lower 4 bits of letter 'C'
					s_delay_value <= delay_40us;
					count <= (others => '0');				
					NS <= display_data_onLCD_lower;
				else
					count <= count + 1;
				end if;
				
			when display_data_onLCD_lower =>				-- make changes in this state for next state
				if (count = max_count) then
					lcd_e <= '0';
					lcd_rs <= '0';
					data <= char(j)(3 downto 0);
					-- update variable j to count 
					j := j + 1;
					s_delay_value <= delay_40us;	
					count <= (others => '0');				
					NS <= display_data_onLCD_lower_delay;
				else
					count <= count + 1;
				end if;
				
			when display_data_onLCD_lower_delay =>
				if (count = max_count) then
					if (j < max_chars) then 	-- when j is less than max_chars it will keep iterating through char array
						lcd_e <= '1';         -- and next state will be display_data_onLCD_upper
						lcd_rs <= '1';
						data <= char(j)(7 downto 4);
						s_delay_value <= delay_40us;
						count <= (others => '0');				
						NS <= display_data_onLCD_upper;
					else
						NS <= done_state;			-- once j is equal to max_chars it will go to done_state
					end if;
				else
					count <= count + 1;
				end if;
				
----------------------------------------------------------------------------------------------------------------
-------------------------------- Done State --------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------				
			
			when done_state =>               -- do nothing in this state
				lcd_e <= '0';
				data <= x"0";
			--when others =>
				--Z1 <= '0';	Z2 <= '0';	NS <= a;
		
		
		
		end case;
		end if;
		end if;
	end process comb_proc;
	
	
end meat;

 Pin constraints:

#--clear (push button)
set_property PACKAGE_PIN G12 [get_ports {clr}]

set_property IOSTANDARD LVCMOS25 [get_ports {clr}]
#-----------------------------------------------------
#--clocks
set_property PACKAGE_PIN AD12 [get_ports {clk_in1_p}]
set_property PACKAGE_PIN AD11 [get_ports {clk_in1_n}]

set_property IOSTANDARD LVDS [get_ports {clk_in1_p}]
set_property IOSTANDARD LVDS [get_ports {clk_in1_n}]
#-----------------------------------------------------
#--LCD
set_property PACKAGE_PIN AA13 [get_ports {lcd_data_out[0]}]
set_property PACKAGE_PIN AA10 [get_ports {lcd_data_out[1]}]
set_property PACKAGE_PIN AA11 [get_ports {lcd_data_out[2]}]
set_property PACKAGE_PIN Y10 [get_ports {lcd_data_out[3]}]

set_property IOSTANDARD LVCMOS15 [get_ports {lcd_data_out[3]}]
set_property IOSTANDARD LVCMOS15 [get_ports {lcd_data_out[2]}]
set_property IOSTANDARD LVCMOS15 [get_ports {lcd_data_out[1]}]
set_property IOSTANDARD LVCMOS15 [get_ports {lcd_data_out[0]}]

set_property PACKAGE_PIN AB13 [get_ports {lcd_rw}]
set_property IOSTANDARD LVCMOS15 [get_ports {lcd_rw}]

set_property PACKAGE_PIN Y11 [get_ports {lcd_rs}]
set_property IOSTANDARD LVCMOS15 [get_ports {lcd_rs}]

set_property PACKAGE_PIN AB10 [get_ports {lcd_e}]
set_property IOSTANDARD LVCMOS15 [get_ports {lcd_e}]
#-----------------------------------------------------

 

 

 

0 Kudos