Sida 1 av 1

KS0108B kontroller i VHDL

Postat: 23 april 2006, 19:04:44
av Solution9
Börjar med koden:

Kod: Markera allt

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity LCD is
    Port ( E : out  STD_LOGIC;
           RS : out  STD_LOGIC;
           DATA : inout  STD_LOGIC_VECTOR (7 downto 0);
           RW : inout  STD_LOGIC;
           CS1 : out  STD_LOGIC;
           CS2 : out  STD_LOGIC;
			  clka : in    STD_LOGIC;
			  status : out STD_LOGIC_VECTOR(4 downto 0));
end LCD;

architecture Behavioral of LCD is
	signal delay : integer := 0;
	signal done_sendning : STD_LOGIC;
	signal wait_for : STD_LOGIC;
	signal e_strobe_res : STD_LOGIC;
	
	signal CMD : STD_LOGIC_VECTOR(8 downto 0); -- 8: (0 = Kommando, 1 = Data)
   signal IP: integer := 0;
   signal tempsig: STD_LOGIC_VECTOR(5 downto 0);
	signal init_next_half: STD_LOGIC;
begin

	e_strobe: process (clka, wait_for) 
	begin
	if (wait_for = '1') then
   if (clka'event and clka='1') then
		E <= '1';
      delay <= delay + 1;
      if (delay >= 22500) then --0,00045 / 0,00000002 = 22500 (450 ns min)
			 E <= '0';
			 if (delay = 45000) then
				delay <= 0;
				e_strobe_res <= '0';
			 end if;
      end if;
   end if;
	end if;
	end process e_strobe;
	
	sendCMD_D: process (CMD)
	begin
	    if CMD > "000000000" then
			done_sendning <= '0';
			RW <= '1';
			RS <= '0'; -- Läser status...
			while DATA(7) = '1' loop
					wait_for <= '1';
			end loop;	
			if DATA(7) = '1' then
				RW <= '0';
				DATA(7 downto 0) <= CMD (7 downto 0);
				RS <= CMD(8) and '1';
				wait_for <= '1';
				if e_strobe_res = '0' then
					done_sendning <= '1';
				end if;
			end if;
		 end if;
	end process sendCMD_D;	 

	state_machine: process
		subtype rom_word is STD_LOGIC_VECTOR(3 downto 0);
		type rom_table is array(0 to 10) of rom_word;
		constant State_rom: rom_table := rom_table'("0001","0000","0010","0101",
																  "0100","0110","1001","0111",
																  "0011","1011","1101");	
	begin
	   status(3 downto 0) <= State_rom(IP);
		case State_rom(IP)(0) is
			when '0' => --- Skicka kommando
			  CMD(8) <= '0';
			  case State_rom(IP)(3 downto 1) is
				  when "000" => CMD(7 downto 0) <= X"3F"; -- Sätter på display(X) utpekad av CSx
				  when "001" => CMD(7 downto 0) <= X"C0"; -- Sätter start linje
				  when "010" => CMD(7 downto 0) <= (X"B8" or ("00" & (tempsig and "111111")));
				  when "011" => CMD(7 downto 0) <= X"40";
				  when others => IP <= IP - 1;
			  end case;
			  if done_sendning = '1' then -- Behöver bara kolla denna bit
				  IP <= IP + 1;
			  end if;
			when '1' => -- Gör någonting annat...
            case State_rom(IP)(3 downto 1) is
					when "000" => CS1 <= '1'; -- Markera CS1
									  CS2 <= '0';
									  IP <= IP + 1;
			      when "001" => CS1 <= '0'; -- Makera CS2
								     CS2 <= '1';
									  IP <= IP + 1;
               when "010" => tempsig <= "001000";
									  IP <= IP + 1;
					when "011" => tempsig <= tempsig - 1;
						           if (tempsig = 0) then
										  IP <= IP + 1;
									  else
										  IP <= IP - 3;
								     end if;
					when "100" => tempsig <= "000000";
					              while (tempsig < "111111") loop
											CMD(8 downto 0) <= "111111111";
											if done_sendning = '1' then
											   tempsig <= tempsig + 1;
											end if;
									  end loop;
					when "101" => if init_next_half = '0' then
										  IP <= IP - 8;
										  init_next_half <= '1';
									  else
										   IP <= IP + 1;
									  end if;
					when "110" => status(4) <= '1';-- Evighets loop...				  
					when others => null
				end case;
			when others => null;	
		end case;
   end process state_machine;           				
		
