• We recently switched our forum platform. If you experience any issues please email support@crystalfontz.com

CFAH2002A-RMC-JP: VHDL + Spartan3e board problem

defenseman

New member
I cannot get my LCD to initialize. to rule out bad timing, I made the wait ~1sec after each initialize setting, hence the 26-bit count. here is my code:

EDIT: this code sucks...dont use it. see my updated code below.

Code:
library ieee; 
use ieee.std_logic_1164.all; 
use ieee.std_logic_arith.all; 
use ieee.std_logic_unsigned.all; 

entity lcd_init is  
     port(  
            reset    : in std_logic; 
            clock    : in std_logic;
            enable   : in std_logic; 
            done_ack : in std_logic; 
            done     : out std_logic; 
            RW       : out std_logic;
            rs       : out std_logic;
            lcd_e    : out std_logic;
            leds     : out std_logic_vector (7 downto 0); 
            Qout     : out std_logic_vector(7 downto 0));
            --lcd_power: out std_logic_vector(2 downto 0)); 

end lcd_init; 

architecture initial of lcd_init is 

    type state_type is (waiting, i0, i1, i2, i3, i4, i5, i6, donestate); 
    signal state, next_state  : state_type; 
    signal count, count_temp : std_logic_vector(25 downto 0);
    signal Qout_temp          : std_logic_vector(7 downto 0); 

begin 

running : process(state,enable,done_ack,count) is 

begin 

case state is 

when waiting => 
     leds <= Qout_temp;
     done <= '0'; 
     lcd_e <= '1'; 
     RW <= '0'; 
     rs <= '0';
     Qout_temp <= "00000000"; 

     if (enable = '1' and count = "10111110101111000010000000") then 
          next_state <= i0; 
     else 
          next_state <= waiting; 
     end if; 

when i0 => 
     leds <= Qout_temp;
     Qout_temp <= "00110000"; 
     done <= '0'; 
     lcd_e <= '1'; 
     RW <= '0'; 
     rs <= '0';
     if count = "10111110101111000010000000" then 
          next_state <= i1; 
     else 
          next_state <= i0; 
     end if; 

when i1 =>
     leds <= Qout_temp; 
     Qout_temp <= "00110000";
     done <= '0'; 
     lcd_e <= '1'; 
     RW <= '0'; 
     rs <= '0';
     if count = "10111110101111000010000000" then 
          next_state <= i2; 
     else 
          next_state <= i1; 
     end if; 

when i2 => 
     leds <= Qout_temp;
     Qout_temp <= "00110000"; 
     done <= '0'; 
     lcd_e <= '1'; 
     RW <= '0'; 
     rs <= '0';
     if count = "10111110101111000010000000" then 
          next_state <= i3; 
     else 
          next_state <= i2; 
     end if; 
  

when i3 => 
     leds <= Qout_temp;
     Qout_temp <= "00111100"; 
     done <= '0'; 
     lcd_e <= '1'; 
     RW <= '0'; 
     rs <= '0';
     if count = "10111110101111000010000000" then 
          next_state <= i4; 
     else 
          next_state <= i3; 
     end if; 

when i4 => 
     leds <= Qout_temp;
     Qout_temp <= "00001000"; 
     done <= '0'; 
     lcd_e <= '1'; 
     RW <= '0'; 
     rs <= '0';
     if count = "10111110101111000010000000" then 
          next_state <= i5; 
     else 
          next_state <= i4; 
     end if; 

when i5 => 
     leds <= Qout_temp;
     Qout_temp <= "00000001"; 
     done <= '0'; 
     lcd_e <= '1'; 
     RW <= '0'; 
     rs <= '0';
     if count = "10111110101111000010000000" then 
          next_state <= i6; 
     else 
          next_state <= i5; 
     end if; 

when i6 => 
     leds <= Qout_temp;
     Qout_temp <= "00000111";
     done <= '0'; 
     lcd_e <= '1'; 
     RW <= '0'; 
     rs <= '0';
     if count = "10111110101111000010000000" then 
          next_state <= donestate; 
     else 
          next_state <= i6; 
     end if; 

when donestate =>
     leds <= Qout_temp; 
     done <= '1'; 
     lcd_e <= '1'; 
     RW <= '0'; 
     rs <= '1';
     Qout_temp <= "01111111"; 

     if done_ack = '1' then 
          next_state <= waiting; 
     else 
          next_state <= donestate; 
     end if; 

end case; 
end process running; 


timing : process(clock,reset) is 

begin 

    if rising_edge(clock) then 
         Qout <= Qout_temp; 
         count <= count_temp; 
             if reset = '1' then 
                  state <= waiting; 
                  count_temp <= "00000000000000000000000000"; 
             else 
                  state <= next_state; 
                  count_temp <= count_temp + '1'; 
             end if; 
    end if; 

