mikrocontroller.net

Forum: Projekte & Code [VHDL] 16x2 LCD Textcontroller / HD44780


Autor: Läubi .. (laeubi) Benutzerseite
Datum:
Angehängte Dateien:

Bewertung
1 lesenswert
nicht lesenswert
Da ich im Internet immer nur die Info gefunden habe ein Text LCD 
Controller sei zu "komplex" und man solle doch einen Softcore verwenden 
habe ich mir selber einen geschrieben.
Unterstüzt zur Zeit 16x2 im 8-Bit Modus, sollte sich aber leicht 
anpassen lassen.

Braucht etwa 80 Slices, wobei 32 auf einen Schattenspeicher entfallen, 
d.h. man kann in die Komponente mit vollem Systemtakt schreiben und der 
Controller überträgt die Daten dann kontinuierlich an das LCD.

Getestet habe ich das ganze mit meinem Spartan3A Startet Board mit 
folgendem Code, es wird einfach bis zum init gewartet und dann 
kontinuierlich in die erste Zeile ein '#' Zeichen geschrieben.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity LCD16x2TEST is
    Port ( clk_50M : in  STD_LOGIC;
           LCD_DB  : out  STD_LOGIC_VECTOR (7 downto 0);
           LCD_E   : out  STD_LOGIC;
           LCD_RW  : out STD_LOGIC;
           LCD_RS  : out  STD_LOGIC
    );
end LCD16x2TEST;

architecture Behavioral of LCD16x2TEST is
component CHAR_LCD_CTR is
    Port ( clk_50M            : in  STD_LOGIC;
           LCDData            : out  STD_LOGIC_VECTOR (7 downto 0);
           LCD_Enable         : out  STD_LOGIC;
           LCD_RW             : out STD_LOGIC;
           LCD_RegisterSelect : out  STD_LOGIC;
           init_done          : out std_logic;
           address            : in std_logic_vector(4 downto 0);
           data               : in std_logic_vector(7 downto 0);
           wr                 : in std_logic
    );
end component;
signal init_done  : std_logic;
signal address    : std_logic_vector(4 downto 0) := (others =>'0');
signal data       : std_logic_vector(7 downto 0) := x"23";
signal wr         : std_logic := '0';
constant end_Addr : integer := 15;
begin

    TEST: process 
    begin
    wait until rising_edge(clk_50m);    
        if init_done = '1' then
            wr      <= '1';
            if address /= end_Addr then
                address <= address + 1;
            else
                address <= (others => '0');
            end if;
        end if;
    end process;

LCD16x2: CHAR_LCD_CTR 
    Port map(clk_50M, LCD_DB, LCD_E, LCD_RW, LCD_RS, init_done, address, data, wr);
end Behavioral;

Die UCF Constraints für das Board:
NET "CLK_50M"       LOC = "E12"  | IOSTANDARD = LVCMOS33 | PERIOD = 20.000 ;
OFFSET = IN  10.000 VALID 20.000 BEFORE "CLK_50M" ;
OFFSET = OUT 20.000 AFTER "CLK_50M" ;
##############################################################################
# Character Display (LCD)
##############################################################################
NET "LCD_DB<0>"     LOC = "Y13"  | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "LCD_DB<1>"     LOC = "AB18" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "LCD_DB<2>"     LOC = "AB17" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "LCD_DB<3>"     LOC = "AB12" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "LCD_DB<4>"     LOC = "AA12" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "LCD_DB<5>"     LOC = "Y16"  | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "LCD_DB<6>"     LOC = "AB16" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "LCD_DB<7>"     LOC = "Y15"  | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "LCD_E"         LOC = "AB4"  | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "LCD_RS"        LOC = "Y14"  | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "LCD_RW"        LOC = "W13"  | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;

Verbesserungsmöglichkeiten und konstruktive Vorschläge sind gerne 
Willkommen.