end Behavioral;
.ucf filen:

Kod: Markera allt

NET "E" LOC = "C11";
NET "RS" LOC = "C10";
NET "RW" LOC = "E10";
NET "DATA<0>" LOC = "D11";
NET "DATA<1>" LOC = "C12";
NET "DATA<2>" LOC = "D12";
NET "DATA<3>" LOC = "E11";
NET "DATA<4>" LOC = "B16";
NET "DATA<5>" LOC = "R3";
NET "DATA<6>" LOC = "C16";
NET "DATA<7>" LOC = "D16";
NET "CS1" LOC = "E16";
NET "CS2" LOC = "G15";
NET "status<4>" LOC = "P11";
NET "status<3>" LOC = "P12";
NET "status<2>" LOC = "N12";
NET "status<1>" LOC = "P13";
NET "status<0>" LOC = "N14";

NET "clka" TNM_NET = "clk";
TIMESPEC "TS_clk" = PERIOD "clk" 50 MHz HIGH 50%;
NET "clka" LOC = "T9";
Nu till problembeskrivningen... när jag laddat över programmet till FPGA:n (Spartan3 -400k på en S3BOARD) så börjar lysdioden på P11 lysa (alltså status<4> = '1') vilken den inte borde göra sen stannar den vid IP = 0000 vilket inte heller stämmer.

Någon som har nån aning om vad felet kan vara? (okej koden är nog inte den bästa så all feedback är varmt välkommen då detta är mitt typ 3:e VHDL "program")

Postat: 27 april 2006, 21:33:32
av d99dan
Jag har inte kollat så noga på själva koden, men vad är det förväntade betendet.

Vad jag kan se så är både wait_for och CMD odefienerade i start. wait_for verkar bara tilldelas 1?. Eller jag kanske missade var den blev noll men den borde bli det vid initieringen.

state machine processen borde inte den vara beroende av staten? jag vet inte när den förväntas "uppdatera" sina värden när processen inte har några beroende variabler men risken är att det optimeras bort.

Vad använder du för verktyg?

Har du möjlighet att se en schematic av den optimerade koden?

Postat: 28 april 2006, 14:58:46
av Solution9
du har rätt med att wait_for och CMD inte ändrar värde och soledes kommer koden försöka skicka kommandon hela tiden. Iof skulle jag nog försöka initiera signalerna och variablerna också...

"state-machine:en" ändrar sitt värde då IP ökas eller minskas då den funkar som en pekare i det ROM som heter State_rom.

Här är den C kod som jag försöker översätta till VHDL:

Kod: Markera allt

#define lcd_left()   LCD_CS1 = 1;   LCD_CS2 = 0;   // sélectionne la partie gauche du LCD
#define lcd_right()  LCD_CS1 = 0;   LCD_CS2 = 1;   // sélectionne la partie droite du LCD
#define lcd_strobe() LCD_EN = 1; asm("nop"); asm("nop");LCD_EN = 0;// strobe la donnée

lcd_init_both(unsigned char yMax){
   lcd_right();
   lcd_init(yMax);
   lcd_left();                      // LCD initialisé ligne 0, colonne 0, Z=0, coté gauche
   lcd_init(64);
}

lcd_init(unsigned char yMax){       // yMax = 63 : effacement total
   unsigned char x, y;
   lcd_disp_on_off(1);              // display ON
   lcd_startZ(0);
   for(x=8; x!=0; x--){          
      lcd_pageX(x);
      lcd_addressY(0);              
      for(y=yMax; y!=0; y--){    
         lcd_putdata(0);   
      }     
   }
   lcd_addressY(0);
   lcd_pageX(0);
}