end process timing; 

end initial;
Looking for additional LCD resources? Check out our LCD blog for the latest developments in LCD technology.
 
Last edited:

CF Tech

Administrator
I see "lcd_e" get set to 1, but never cleared to 0. Am I missing something?

Also, I usually set all the data and control lines with E low, then bring E high wait a slight delay (250nS min), then bring E low again.
 

CF Tech

Administrator
E is essentially the clock that makes the write happen. Take a look at the source from this utility:

http://www.crystalfontz.com/software/CFAH_WinTest/index.html

in "CFAH_WinTestDlg.cpp":
Code:
/////////////////////////////////////////////////////////////////////////////
void CCFAH_WinTestDlg::Write_LCD_Control_8(ubyte data,ubyte enable)
  {
  //Make register select 0, Make R/W 0=write
  OnRsL();
  OnRwL();
  //Write the data to the port.
  data_register=data;	
  Update_Buttons_From_Data_Register();
  //Strobe enable
  Sleep(1);
  if(enable)
    {
    OnE1H();
    Sleep(1);
    OnE1L();
    }
  else
    {
    OnE0H();
    Sleep(1);
    OnE0L();
    }
  }
/////////////////////////////////////////////////////////////////////////////
void CCFAH_WinTestDlg::Write_LCD_Data_8(ubyte data,ubyte enable)
  {
  //Make register select 1, Make R/W 0=write
  OnRsH();
  OnRwL();
  //Write the data to the port.
  data_register=data;	
  Update_Buttons_From_Data_Register();
  //Strobe enable
  Sleep(1);
  if(enable)
    {
    OnE1H();
    Sleep(1);
    OnE1L();
    }
  else
    {
    OnE0H();
    Sleep(1);
    OnE0L();
    }
  }
/////////////////////////////////////////////////////////////////////////////
This example is a little complicated since it supports the 40x4 which has two controllers. Here is a version cleaned up for one controller:
Code:
/////////////////////////////////////////////////////////////////////////////
void Write_LCD_Control(unsigned char data)
  {
  //Make register select 0, Make R/W 0=write
  OnRsL();  //RS low
  OnRwL();  //RW low
  //Write the data to the port.
  data_register=data;	
  //Strobe enable
  Sleep(1);
  OnEH();    //E high
  Sleep(1);
  OnEL();    //E low
  }
/////////////////////////////////////////////////////////////////////////////
void Write_LCD_Data(unsigned char data)
  {
  //Make register select 1, Make R/W 0=write
  OnRsH();  //RS high
  OnRwL();  //RW low
  //Write the data to the port.
  data_register=data;	
  //Strobe enable
  Sleep(1);
  //Strobe enable
  Sleep(1);
  OnEH();    //E high
  Sleep(1);
  OnEL();    //E low
  }
/////////////////////////////////////////////////////////////////////////////
The sleeps are way overkill . . .
 

defenseman

New member
ok ok. im looking at the write cycle wave forms...

if "tc" (min enable pulse width) needs to be 500ns, can I just create a 500ns pulse on the Enable pin (lcd_e)?
 

defenseman

New member
ive been thinking about an E clock, but that wont work. things will get executed when they arnt needed (ie too early).

i thought this was going to be simple but there is so much timing involved.

do I have to check the busy flag every time I do a command?

whats the simplest way to initialize if time/clk speed is not an issue? im getting really frustrated.
 
i thought this was going to be simple but there is so much timing involved.
The timing is really simple: put the data on the bus and set/clear A0 (RS), then raise E, wait 250ns, then lower E. The write "action" takes place on the falling edge of E. E stays low when idle, its not a continuous periodic signal. Think of it as a strobe, not a clock.
do I have to check the busy flag every time I do a command?
Only if you want optimized speed. Otherwise, just wait 2ms between each write.
 
Last edited:

defenseman

New member
im not sure whats wrong with my waveforms? should E (control bit 0) stay high for that long? sorry for the bad image, but the data line stays for 2 sec and the E goes low after 1 sec.

the only thing that works is i now see dual "block" lines displayed on the LCD.


 
According to the data sheet, the E signal only needs to stay high for 250 nanosecs, and the RS and RW must be stable 40 ns before E goes high, and data must be stable during the falling edge of E (plus a little before and after... setup & hold times). Having your control and data signals change simultaneously is unusual (they are usually sequenced by consecutive processor instructions) and I can't help but wonder if that is causing a problem. There is no reason that E can't stay high for 1 sec, if you like slow updates. Your timing diagram is somewhat inscrutable.