Autor: LOSIjunior (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Herr Läubi,
Ich bin auf der Suche nach einem möglichst einfachen Display controller.
Dieser sollte endlos einen logic_vector am Display anzeigen.

Mein FPGA: Altera MAX II EMP2210F324C3N / 50 MHz
LC-Display: EA DIP204B-4NLW mit 4x20 Zeichen
dieser enthällt den KS0073 kontroller welcher zu 100% mit dem HD44780 
kompatibel ist.

Das Signal welches am Display angezeigt werden sollte ist:
display      : IN   std_logic_vector(639 downto 0);

Dieses ist folgendermassen zu interpretieren: (80 ASCII zeichen)

display(639 downto 632)   1. Zeile(oben) 1. ASCII-Zeichen (links)
display(159 downto 152)   4. Zeile(unten) 1. ASCII-Zeichen (links)
display(007 downto 000)   4. Zeile(unten) 20. ASCII-Zeichen (rechts)
... etc ...

Die Signale zum Display sind:
lcd_data    : OUT  std_logic_vector(7 downto 0);
lcd_rs      : OUT  std_logic;
lcd_rw      : OUT  std_logic;
lcd_e      : OUT  std_logic

Der Code sollte möglichst wenig Logik zellen im FPGA verwenden.

Kann du mir erklären, wie ich das implementieren kann?

Mit freundlichen Grüsse
LOSIjunior

Autor: nur (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
es wäre auch schon wenn deine codes synthezierbar wäre.

Autor: Läubi .. (laeubi) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
nur schrieb:
> Hallo,
> es wäre auch schon wenn deine codes synthezierbar wäre.

Zumindest auf XILINX FPGAs mit Block-RAM ist er das, ohne etwas mehr 
Infos kann aber niemand sagen wo es bei dir ggf. hängt.

LOSIjunior schrieb:
> Das Signal welches am Display angezeigt werden sollte ist:
> display      : IN   std_logic_vector(639 downto 0);

Was spricht gegen die RAM Lösung?

LOSIjunior schrieb:
> Der Code sollte möglichst wenig Logik zellen im FPGA verwenden

Der Verbrauch ist oben angegeben.

Autor: Karl-Heinz M. (khmweb)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Newbie-Antwort:
Ich hab auch Fehler bei der Synthesis für die oben gezeigten Codes 
(einkopiert in neue Files vhd und ucf):

ERROR:Xst:2585 - Port <LCD_Enable> of instance <LCD16x2> does not exist 
in definition <CHAR_LCD_CTR>. Please compare the definition of block 
<CHAR_LCD_CTR> to its component declaration to detect the mismatch.

ERROR:Xst:2585 - Port <LCD_RW> of instance <LCD16x2> does not exist in 
definition <CHAR_LCD_CTR>. Please compare the definition of block 
<CHAR_LCD_CTR> to its component declaration to detect the mismatch.

ERROR:Xst:2585 - Port <LCDData> of instance <LCD16x2> does not exist in 
definition <CHAR_LCD_CTR>. Please compare the definition of block 
<CHAR_LCD_CTR> to its component declaration to detect the mismatch.

CHAR_LCD_CTR.vhd hab ich noch nicht ausprobiert. Was mache ich falsch?

Autor: Läubi .. (laeubi) Benutzerseite
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Karl-Heinz M. schrieb:
> CHAR_LCD_CTR.vhd hab ich noch nicht ausprobiert. Was mache ich falsch?

Was heißt das? Ohne die Datei funktioniert es nicht, das oben angegeben 
ist nur der Testcode für das Modul welches in CHAR_LCD_CTR.vhd steckt!

Autor: Karl-Heinz M. (khmweb)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das heißt: Ich hab die beiden kopiert, aber nicht die andere benutzt. 
Ich brauche also den Testcode nicht?

Autor: Läubi .. (laeubi) Benutzerseite
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Karl-Heinz M. schrieb:
> Ich brauche also den Testcode nicht?

Nur wenn du es auf ein "echtes" Board bringen willst, dann mußt du aber 
ggf. die Pinzuordnungen anpassen.

Wenn du das ganze nur synthetisieren/simulieren möchtest reicht auch das 
reine Modul.

Falls deine Erfahrung in VHDL noch recht neu ist würde ich erstmal mit 
einem einfachem Beispiel beginnen.

Autor: Basti (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hmm... So ganz hab ich das jetzt noch nicht verstanden. Welcher der 
beiden Blöcke soll denn nun an die realen HardwarePorts gekoppelt 
werden?

Autor: Karl-Heinz M. (khmweb)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Läubi .. schrieb:
> Falls deine Erfahrung in VHDL noch recht neu ist würde ich erstmal mit
> einem einfachem Beispiel beginnen.

Dank Dir, aber mein Prob ist trotzdem nicht viel anders als das von 
Basti. Offenbar hatte jeder hier damit Probleme für die ich keine Lösung 
seh und das nicht nachvollziehen kann.

Im XILINX Tut sieht das für mich ziemlich ähnlich aus, wie das hier.

Autor: Basti (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nach kurzem drübersehen vermute ich, dass ich den Block CHAR_LCD_CTR 
brauche. An diesen übergebe ich nun meine gewünschte Andresse (also 
Zeile 1 Zeichen 1) und meine Daten. ????

Autor: Läubi .. (laeubi) Benutzerseite
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Basti schrieb:
> Nach kurzem drübersehen vermute ich, dass ich den Block CHAR_LCD_CTR
> brauche. An diesen übergebe ich nun meine gewünschte Andresse (also
> Zeile 1 Zeichen 1) und meine Daten. ????

So ist es. Der CHAR_LCD_CTR ist im Prinzip für dich ein 
Write-Only-Memory, welches die Geschriebenen Daten auf dem LCD ausgibt.
Alles auf der linken Seite deiner Grafik ist dabei das, was du benutzt, 
das auf der rechten Seite wird an die Pins des LCD verdrahtet (Ausnahme: 
Init done).

Das Beispiel zeigt nur wie man das ganze verwenden könnte muss aber 
wie gesagt für das konkrete Board angepasst werden!

Autor: Basti (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also drahte ich das INIT_DONE an meinen eigenen Block. Wenn da was 
kommt, heißt das für mich, ich kann daten rüber schieben? Super!

Autor: Läubi .. (laeubi) Benutzerseite
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Basti schrieb:
> Also drahte ich das INIT_DONE an meinen eigenen Block. Wenn da was
> kommt, heißt das für mich, ich kann daten rüber schieben?

So ist es. Aus Platz- und Anpassungsgründen nutze ich das Ram auch für 
die Init Sequenz des LCD, wenn vorher geschrieben wird wird ggf. diese 
überschrieben, deshalb im Usercode erst auf init_done warten.

Autor: Karl-Heinz M. (khmweb)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das sind jetzt mal klare Hinweise, besten Dank, Läubi! Damit kann man 
auch was anfangen. Schaun wir mal...

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.