lcd_putcmd(unsigned char cmd){
   FLAG_GIE_SAVE;
   lcd_busy();                      //       while(lcd_busy());             
   LCD_TRIS    = 0x00;              // out
   LCD_RS_DI   = 0; 
   LCD_R_W     = 0;
   LCD_DATA    = cmd;   
   lcd_strobe();
   FLAG_GIE_REST;
}

lcd_putdata(unsigned char data){
   FLAG_GIE_SAVE;
   lcd_busy();                      //       while(lcd_busy());
   LCD_TRIS    = 0x00;              // out 
   LCD_RS_DI   = 1; 
   LCD_R_W     = 0;
   LCD_DATA    = data;  
   lcd_strobe();
   FLAG_GIE_REST;
}

lcd_busy(void){
   unsigned char stat;

   if ((!LCD_CS1)&&(!LCD_CS2)) LCD_CS1 = 1;  
      // danger si CS1 et CS2 désactivés -> blocage while(lcd_busy);

   //FLAG_GIE_SAVE;
   LCD_TRIS    = 0xFF;              // in
   LCD_RS_DI   = 0; 
   LCD_R_W     = 1;


   //busy_lbl:
   
   do{
      LCD_EN      = 1;
      asm("nop");
      asm("nop");
      stat        = LCD_DATA; 
      LCD_EN      = 0;
   } while(stat&0x80);
}

lcd_disp_on_off(unsigned char disp){
   lcd_putcmd(0x3E | (disp & 0x01) );
}

lcd_addressY(unsigned char adr){
   lcd_putcmd(0x40 | (adr & 0x3F) );
}

lcd_pageX(unsigned char adr){
   lcd_putcmd(0xB8 | (adr & 0x07) );
}

lcd_startZ(unsigned char adr){
   lcd_putcmd(0xC0 | (adr & 0x3F) );
}

lcd_startZ, lcd_pageX, lcd_addressY, lcd_disp_on_off, lcd_init, lcd_init_both, lcd_left och lcd_right finns "avbildade" i state_machine. lcd_busy, lcd_put_cmd, lcd_put_data finns i sendCMD_D. lcd_strobe finns i e_strobe.

koden ovan är skriven för en PIC16F877 och ska kunna starta en KS0108B display (jag använder den vanliga som fractronics har, dvs blå/vit 128x64).

Jag använder Xilinx ISE 8.1i för övrigt.

EDIT: är det någon som vet ett smidigt sätt för två processor att kommunicera med en annan och att den kan svara de två processerna med typ "nu är jag klar".

Postat: 29 april 2006, 10:36:36
av d99dan
Jag testade att köra din kod i synplify och den tycker tex att

Kod: Markera allt

while DATA(7) = '1' loop
               wait_for <= '1';
         end loop; 
är en inte terminerande loop och det kan väl ligga något i det. Får du inga fel eller varningar när du compilerar?

Postat: 29 april 2006, 11:10:03
av Solution9
jag får massa warningar men inga fel.

Postat: 29 april 2006, 11:14:31
av d99dan
Så nu har jag modifierat din kod så att den går att syntetisera.

Kod: Markera allt

state_machine: process(IP)

Kod: Markera allt

		if DATA(7) = '1' then 
			wait_for <= '1';
		end if;

Kod: Markera allt

if (tempsig < "111111") then
                                 CMD(8 downto 0) <= "111111111";
                                 if done_sendning = '1' then
                                    tempsig <= tempsig + 1;
                                 end if;
                             end if;
är de ändringar jag gjorde det är nog inte säkert att det fungerar som du tänkt men det går att syntetisera, det är lite svårt att säga något om vad som är fel med din kod om den inte går att köra, verkar konstigt om det går i webpack. Jag har visst förlagt min vhdl bok någonstans men jag tror att du använder while fel, om du vill tilldela en signal ett värde beronde på någon annan och ett logiskt vilkor så ska de konstruktionerna ligga utanför processen tex

Kod: Markera allt

	end if;

	end process READ_VER;

	wbs_ACK_t <= ((wbs_acko or wbs_ACK_t) and wbs_STB_I);
	wbs_ACK_O <= wbs_ACK_t;
om det nu är det du försöker göra.