Note that in the init sequence, you must wait 4 ms between the first two 0x30 commands, and then wait 100 us before the 3rd 0x30 command.

I don't see that you are ever turning the display 'on' ("000011xx" command).

If you are getting a row of dark 'block' cells, this usually means the display is not being initialized properly. That usually means your commands aren't being received. But then, since you are sending 0x7F as your data, that would give a dark block character, so maybe its actually working. Try using less ambiguous character data.
 
Last edited:

defenseman

New member
heres a better picture.

the thing is, it kinda works cause it displays the second block line. but the initialize commands after that dont seem to do anything. judging from the commands, it should turn off, clear, the display a blinking cursor.

whats the display look like after it initializes properly?

 

defenseman

New member
as you can see my commands are:

00110000
00110000
00110000
00111100
00001000 <- should this be 00001100 ?
00000001
00000111

01111111 <- im trying to display a "<-" character

where do you see 0x7F (11111111)?
 
I don't really understand VHDL; I can't tell whether your init sequence is inside a loop which is repeated, or the whole thing only executes once. What is 'done_ack'? Anyway, the init commands shouldn't be repeated. Are you sending multiple 0x7F's? That would fill the display row with block characters, but you don't address the 2nd row, so how is that being filled?

An initialized display is blank, except if there is a cursor showing.

Also, you haven't commented about meeting the RS and RW setup times.
 
00001000 <- should this be 00001100 ?
Yes.
01111111 <- im trying to display a "<-" character

where do you see 0x7F (11111111)?
Ooops, my bad, the block char is 0xFF, not 0x7F. "11111111" is 0xFF, "01111111" is 0x7F.

I still don't understand what you are seeing on the display. Dark cells? 1 row or both rows?

I think you really don't want the "00000111" command, that would shift the display. Maybe you want "00001111" which turns on display and cursor.
 

defenseman

New member
first off the VHDL code has changed a little bit (see below). but im still running a state machine which runs only once now.

im still not seeing where my LCD data is 0X7F (11111111)?

The RS and RW always stay low from the beginning. i dont neccessarily have to worry about them right? that is until i try to write my character.


Code:
library ieee; 
use ieee.std_logic_1164.all; 
use ieee.std_logic_arith.all; 
use ieee.std_logic_unsigned.all; 

entity lcd_init is 
   port ( 
       rst		: in STD_LOGIC; 
       clk		: in STD_LOGIC; 
       control	: out std_logic_vector (2 downto 0);
		 leds		: out std_logic_vector (7 downto 0);
       LCD		: out STD_LOGIC_VECTOR (7 downto 0)); 
end lcd_init; 

architecture lcd_init_arch of lcd_init is
type state_type is (waiting, i0,i1,i2,i3,i4,i5,i6,i7,i8,i9,i10,i11,i12,i13,i14,i15,donestate);
signal state,next_state : state_type;
signal LCD_temp 	 			 : std_logic_vector (7 downto 0);
signal count, count_temp	 : std_logic_vector (3 downto 0);
signal test : std_logic := '0';

begin 

