CPLD LCD drivare, tips på förbättringar i Verilog-koden?

Elektronikrelaterade (på komponentnivå) frågor och funderingar.
Användarvisningsbild
E85
Inlägg: 1274
Blev medlem: 29 maj 2007, 16:24:19
Ort: Övik

CPLD LCD drivare, tips på förbättringar i Verilog-koden?

Inlägg av E85 »

Jag har skaffat ett Xilinx Coolrunner II starter kit som jag sitter och testar. Har skrivit kod som lyckas skriva ut bokstäver på LCD-displayen som följer med men eftersom jag är helt nybörjare är jag lite nyfiken ifall det går att förbättra koden på nåt smart sätt? Det här är i princip det första jag skriver i HDL...

Det den gör (eller borde göra):
0. Nollställ allt
1. Vänta 21ms, skicka "Set function"
2. Vänta 40us, skicka "Display set"
3. Vänta 40us, skicka "Display clear"
4. Vänta 1.6ms, skicka "Entry mode set"
5. Vänta 40us, skicka tecken 'A'
6. Vänta 40us, skicka tecken 'e'
7. Vänta på knapptryck...
8. Vänta 40us, skicka state-variabeln som ASCII-siffra

btn0 hoppar till steg 0. <- Rensar och skriver ut "Ae" på LCD:n
btn1 hoppar till steg 8. <- Skriver en '8' på LCD:n

Bild

Datablad på displayen: http://www.digilentinc.com/Data/Product ... m_RevA.pdf

Min kod såhär långt:

Kod: Markera allt