Och så till din fråga om interprocess kommunikation, så löses det med ett antal signaler. Jag vet inte riktigt vad du menar med smidigt men en signal från varje process till den 3:e och en jag_är_klar signal från den till de första 2. är hur jag skulle göra.

Postat: 29 april 2006, 11:15:34
av d99dan
vilka varningar?

Postat: 29 april 2006, 23:12:00
av Solution9
som du ser använder jag "status" signalerna för debuggning... och dom stannar alltid på "00000" vilket betyder att state-machine inte räknar upp IP... så någonting fungerar inte med antingen E-genereringen (E ska vara hög i 450 ns och låg i 450 ns enligt KS0108B databladet och med en 50 MHz klocka blir det 22,5 klockcykler som jag avrundade uppåt till 24) eller utskicket av kommandon...

angående dina modifieringar:

Modifiering 1: IP är inte en signal som ska väcka "state_machine" behöver den verkligen stå i känslighetslistan (heter det så på svenska?)

Modifiering 3: jag märkte att tempsig används samtidigt på flera ställen så jag fick ändra en del andra koder, men meningen är ju att det ska vara en loop...

här är varningarna jag får:

Kod: Markera allt

WARNING:HDLParsers:1406 - "E:/Main_Gate2/Main_Gate/My_VHDL/KS0108B/LCD/LCD.vhd" Line 93. No sensitivity list and no wait in the process
WARNING:Xst:819 - "E:/Main_Gate2/Main_Gate/My_VHDL/KS0108B/LCD/LCD.vhd" line 71: The following signals are missing in the process sensitivity list:
WARNING:Xst:819 - "E:/Main_Gate2/Main_Gate/My_VHDL/KS0108B/LCD/LCD.vhd" line 93: The following signals are missing in the process sensitivity list:
WARNING:Xst:1778 - Inout <RW> is assigned but never used.
WARNING:Xst:1778 - Inout <DATA<6:0>> is assigned but never used.
WARNING:Xst:737 - Found 1-bit latch for signal <CS1>.
WARNING:Xst:737 - Found 1-bit latch for signal <CS2>.
WARNING:Xst:737 - Found 6-bit latch for signal <tempsig>.
WARNING:Xst:737 - Found 1-bit latch for signal <wait_for>.
WARNING:Xst:737 - Found 1-bit latch for signal <RS>.
WARNING:Xst:737 - Found 1-bit latch for signal <RW>.
WARNING:Xst:737 - Found 1-bit latch for signal <done_sendning>.
WARNING:Xst:737 - Found 1-bit latch for signal <init_next_half>.
WARNING:Xst:737 - Found 1-bit latch for signal <status_4>.
WARNING:Xst:737 - Found 8-bit latch for signal <DATA>.
WARNING:Xst:737 - Found 9-bit latch for signal <CMD>.
WARNING:Xst:737 - Found 32-bit latch for signal <IP>.
WARNING:Xst:1426 - The value init of the FF/Latch status_4 hinder the constant cleaning in the block LCD.
WARNING:Xst:1291 - FF/Latch <IP_31> is unconnected in block <LCD>.
WARNING:Xst:1291 - FF/Latch <IP_30> is unconnected in block <LCD>.
WARNING:Xst:1291 - FF/Latch <IP_29> is unconnected in block <LCD>.
WARNING:Xst:1291 - FF/Latch <IP_28> is unconnected in block <LCD>.
WARNING:Xst:1291 - FF/Latch <IP_27> is unconnected in block <LCD>.
WARNING:Xst:1291 - FF/Latch <IP_26> is unconnected in block <LCD>.
WARNING:Xst:1291 - FF/Latch <IP_25> is unconnected in block <LCD>.
WARNING:Xst:1291 - FF/Latch <IP_24> is unconnected in block <LCD>.
WARNING:Xst:1291 - FF/Latch <IP_23> is unconnected in block <LCD>.
WARNING:Xst:1291 - FF/Latch <IP_22> is unconnected in block <LCD>.
WARNING:Xst:1291 - FF/Latch <IP_21> is unconnected in block <LCD>.
WARNING:Xst:1291 - FF/Latch <IP_20> is unconnected in block <LCD>.
WARNING:Xst:1291 - FF/Latch <IP_19> is unconnected in block <LCD>.
WARNING:Xst:1291 - FF/Latch <IP_18> is unconnected in block <LCD>.
WARNING:Xst:1291 - FF/Latch <IP_17> is unconnected in block <LCD>.
WARNING:Xst:1291 - FF/Latch <IP_16> is unconnected in block <LCD>.
WARNING:Xst:1291 - FF/Latch <IP_15> is unconnected in block <LCD>.
WARNING:Xst:1291 - FF/Latch <IP_14> is unconnected in block <LCD>.
WARNING:Xst:1291 - FF/Latch <IP_13> is unconnected in block <LCD>.
WARNING:Xst:1291 - FF/Latch <IP_12> is unconnected in block <LCD>.
WARNING:Xst:1291 - FF/Latch <IP_11> is unconnected in block <LCD>.
WARNING:Xst:1291 - FF/Latch <IP_10> is unconnected in block <LCD>.
WARNING:Xst:1291 - FF/Latch <IP_9> is unconnected in block <LCD>.
WARNING:Xst:1291 - FF/Latch <IP_8> is unconnected in block <LCD>.
WARNING:Xst:1291 - FF/Latch <IP_7> is unconnected in block <LCD>.
WARNING:Xst:1291 - FF/Latch <IP_6> is unconnected in block <LCD>.
WARNING:Xst:1291 - FF/Latch <IP_5> is unconnected in block <LCD>.
WARNING:Xst:1291 - FF/Latch <IP_4> is unconnected in block <LCD>.
WARNING:Xst:1426 - The value init of the FF/Latch init_next_half hinder the constant cleaning in the block LCD.
EDIT: en sak jag kom på nu... kan verkligen FPGA:n Xilinx Spartan 3 (400k) driva sina I/O pinnar till 5V eller ta emot 5V? som en KS0108B display använder sig av...