run : process (state,count) is
begin
    
	case state is
		when waiting =>
			control <= "000"; 				-- RS, RW, E
			LCD_temp <= "00000000";
			leds <= "00000000";
			if (count = "1011") then -- 15ms (750,000/50MHz=15ms)
					next_state <= i0;
			else 	next_state <= waiting;	end if;
		when i0 =>
			control <= "001";
			leds <= "10000000";
			LCD_temp <= "00110000";	 
			if (count = "1011") then --  5ms (250,000/50MHz= 5ms)
					next_state <= i1;
			else 	next_state <= i0; end if;
		when i1 =>
			control <= "000"; 				-- WRITE
			LCD_temp <= "00110000";
			leds <= "10000000";
			if (count = "1011") then -- 260ns (13/50MHz=260ns)
					next_state <= i2;
			else 	next_state <= i1; end if;
		when i2 =>
			control <= "001";
			LCD_temp <= "00110000";	 
			leds <= "01000000";
			if (count = "1011") then --  5ms (250,000/50MHz= 5ms)
					next_state <= i3;
			else 	next_state <= i2; end if;
		when i3 =>
			control <= "000"; 				-- WRITE
			LCD_temp <= "00110000";
			leds <= "01000000";
			if (count = "1011") then -- 260ns (13/50MHz=260ns)
					next_state <= i4;
			else 	next_state <= i3; end if;
		when i4 =>
			control <= "001";
			LCD_temp <= "00110000";	 
			leds <= "00100000";
			if (count = "1011") then --  5ms (250,000/50MHz= 5ms)
					next_state <= i5;
			else 	next_state <= i4; end if;
		when i5 =>
			control <= "000"; 				-- WRITE
			LCD_temp <= "00110000";
			leds <= "00100000";
			if (count = "1011") then -- 260ns (13/50MHz=260ns)
					next_state <= i6;
			else 	next_state <= i5; end if;
		when i6 =>
			control <= "001";
			LCD_temp <= "00111100";	 
			leds <= "00010000";
			if (count = "1011") then --  5ms (250,000/50MHz= 5ms)
					next_state <= i7;
			else 	next_state <= i6; end if;
		when i7 =>
			control <= "000"; 				-- WRITE
			LCD_temp <= "00111100";
			leds <= "00010000";
			if (count = "1011") then -- 260ns (13/50MHz=260ns)
					next_state <= i8;
			else 	next_state <= i7; end if;
		when i8 =>
			control <= "001";
			LCD_temp <= "00001000";	 
			leds <= "00001000";
			if (count = "1011") then --  5ms (250,000/50MHz= 5ms)
					next_state <= i9;
			else 	next_state <= i8; end if;
		when i9 =>
			control <= "000"; 				-- WRITE
			LCD_temp <= "00001000";
			leds <= "00001000";
			if (count = "1011") then -- 260ns (13/50MHz=260ns)
					next_state <= i10;
			else 	next_state <= i9; end if;
		when i10 =>
			control <= "001";
			LCD_temp <= "00000001";	 
			leds <= "00000100";
			if (count = "1011") then --  5ms (250,000/50MHz= 5ms)
					next_state <= i11;
			else 	next_state <= i10; end if;
		when i11 =>
			control <= "000"; 				-- WRITE
			LCD_temp <= "00000001";
			leds <= "00000100";
			if (count = "1011") then -- 260ns (13/50MHz=260ns)
					next_state <= i12;
			else 	next_state <= i11; end if;
		when i12 =>
			control <= "001";
			LCD_temp <= "00000111";	 
			leds <= "00000010";
			if (count = "1011") then --  5ms (250,000/50MHz= 5ms)
					next_state <= i13;
			else 	next_state <= i12; end if;
		when i13 =>
			control <= "000"; 				-- WRITE
			LCD_temp <= "00000111";
			leds <= "00000010";
			if (count = "1011") then -- 260ns (13/50MHz=260ns)
					next_state <= i14;
			else 	next_state <= i13; end if;
		when i14 =>
			control <= "101";
			LCD_temp <= "01111111";	 
			leds <= "00000010";
			if (count = "1011") then --  5ms (250,000/50MHz= 5ms)
					next_state <= i15;
			else 	next_state <= i14; end if;
		when i15 =>
			control <= "100"; 				-- WRITE
			LCD_temp <= "01111111";
			leds <= "00000010";
			if (count = "1011") then -- 260ns (13/50MHz=260ns)
					next_state <= donestate;
			else 	next_state <= i15; end if;


		when donestate =>
			control <= "000";
			leds <= "00000001"; 				
			LCD_temp <= "01111111";
			if (count = "1011") then -- 260ns (13/50MHz=260ns)
					next_state <= donestate;
			else 	next_state <= donestate; end if;
	end case;
end process run;

timing : process (rst, clk) is
begin
	if	(rising_edge(clk)) then
		LCD <= LCD_temp; 
		count <=	count_temp;
		if (rst = '1') then
			state <= waiting;
			count_temp <= "0000";
		else
			state <= next_state;
			count_temp <= count_temp + '1';
		end if;
	end if;
end process timing; 

end lcd_init_arch;
 

defenseman

New member
im seeing two rows that are all dark. meaning there is a block (0xFF) displayed in every box, both rows.

i changed the "00001000" command to "00001100" and it doesnt do anything different.
 

defenseman

New member
cosmicvoid said:


I think you really don't want the "00000111" command, that would shift the display. Maybe you want "00001111" which turns on display and cursor.
im looking right at the manual and the last command is: 00000111. bit<1> is I/D and bit<0> is SH.
 
im seeing two rows that are all dark. meaning there is a block (0xFF) displayed in every box, both rows.
Hard to believe, for code that only writes the data character once. The normal un-initialized behavior is that only the top row of cells is dark. So I don't know whats the deal.

As I read your code, E goes high for 5 ms and low for 260 ns. This is the opposite of what you want.
 

defenseman

New member
cosmicvoid said:
Hard to believe, for code that only writes the data character once. The normal un-initialized behavior is that only the top row of cells is dark. So I don't know whats the deal.

As I read your code, E goes high for 5 ms and low for 260 ns. This is the opposite of what you want.
im sorry. pls disregard the comments. im not updating the comments as i go along.
 
Top