`timescale 1ns / 1ps

module t5(
    input clock,
    input btn0,
    input btn1,
    output reg [3:0] leds,
    output reg lcd_rs,
    output reg lcd_rw,
    output reg lcd_e,
    output reg [7:0] lcd_data
    );

reg [15:0] cnt;
reg [3:0] state;

initial begin
	state = 3'b000;
	leds = 4'b1111;
	lcd_e = 1'b1;
	lcd_rs = 1'b0;
	lcd_rw = 1'b0;
	lcd_data = 8'b00000000;
	cnt = 16'd0;
end

always @ (posedge clock) //1MHz clock
begin
	lcd_rw <= 1'b0;							//Set R/W to write
	leds <= ~state;							//Show state on LEDs (0=ON, 1=OFF)
	lcd_e <= (cnt <= 4) ? lcd_e : 1'b0;	//Keep E high 4 clocks
	cnt <= cnt + 1'b1;						//Increment timer (1 MHz)
	
	//state 0000, Wait 10 counts then reset outputs
	if (cnt == 16'd10 && state == 4'b0000)
	begin
		cnt <= 16'd0;
		state <= state + 1'b1;
		lcd_rs <= 1'b0;
		lcd_data <= 8'b00000000;
		lcd_e <= 1'b1;
	end
	//state 0001, Wait 21ms then send "Set function" to LCD
	else if (cnt == 16'd21000 && state == 4'b0001)
	begin
		cnt <= 16'd0;
		state <= state + 1'b1;
		lcd_rs <= 1'b0;
		lcd_data <= 8'b00001111;
		lcd_e <= 1'b1;
	end
	//state 0010, Wait 40us then send "Display set" to LCD
	else if (cnt == 16'd40 && state == 4'b0010)
	begin
		cnt <= 16'd0;
		state <= state + 1'b1;
		lcd_rs <= 1'b0;
		lcd_data <= 8'b00001111;
		lcd_e <= 1'b1;
	end
	//state 0011, Wait 40us then send "Display clear" to LCD
	else if (cnt == 16'd40 && state == 4'b0011)
	begin
		cnt <= 16'd0;
		state <= state + 1'b1;
		lcd_rs <= 1'b0;
		lcd_data <= 8'b00000001;
		lcd_e <= 1'b1;
	end
	//state 0100, Wait 1.6ms then send "Entry mode set" to LCD
	else if (cnt == 16'd1600 && state == 4'b0100)
	begin
		cnt <= 16'd0;
		state <= state + 1'b1;
		lcd_rs <= 1'b0;
		lcd_data <= 8'b00000110;
		lcd_e <= 1'b1;
	end
	//state 0101, Wait 40us then send char 'A' to LCD
	else if (cnt == 16'd40 && state == 4'b0101)
	begin
		cnt <= 16'd0;
		state <= state + 1'b1;
		lcd_rs <= 1'b1;
		lcd_data <= 8'b01000001;
		lcd_e <= 1'b1;
	end
	//state 0110, Wait 40us then send char 'e' to LCD
	else if (cnt == 16'd40 && state == 4'b0110)
	begin
		cnt <= 16'd0;
		state <= state + 1'b1;
		lcd_rs <= 1'b1;
		lcd_data <= 8'b01100101;
		lcd_e <= 1'b1;
	end

	//state 0111, Loop until button is pressed
	
	//state 1000, Wait 40us then send state number to LCD
	else if (cnt == 16'd40 && state == 4'b1000)
	begin
		cnt <= 16'd0;
		state <= state + 1'b1;
		lcd_rs <= 1'b1;
		lcd_data <= {4'b0011, state};
		lcd_e <= 1'b1;
	end
	
	//state 1001, Loop until button is pressed

	//Reset display when btn0 is pressed
	if (!btn0)
	begin
		state <= 4'b0000;
		cnt <= 16'd0;
	end
	
	//Jump to state 1000 on btn1 press
	if (!btn1)
	begin
		state <= 4'b1000;
		cnt <= 16'd0;
	end
end
endmodule
EDIT: Uppdaterat koden. Vet inte riktigt vad jag gjorde men nu blir det aldrig fel när jag trycker på knapparna. Men om nån har tips på förbättringar i mitt sätt att implementera delays eller nåt annat så skriv gärna!
Senast redigerad av E85 9 juli 2009, 00:47:12, redigerad totalt 3 gånger.
blueint
Inlägg: 23238
Blev medlem: 4 juli 2006, 19:26:11
Kontakt:

Re: CPLD LCD drivare, tips på förbättringar i Verilog-koden?

Inlägg av blueint »

Det du behöver är i princip en "state-machine" som klockas med lämplig frekvens i kHz. Sen kan du ev prova att sätta flankegenskaper på utgångarna för att minimera reflektioner.
cyr
Inlägg: 2712
Blev medlem: 27 maj 2003, 16:02:39
Ort: linköping
Kontakt:

Re: CPLD LCD drivare, tips på förbättringar i Verilog-koden?

Inlägg av cyr »

Jag ser ett tänkbart problem med din kod, och det är att du nog inte uppfyller Tsu (setup-tid) för displayen.

Om du körde liknande kod på en microcontroller skulle det inte vara något problem, koden sätter först upp data-bitarna och RS, och sen dras E hög. På CPLD:n görs allt på samma klockcykel, så förmodligen har du en Tsu på mellan -1 och 1 ns ungefär istället för >40ns som krävs enligt databladet.

Sen skulle jag skriva en del saker annorlunda för att göra koden mer lättläst och enklare att bygga vidare på. Ett tips är att dela upp det i mindre logiska block (skriva med egna always-satser eller kanske t.o.m separata verilog-moduler). Kanske en liten status-maskin som enbart hanterar timingen mot displayen och en som räknar ut vilka kommandon som ska skickas...

Gillar också att använda namngivna states och case-satser till statusmaskiner, ungefär såhär:

http://www.asic-world.com/tidbits/verilog_fsm.html
Användarvisningsbild
E85
Inlägg: 1274
Blev medlem: 29 maj 2007, 16:24:19
Ort: Övik

Re: CPLD LCD drivare, tips på förbättringar i Verilog-koden?

Inlägg av E85 »

Okej. Bra idé det där med namngivna states, det får jag nog börja med också. Jag såg det där med Tsu men visste inte hur jag enkelt skulle kunna fördröja E så det fick bli sådär. Tydligen skrivs byten när E går låg så det kanske inte gör nåt?
Skriv svar