Postat: 30 april 2006, 10:50:35
av d99dan
Först tycker jag att du ska fundera på hur din kod går att optimera om du väljer wait_fot till 0 och CMD till 0 som start värde. Verktyg är normalt bra på att ta bort saker som inte behövs. Din kod gick inte att syntetisera med synplify utan mina ändringar så jag har inegn aning om vad som optimeras bort. Har du möjlighet att få en schematic vy över resultatet så brukar den vara informativ om just detta.

Ok vilken signal ska väcka state_machine? Jag är inte helt säker på vad du får med en process utan sensitivity list men en ide skulle ju kunna vara att den bara låser utsignalerna efter insignalernas startvärden. I de flesta fall bör man ha med alla insignaler i sensitivity list för asynkrona processer, eller clocka och reset i synkrona.

Vad är det du vill med while konstruktionen? Tänk på att det inte är en klockad process tempsig är inte i sensitivity list så det blir ingen fördröjning, ev kommer den räknas upp i steg om ett som ändå gör att det tar lite tid men den tiden är i vilket fall som heslst odefinierad. Verktyget får ju helt fria händer att tex, öka den i ett steg på 100 om det inte förstör något annat

While i en process ska inte användas för att lägga in delays utan för att tex gå igenom en table tex

Kod: Markera allt

while a(x) = '1' loop
  b(x) <= a(x) + 1;
  x <= x + 1;
end loop;
Så skulle man kunna använda den för att kopera en sträng med ettor från a till b och sluta när man kommer till första nollan, med reservation för syntaxen men principen bör stämma.

Jag har inte använt spartan 3 själv men vad jag vet så är den i det närmaste identisk med 2:an när det gäller signal nivåer och på den är det inga problem att ha 5V insignaler, de är väl egentligen inte 5V men specade som 5V toleranta. Men jag tror inte att den kan driva 5V själv den jobbar väl bara på 3V eller något sådant har jag för mig. Läs databladet de är bra och informativa från xlinx :)

edit: Du ändrar vilka signaler den ska använda i ucf filen och det är viktigt att göra rätt, tror jag. Jag har aldig provat att ha en 5V signal när jag har ställt in det på lägre.