Forum: FPGA, VHDL & Co. VGA - Fortsetzung


von Kampi (Gast)


Lesenswert?

Hallo,

ich habe gestern mein VGA Projekt wieder ausgekramt und wollte mal 
wieder etwas daran weiter arbeiten (das lag jetzt eine ganze Weile).
Aber irgendwie funktioniert das nicht....ich möchte den Bildschirm 
einfach einfarbig machen...
Wo steckt der Fehler im Code?
Die Komponente "System" ist ein RAM + Clock Manager für den VGA Takt.

VGA Top
1
----------------------------------------------------------------------------------
2
-- Company:         www.kampis-elektroecke.de
3
-- Engineer:        Daniel Kampert
4
-- 
5
-- Create Date:     02.08.2014 13:17:51
6
-- Design Name: 
7
-- Module Name:     VGA_Top - VGA_Top_Arch
8
-- Project Name: 
9
-- Target Devices:  XC7Z010CLG400-1
10
-- Tool Versions:   Vivado 2014.2
11
-- Description:     VGA Interface for a 640 x 480 Pixel Screen
12
-- 
13
-- Dependencies: 
14
-- 
15
-- Revision:
16
-- Revision         0.01 - File Created
17
-- Additional Comments:
18
-- 
19
----------------------------------------------------------------------------------
20
21
library IEEE;
22
use IEEE.STD_LOGIC_1164.ALL;
23
24
-- Uncomment the following library declaration if using
25
-- arithmetic functions with Signed or Unsigned values
26
use IEEE.NUMERIC_STD.ALL;
27
28
-- Uncomment the following library declaration if instantiating
29
-- any Xilinx leaf cells in this code.
30
--library UNISIM;
31
--use UNISIM.VComponents.all;
32
33
entity VGA_Top is
34
    Port (  Color : out STD_LOGIC_VECTOR(15 downto 0);
35
            HSync : out STD_LOGIC;
36
            VSync : out STD_LOGIC;
37
            Output : out STD_LOGIC_VECTOR(3 downto 0);
38
            Reset : in STD_LOGIC;
39
            Clock : in STD_LOGIC         
40
            );
41
end VGA_Top;
42
43
architecture VGA_Top_Arch of VGA_Top is
44
45
    constant Char_Size : integer := 8;
46
47
    -- Clocksignale
48
    signal Clock_VGA : std_logic;
49
    signal Clock_1250 : std_logic;
50
51
    -- Koordinaten des Zeigers auf dem Bildschirm
52
    signal Pos_x : std_logic_vector(9 downto 0) := "0001100100";                
53
    signal Pos_y : std_logic_vector(9 downto 0) := "0001100100"; 
54
    
55
    -- Font ROM
56
    signal Character_No : std_logic_vector(1 downto 0);
57
    signal Row_Addr : std_logic_vector(2 downto 0);
58
    signal ROM_Col : std_logic_vector(2 downto 0);
59
    signal ROM_Addr : std_logic_vector(4 downto 0);
60
    signal ROM_Data : std_logic_vector(7 downto 0);
61
    signal ROM_Bit : std_logic;
62
    
63
    -- Positionen
64
    signal Pos_x_l : integer := 8;
65
    signal Pos_y_t : integer := 8;
66
    signal Pos_x_r : integer := Pos_x_l + Char_Size - 1;
67
    signal Pos_y_b : integer := Pos_y_t + Char_Size - 1;
68
    
69
    --Enable Signale für die Formen
70
    signal Text_on : std_logic;
71
72
    -- Systemsignale
73
    signal Lock : std_logic;
74
75
    -- Erzeugung des 25,175MHz Taktes und einbinden des RAM Moduls
76
    component System is
77
        Port (  Address_RAM : in STD_LOGIC_VECTOR (3 downto 0);
78
                Clock_In : in STD_LOGIC;
79
                Clock_Locked : out STD_LOGIC;
80
                Clock_Out : out STD_LOGIC;
81
                Clock_RAM : in STD_LOGIC;
82
                Clock_Reset : in STD_LOGIC;
83
                RAM_Out : out STD_LOGIC_VECTOR (3 downto 0)
84
                );
85
    end component System;
86
    
87
    -- Einbinden des VGA-Controllers
88
    component VGA_Controller is
89
        Port (  HSync : out STD_LOGIC;
90
                VSync : out STD_LOGIC;
91
                Clock_VGA : in STD_LOGIC;
92
                Reset : in STD_LOGIC;
93
                x_out : out STD_LOGIC_VECTOR(9 downto 0);                
94
                y_out : out STD_LOGIC_VECTOR(9 downto 0) 
95
                );
96
    end component VGA_Controller;  
97
98
begin
99
    
100
    Clock_25MHz     : System port map ("0001", Clock, Lock, Clock_VGA, Clock_VGA, '1', Output);
101
    VGA_Core        : VGA_Controller port map (HSync, VSync, Clock_VGA, '1', Pos_x, Pos_y);   
102
103
    -- Wenn Position erreicht, Enable-Signal auf High setzen
104
    Text_on <=
105
        '1' when (Pos_x_l <= to_integer(unsigned(Pos_x))) and (to_integer(unsigned(Pos_x)) <= Pos_x_r) and
106
                 (Pos_y_t <= to_integer(unsigned(Pos_y))) and (to_integer(unsigned(Pos_y)) <= Pos_y_b) else '0'; 
107
    
108
    -- ROM auslesen
109
    Row_Addr <= Pos_y(2 downto 0);
110
    ROM_Addr <= Character_No & Row_Addr;
111
    
112
    ROM_Col <= Pos_x(2 downto 0);
113
    ROM_Bit <= ROM_Data(7 - to_integer(unsigned(ROM_Col)));
114
115
    -- Formen am Bildschirm ausgeben
116
   -- process(Clock_VGA)
117
    --begin
118
        --if(Text_on = '1') then
119
             Color <= x"FFFF";   
120
        --end if;
121
        
122
        --Color <= x"0000" ;
123
        
124
    --end process;
125
126
    -- Betriebsstatus
127
    --Output(1) <= Lock;
128
    --Output(0) <= Reset;
129
    
130
end VGA_Top_Arch;

VGA Controller
1
----------------------------------------------------------------------------------
2
-- Company:         www.kampis-elektroecke.de
3
-- Engineer:        Daniel Kampert
4
-- 
5
-- Create Date:     06.08.2014 23:31:52
6
-- Design Name: 
7
-- Module Name:     VGA_Controller - VGA_Controller_Arch
8
-- Project Name: 
9
-- Target Devices:  XC7Z010CLG400-1
10
-- Tool Versions:   Vivado 2014.2
11
-- Description:     Der Controller erzeugt alle notwendigen Signale
12
--                  für ein VGA Interface
13
-- Dependencies: 
14
-- 
15
-- Revision:
16
-- Revision         0.01 - File Created
17
-- Additional Comments:
18
-- 
19
----------------------------------------------------------------------------------
20
21
library IEEE;
22
use IEEE.STD_LOGIC_1164.ALL;
23
use IEEE.NUMERIC_STD.ALL;
24
25
-- Uncomment the following library declaration if instantiating
26
-- any Xilinx leaf cells in this code.
27
--library UNISIM;
28
--use UNISIM.VComponents.all;
29
30
entity VGA_Controller is
31
    Generic (
32
            -- Bildeinstellungen
33
            -- Für andere Monitorformate diese Werte anpassen
34
            -- Horizontal timing
35
            WholeLine : integer := 800;
36
            BackPorch_H : integer := 48;
37
            SyncPulse_H : integer := 96;
38
            VisibleArea_H : integer := 640;
39
            FrontPorch_H : integer := 16;
40
            
41
            -- Vertical timing
42
            WholeFrame : integer := 525;
43
            BackPorch_V : integer := 33;
44
            SyncPulse_V : integer := 2;
45
            VisibleArea_V : integer := 480
46
            );
47
    Port (  HSync : out STD_LOGIC;            
48
            VSync : out STD_LOGIC;              
49
            Clock_VGA : in STD_LOGIC;           
50
            Reset : in STD_LOGIC;                           
51
            x_out : out STD_LOGIC_VECTOR(9 downto 0);                
52
            y_out : out STD_LOGIC_VECTOR(9 downto 0)                
53
            );
54
end VGA_Controller;
55
56
architecture VGA_Controller_Arch of VGA_Controller is
57
58
    signal x : integer range 0 to (VisibleArea_H - 1);
59
    signal y : integer range 0 to (VisibleArea_V - 1);
60
    
61
    -- Aktuelle Pixelpositionen des Monitors
62
    signal Pixel_Counter : integer;
63
    signal Line_Counter : integer;
64
65
begin
66
67
    x_out <= std_logic_vector(to_unsigned(x, x_out'length));
68
    y_out <= std_logic_vector(to_unsigned(y, y_out'length));
69
70
    -- X-Koordinate hochzählen
71
    process(Clock_VGA)
72
    begin
73
        if rising_edge(Clock_VGA) then
74
            if(x < (VisibleArea_H - 1)) then    
75
                x <= x + 1;  
76
            end if;
77
           
78
            if(Pixel_Counter <= (BackPorch_H + SyncPulse_H)) then
79
                x <= 0;
80
            end if;
81
        end if;        
82
    end process;
83
   
84
    -- Y-Koordinate hochzählen
85
    process(Clock_VGA)
86
    begin
87
        if rising_edge(Clock_VGA) then
88
            if((y < (VisibleArea_V - 1)) and (Pixel_Counter = WholeLine))  then    
89
                y <= y + 1; 
90
            end if;
91
           
92
            if(Line_Counter <= BackPorch_V)     then    y <= 0;     end if;
93
        end if;        
94
    end process;
95
96
    -- HSync auslösen
97
    process(Clock_VGA)
98
    begin
99
        if rising_edge(Clock_VGA) then
100
            if(Pixel_Counter = 0)               then    HSync <= '0';   end if;
101
            if(Pixel_Counter = SyncPulse_H)     then    HSync <= '1';   end if;
102
        end if;
103
    end process; 
104
   
105
    -- VSync auslösen
106
    process(Clock_VGA)
107
    begin
108
        if rising_edge(Clock_VGA) then
109
            if(Line_Counter = 0)                then    VSync <= '0';   end if;  
110
            if(Line_Counter = SyncPulse_V)      then    VSync <= '1';   end if;          
111
        end if;
112
    end process; 
113
   
114
    -- Counter
115
    process(Clock_VGA)
116
    begin
117
        if (rising_edge(Clock_VGA)) then
118
            if(Reset = '0') then
119
                Pixel_Counter <= 0;
120
                Line_Counter <= 0;
121
            else
122
                -- Pixelzähler erhöhen
123
                Pixel_Counter <= Pixel_Counter + 1;
124
               
125
                -- Pixelcounter zurücksetzen und Zeilencounter erhöhen
126
                if(Pixel_Counter = WholeLine) then
127
                    Pixel_Counter <= 0;
128
                    Line_Counter <= Line_Counter + 1;
129
                end if; 
130
               
131
                -- Zeilencounter zurücksetzen
132
                if(Line_Counter = WholeFrame)  then    Line_Counter <= 0;  end if;
133
            end if;
134
        end if;
135
    end process;
136
end VGA_Controller_Arch;

Ist bestimmt nur ein kleiner Fehler...aber ich sehe es gerade nicht :(

Danke für die Hilfe!

von Dumdi D. (dumdidum)


Lesenswert?

Vielleicht ist die Hardware ein Problem. Bei mir ging einfarbig nicht. 
(Da war wohl irgendeo ein Hochpass). Probier mal zweifarbig.

von Fpgakuechle K. (Gast)


Lesenswert?

Kampi schrieb:
> Hallo,
>
> ich habe gestern mein VGA Projekt wieder ausgekramt und wollte mal
> wieder etwas daran weiter arbeiten (das lag jetzt eine ganze Weile).
> Aber irgendwie funktioniert das nicht....ich möchte den Bildschirm
> einfach einfarbig machen...
> Wo steckt der Fehler im Code?

Der fehler steckt erst mal in deiner Vorgehensweise:
-Es fehlt eine genaue Beschreibung des Fehlerbildes - Was passiert am 
Monitor
-Es fehlt eine Simulation.

So mit drüberschauen hab ich nicht erkennen wann welche synxs wie lange 
aktiv sind und ob im nicht sichtbaren Feld die Daten auch auf 0 gezogen 
werden.
Besser ist IMHO zwei counter für horizontal und vertikal durchlaufen 
lassen und dann mit komperatoren syncs und enable zu setzen.

MfG,

von Daniel K. (daniel_k80)


Lesenswert?

Hallo,

danke für die Antworten.
Also zum Fehlerbild:
Ich habe einen kleinen 640x480 Monitor den ich an das FPGA anschließe. 
Sobald kein Kabel angeschlossen ist, gibt er eine Meldung "No Signal" 
aus....diese verschwindet beim FPGA, aber der Monoitor bleibt schwarz.
Daraufhin habe ich mit meinem LA mal HS und VS durchgemessen und die 
Signale laufen und auch die Timings stimmen.
Es kann daher eigentlich nur an den Farben liegen (ich probiere mal 
zweifarbig).

Was meinst du genau mit den zwei Countern?
Im Moment habe ich es ja so gelöst, dass ein Counter das Zählen 
übernimmt und dann mit Hilfe zweier Vergleichswerte die Synchs 
geschaltet werden (VGA-Controller ist für das Timing da....VGA Top soll 
die Farben darstellen - im Idealfall aus dem RAM :) ).

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Fpga Kuechle schrieb:
> -Es fehlt eine Simulation.
Das würde ich auch sagen. Denn gerade so ein unidirektionales Interface 
wie hier ist doch in Sekundenschnelle wenigstens bis zur Waveform 
simuliert: Takt anlegen und zuschauen. Dann sieht man blitzschnell, ob 
die Timings grundlegend passen...

BTW: du hattest das Zeug im Beitrag "Kein Bild bei eigenem VGA" 
doch schon am Laufen. Warum geht das nicht mehr?

: Bearbeitet durch Moderator
von Mike (Gast)


Lesenswert?

Du musst das Farbsignal während der Austastlücken unbedingt auf 0 
setzen.

Bei aktuellen Monitoren kann man im OSD nachschauen was für eine 
Auflösung erkannt wurde. Steht dort was?

von Daniel K. (daniel_k80)


Angehängte Dateien:

Lesenswert?

Mike schrieb:
> Du musst das Farbsignal während der Austastlücken unbedingt auf 0
> setzen.
>
> Bei aktuellen Monitoren kann man im OSD nachschauen was für eine
> Auflösung erkannt wurde. Steht dort was?

Ah der Tipp ist gut....
Bei dem Monitor handelt es sich um einen VGA/LVDS Konverter + 
Display...da habe ich leider nicht die entsprechende Platine mit Knöpfen 
um das zu sehen.

Btw...ich versuche gerade das ganze zu simulieren, bekomme bei VSync und 
HSync die ganze Zeit nur ein "U" im Simulator (hab erst einmal nur den 
VGA-Controller für die Timings).
Da ich gestern mit dem LA gemessen habe weiß ich, dass es 
funktioniert....aber warum nicht in der Simulation?

Edit:
Problem gefunden.... -.-
Der Simulator hat die längere Simulationszeit nicht akzeptiert :D
Anbei die Screenshots der Simulation vom Controller

: Bearbeitet durch User
von Daniel K. (daniel_k80)


Lesenswert?

Daniel K. schrieb:
> Mike schrieb:
>> Du musst das Farbsignal während der Austastlücken unbedingt auf 0
>> setzen.
>>
>> Bei aktuellen Monitoren kann man im OSD nachschauen was für eine
>> Auflösung erkannt wurde. Steht dort was?
>
> Ah der Tipp ist gut....
> Bei dem Monitor handelt es sich um einen VGA/LVDS Konverter +
> Display...da habe ich leider nicht die entsprechende Platine mit Knöpfen
> um das zu sehen.
>
> Btw...ich versuche gerade das ganze zu simulieren, bekomme bei VSync und
> HSync die ganze Zeit nur ein "U" im Simulator (hab erst einmal nur den
> VGA-Controller für die Timings).
> Da ich gestern mit dem LA gemessen habe weiß ich, dass es
> funktioniert....aber warum nicht in der Simulation?
>
> Edit:
> Problem gefunden.... -.-
> Der Simulator hat die längere Simulationszeit nicht akzeptiert :D
> Anbei die Screenshots der Simulation vom Controller

Sorry Timings sind auf den Screens falsch...
VSync: 16,7047ms, Breite Low Level: 63,597us
HSync: 35,632us, Breite Low Level: 3,813us

von Daniel K. (daniel_k80)


Lesenswert?

Hallo,

ich habe gestern noch mal die Timins gecheckt...sowohl in der Simulation 
als auch in der Hardware. Beide waren für einen 640x480 Monitor in 
Ordnung.
Jetzt will ich einfach eine Farbe am Monitor ausgeben....:
1
----------------------------------------------------------------------------------
2
-- Company:         www.kampis-elektroecke.de
3
-- Engineer:        Daniel Kampert
4
-- 
5
-- Create Date:     02.08.2014 13:17:51
6
-- Design Name: 
7
-- Module Name:     VGA_Top - VGA_Top_Arch
8
-- Project Name: 
9
-- Target Devices:  XC7Z010CLG400-1
10
-- Tool Versions:   Vivado 2014.2
11
-- Description:     VGA Interface for a 640 x 480 Pixel Screen
12
-- 
13
-- Dependencies: 
14
-- 
15
-- Revision:
16
-- Revision         0.01 - File Created
17
-- Additional Comments:
18
-- 
19
----------------------------------------------------------------------------------
20
21
library IEEE;
22
use IEEE.STD_LOGIC_1164.ALL;
23
24
-- Uncomment the following library declaration if using
25
-- arithmetic functions with Signed or Unsigned values
26
use IEEE.NUMERIC_STD.ALL;
27
28
-- Uncomment the following library declaration if instantiating
29
-- any Xilinx leaf cells in this code.
30
--library UNISIM;
31
--use UNISIM.VComponents.all;
32
33
entity VGA_Top is
34
    Port (  Color : out STD_LOGIC_VECTOR(15 downto 0);
35
            HSync : out STD_LOGIC;
36
            VSync : out STD_LOGIC;
37
            Reset : in STD_LOGIC;
38
            Clock_In : in STD_LOGIC         
39
            );
40
end VGA_Top;
41
42
architecture VGA_Top_Arch of VGA_Top is
43
44
    -- Clocksignale
45
    signal Clock_VGA : std_logic;
46
    signal Output : std_logic_vector(3 downto 0);
47
48
    -- Koordinaten des Zeigers auf dem Bildschirm
49
    signal Pos_x : std_logic_vector(9 downto 0);                
50
    signal Pos_y : std_logic_vector(9 downto 0); 
51
    
52
    -- Font ROM
53
    signal Character_No : std_logic_vector(1 downto 0);
54
    signal Row_Addr : std_logic_vector(2 downto 0);
55
    signal ROM_Col : std_logic_vector(2 downto 0);
56
    signal ROM_Addr : std_logic_vector(4 downto 0);
57
    signal ROM_Data : std_logic_vector(7 downto 0);
58
    signal ROM_Bit : std_logic;
59
60
    -- Systemsignale
61
    signal Lock : std_logic;
62
63
    -- Erzeugung des 25,175MHz Taktes und einbinden des RAM Moduls
64
    component Clock is
65
        Port (  Clock_In : in STD_LOGIC;
66
                Clock_Locked : out STD_LOGIC;
67
                Clock_Out : out STD_LOGIC;
68
                Clock_Reset : in STD_LOGIC
69
                );
70
    end component Clock;
71
    
72
    -- Einbinden des VGA-Controllers
73
    component VGA_Controller is
74
        Port (  HSync : out STD_LOGIC;
75
                VSync : out STD_LOGIC;
76
                Clock_VGA : in STD_LOGIC;
77
                Reset : in STD_LOGIC;
78
                x_out : out STD_LOGIC_VECTOR(9 downto 0);                
79
                y_out : out STD_LOGIC_VECTOR(9 downto 0) 
80
                );
81
    end component VGA_Controller;  
82
    
83
    -- Font-ROM für VGA-Controller
84
    component Font_ROM is
85
        Port (  ROM_DataOut : out STD_LOGIC_VECTOR(2 downto 0);
86
                ROM_Address : in STD_LOGIC_VECTOR(3 downto 0);
87
                ROM_Clock : in STD_LOGIC
88
                );
89
    end component Font_ROM;
90
91
begin
92
    
93
    Clock_25MHz     : Clock port map (Clock_In, Lock, Clock_VGA, '1');
94
    VGA_Core        : VGA_Controller port map (HSync, VSync, Clock_VGA, '1', Pos_x, Pos_y);   
95
96
    -- Formen am Bildschirm ausgeben
97
    process(Pos_x, Pos_y, Clock_VGA)
98
    begin
99
    if rising_edge(Clock_VGA) then
100
        if((to_integer(unsigned(Pos_x)) > 200) and (to_integer(unsigned(Pos_y)) > 200)) then
101
             Color <= x"FFFF";   
102
        end if;
103
    end if;   
104
        Color <= x"0000" 
105
    
106
end VGA_Top_Arch;

Ich habe jetzt auch mal einen anderen Monitor genommen 
(testweise)...dort ist das selbe Verhalten zu erkennen...es passiert 
nichts....keine Farben, nur die Meldung "No Signal" verschwindet :/

: Bearbeitet durch User
von peter (Gast)


Lesenswert?

Setz mal x> , x< und y> , y<
Also Grenzen setzen auf das Sichtbare...

Gruss

von peter (Gast)


Lesenswert?

Wie ist bei dir RGB aufgeteilt?

Bei meinem DE0 ist es zb:
red   : OUT STD_LOGIC_VECTOR(3 downto 0);
green : OUT STD_LOGIC_VECTOR(3 downto 0);
blue  : OUT STD_LOGIC_VECTOR(3 downto 0);

Meine Abfrage für ein Farbkästchen zb:
if Counterx >=230 and Counterx < 245 then
if Countery >=20 and Countery < 40 then
red <="0011";
blue <="0011";
green <="0011";


Gruss

von Daniel K. (daniel_k80)


Lesenswert?

Hallo,

habe ich mal gemacht:
1
    Clock_25MHz     : Clock port map (Clock_In, Lock, Clock_VGA, '1');
2
    VGA_Core        : VGA_Controller port map (HSync, VSync, Clock_VGA, '1', Pos_x, Pos_y);   
3
4
    -- Formen am Bildschirm ausgeben
5
    process(Reset, Color_Enable, Clock_VGA)
6
    begin
7
        if(rising_edge(Clock_VGA)) then
8
            if(Reset = '0') then
9
                Color <= x"0000";
10
            else
11
                if(Color_Enable = '1') then
12
                    Color <= x"FFFF";
13
                else
14
                    Color <= x"0000";
15
                end if;
16
            end if;
17
        end if;
18
    end process;
19
    
20
   Color_Enable <= '1' when ((Pixel_x >= 230) and (Pixel_x < 245) and (Pixel_y >= 50) and (Pixel_y < 200)) else '0';
21
22
    Pixel_x <= unsigned(Pos_x);
23
    Pixel_y <= unsigned(Pos_y);

Aufteilung beim Zybo ist wie folgt:

Rot: 5 Bit (0 - 4)
Blau: 5 Bit (5 - 9)
Grün: 6 Bit (10 -15)

Zusammen sind es die 16 Bit des Vectors "Color"

: Bearbeitet durch User
von Daniel K. (daniel_k80)


Lesenswert?

Ok! Ich habe es hinbekommen.
Ich habe noch mal den VGA-Controller simuliert, die Timings gecheckt, 
paar kleine Änderungen vorgenommen und dann das Top Design simuliert.
Wie sich herausgestellt hat, hat der Core nicht die x und y Koordinaten 
hochgezählt, da ich die Bedingung vor dem Hochzählen immer vorher zurück 
gesetzt habe.

Danke für die Hilfe! Es war zudem eine schöne Übung für den 
Simulator....und wie ich gesehen habe mag der Simulator keinen DCM, da 
ich immer keinen Takt hatte sobald dieser im Design war.

von Duke Scarring (Gast)


Lesenswert?

Daniel K. schrieb:
> wie ich gesehen habe mag der Simulator keinen DCM, da
> ich immer keinen Takt hatte sobald dieser im Design war.
Du mußt möglicherweise die Zeitauflösung des Simulators auf ps 
(Picosekunden) stellen, damit die DCm richtig simuliert wird.

Duke

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Daniel K. schrieb:
> die x und y Koordinaten
Diese beiden Zähler würde ich sowieso als Integer ausführen, damit diese 
Umwandlungsorgie entfällt:
1
        if((to_integer(unsigned(Pos_x)) > 200) and (to_integer(unsigned(Pos_y)) > 200)) then
Es liest sich so einfach flüssiger:
1
        if (Pos_x > 200 and Pos_y > 200) then

von Josef G. (bome) Benutzerseite


Lesenswert?

Lothar Miller schrieb:
> Diese beiden Zähler würde ich sowieso als Integer
> ausführen, damit diese Umwandlungsorgie entfällt:

Oder einfach das to_integer weglassen.
Rechnen kann man auch mit unsigned.

von Daniel K. (daniel_k80)


Lesenswert?

Josef G. schrieb:
> Lothar Miller schrieb:
>> Diese beiden Zähler würde ich sowieso als Integer
>> ausführen, damit diese Umwandlungsorgie entfällt:
>
> Oder einfach das to_integer weglassen.
> Rechnen kann man auch mit unsigned.

Ich habe nun einfach einen Integer genommen :)
Funktioniert genau so gut

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Josef G. schrieb:
> Oder einfach das to_integer weglassen.
> Rechnen kann man auch mit unsigned.
Bringt nichts, denn der Vergleich ist dann genauso unleserlich:
1
        if (Pos_x > to_unsigned(200,Pos_x'length) and Pos_y > to_unsigned(200,Pos_y'length)) then

: Bearbeitet durch Moderator
von Josef G. (bome) Benutzerseite


Lesenswert?

Lothar Miller schrieb:
> Bringt nichts, denn der Vergleich ist dann genauso unleserlich:

So hatte ich gemeint:
1
if((unsigned(Pos_x) > 200) and (unsigned(Pos_y) > 200)) then

Geht das nicht?

von Daniel K. (daniel_k80)


Lesenswert?

Hallo,

so ich habe gestern noch etwas weiter gewerkelt...
Mittlerweile läuft der Core richtig gut...Timing Probleme sind alle 
behoben und ich kann über Positionen zwischen 0-79 und 0-59 die Position 
des Zeichens auf dem Monitor angeben.
Ein FONT-Rom ist auch weitestgehend vorhanden und ich bin schon in der 
Lage Buchstaben und Zahlen auszugeben.
Leider sind das erst einzelne Zahlen und Buchstaben.
Ich möchte nun mal zusammenhängende Zahlen und Worte (z.B. ein "Hello 
World") ausgeben.
Da muss ich ja einfach nur Zeichen x ausgeben, Zähler inkrementieren, 
Zeichen x+1 an Position+1 ausgeben, etc.
Das ganze wollte ich mal für die Buchstabenkombi "ABCD" probieren:
1
    Clock_25MHz     : Clock port map (Clock_In, Clock_Lock, Clock_VGA, Reset);
2
    VGA_Top         : VGA port map (Clock_VGA, Reset, '1', std_logic_vector(to_unsigned(Zeichen, 8)), Farbe, Position, Zeile, HSync, VSync, RGB);
3
    
4
    process(Clock_1)
5
    begin
6
        if rising_edge(Clock_1) then
7
            for I in 0 to 3 loop
8
                Zeichen <= 64 + I;
9
                Position <= 39 + I;
10
            end loop;
11
   
12
        end if;
13
    end process;

Die Buchstaben sind nach ASCII-Wert in meinem ROM hinterlegt, sprich 65 
ist A etc.
Clock_1 ist einfach ein 1Hz Takt (etwa 1Hz :) ).
Leider wird mir auf dem Bildschirm nur der Buchstabe "A" angezeigt.
Ich gehe mal davon aus, dass ich die Schleife falsch benutzt habe...aber 
wie mache ich es richtig :)

Danke für die Hilfe!

von Markus F. (mfro)


Lesenswert?

Daniel K. schrieb:
> Ich gehe mal davon aus, dass ich die Schleife falsch benutzt habe

Hast Du. Was passiert innerhalb eines Prozesses?

Alles was da steht. Und zwar alles gleichzeitig. Innerhalb eines Taktes.

Eine FOR-Schleife ist damit prinzipiell nur eine verkürzte Schreibweise 
gegenüber der "ausgerollten" Form:
1
PROCESS (Clock1)
2
BEGIN
3
    FOR i IN 0 TO 3 LOOP
4
        a <= i;
5
    END LOOP;
6
END PROCESS;

ist also genau dasselbe wie
1
PROCESS (Clock1)
2
BEGIN
3
    a <= 0;
4
    a <= 1;
5
    a <= 2;
6
    a <= 3;
7
END PROCESS;

Nur daß Du letzteres wahrscheinlich gar nicht erst hinschreiben würdest, 
weil dir sofort klar ist, daß das irgendwie keinen großen Sinn macht...

von peter (Gast)


Lesenswert?

Hast du ein Screenram der dauernd von 0 - 4799 mit Ascii-Code 
beschrieben wird und die Pixel dann vom ROM geholt werden und 
dargestellt werden ?

Gruss

von Daniel K. (daniel_k80)


Lesenswert?

Hallo,

so ich habe noch etwas weiter gemacht...
Jetzt habe ich einen Display-RAM gemacht und diesen mit drei Zeichen 
gefüllt (jeweils Pixel 0, 1 und 2):
1
----------------------------------------------------------------------------------
2
-- Company:             www.kampis-elektroecke.de
3
-- Engineer:            Daniel Kampert
4
-- 
5
-- Create Date:         10.03.2015 09:26:02
6
-- Design Name: 
7
-- Module Name:         Display_RAM - Display_RAM_Arch
8
-- Project Name: 
9
-- Target Devices:      XC7Z010CLG400-1
10
-- Tool Versions:       Vivado 2014.4
11
-- Description: 
12
-- 
13
-- Dependencies: 
14
-- 
15
-- Revision:
16
-- Revision 0.01 - File Created
17
-- Additional Comments:
18
-- 
19
----------------------------------------------------------------------------------
20
21
library IEEE;
22
use IEEE.STD_LOGIC_1164.ALL;
23
24
-- Uncomment the following library declaration if using
25
-- arithmetic functions with Signed or Unsigned values
26
use IEEE.NUMERIC_STD.ALL;
27
28
-- Uncomment the following library declaration if instantiating
29
-- any Xilinx leaf cells in this code.
30
--library UNISIM;
31
--use UNISIM.VComponents.all;
32
33
entity Display_RAM is
34
    Generic (
35
            Addr_Width : integer := 20;
36
            Data_Width : integer := 8
37
            );
38
    Port (  Clock : in STD_LOGIC;
39
            Read_Write : in STD_LOGIC;
40
            Address : in STD_LOGIC_VECTOR((Addr_Width - 1) downto 0);
41
            Data_Out : out STD_LOGIC_VECTOR ((Data_Width - 1) downto 0);
42
            Data_In : in STD_LOGIC_VECTOR ((Data_Width - 1) downto 0)
43
            );
44
end Display_RAM;
45
46
architecture Display_RAM_Arch of Display_RAM is
47
48
    type Display_RAM_Type is array (0 to (2**Address'length) - 1) of std_logic_vector(Data_In'range);
49
    signal Read_Address : std_logic_vector(Address'range);
50
    signal RAM : Display_RAM_Type := (
51
    "01000000",
52
    "01000001",
53
    "01000010",
54
    others=> (others=>'0')
55
    );
56
    
57
begin
58
    
59
    process(Clock)
60
    begin
61
        if(rising_edge(Clock)) then
62
            if(Read_Write = '0') then
63
                RAM(to_integer(unsigned(Read_Address))) <= Data_In;
64
            end if;
65
            
66
            Read_Address <= Address;
67
            
68
        end if;
69
    end process;
70
71
    Data_Out <= RAM(to_integer(unsigned(Read_Address)));   
72
73
end Display_RAM_Arch;

Dieses Display-RAM soll meinen aktuellen Bildschirminhalt darstellen
Jetzt habe ich mein Top Design mit dem Display-RAM und meinem 
VGA-Controller, der ein bestimmtes, gegebenes Zeichen an einer 
bestimmten Stelle auf dem Monitor ausgibt.
1
----------------------------------------------------------------------------------
2
-- Company:             www.kampis-elektroecke.de
3
-- Engineer:            Daniel Kampert
4
-- 
5
-- Create Date:         05.03.2015 13:21:32
6
-- Design Name: 
7
-- Module Name:         Top - Top_Arch
8
-- Project Name: 
9
-- Target Devices:      XC7Z010CLG400-1
10
-- Tool Versions:       Vivado 2014.4
11
-- Description: 
12
-- 
13
-- Dependencies: 
14
-- 
15
-- Revision:
16
-- Revision 0.01 - File Created
17
-- Additional Comments:
18
-- 
19
----------------------------------------------------------------------------------
20
21
library IEEE;
22
use IEEE.STD_LOGIC_1164.ALL;
23
24
-- Uncomment the following library declaration if using
25
-- arithmetic functions with Signed or Unsigned values
26
use IEEE.NUMERIC_STD.ALL;
27
28
-- Uncomment the following library declaration if instantiating
29
-- any Xilinx leaf cells in this code.
30
--library UNISIM;
31
--use UNISIM.VComponents.all;
32
33
entity Top is
34
    Port (  RGB         : out STD_LOGIC_VECTOR(15 downto 0);
35
            Input       : in STD_LOGIC_VECTOR(3 downto 0);
36
            HSync       : out STD_LOGIC;
37
            VSync       : out STD_LOGIC;
38
            Reset       : in STD_LOGIC;
39
            Clock_In    : in STD_LOGIC;    
40
            Output      : out STD_LOGIC_VECTOR(3 downto 0)
41
            );
42
end Top;
43
44
architecture Top_Arch of Top is
45
46
    signal Reset_In : std_logic;
47
    
48
    -- Clocksignale
49
    signal Clock_VGA    : std_logic;
50
    signal Clock_100    : std_logic;
51
    
52
    -- Systemsignale
53
    signal Clock_Lock : std_logic;
54
    
55
    -- Testsignale
56
    signal Display_Counter : integer := 0;
57
    signal Zaehler      : integer;
58
    signal Zeichen_RAM  : std_logic_vector(7 downto 0);
59
    signal Pixel    : integer := 39;
60
    signal Zeile    : integer := 29;
61
    signal Farbe    : std_logic_vector(15 downto 0) := x"F800";
62
    
63
    -- Erzeugung des 25,175MHz Taktes und einbinden des RAM Moduls
64
    component Clock is
65
        Port (  Clock_In    : in STD_LOGIC;
66
                Clock_Locked: out STD_LOGIC;
67
                Clock_Out   : out STD_LOGIC;
68
                Clock_Reset : in STD_LOGIC
69
                );
70
    end component Clock;
71
    
72
    component VGA is
73
        Generic (
74
                ROM_Address_Width   : integer := 11;
75
                ROM_Data_Width      : integer := 8;
76
                Char_Size           : integer := 8
77
                );
78
        Port (  Clock_VGA   : in STD_LOGIC;
79
                Reset       : in STD_LOGIC;
80
                Mode        : in STD_LOGIC; 
81
                Character   : in STD_LOGIC_VECTOR((ROM_Address_Width - 4) downto 0); 
82
                Color       : in STD_LOGIC_VECTOR(15 downto 0);
83
                Position    : in INTEGER;
84
                Zeile       : in INTEGER;
85
                HSync       : out STD_LOGIC;
86
                VSync       : out STD_LOGIC;
87
                RGB         : out STD_LOGIC_VECTOR(15 downto 0)
88
                );
89
    end component VGA;
90
    
91
    component Clock_Divider
92
        Port (  Clock_In : in  STD_LOGIC;
93
                Clock_Out : out  STD_LOGIC;
94
                Div : in  integer
95
                );
96
    end component;
97
    
98
    component Display_RAM
99
        Generic (
100
                Addr_Width : integer := 20;
101
                Data_Width : integer := 8
102
                );
103
        Port (  Clock : in STD_LOGIC;
104
                Read_Write : in STD_LOGIC;
105
                Address : in STD_LOGIC_VECTOR((Addr_Width - 1) downto 0);
106
                Data_Out : out STD_LOGIC_VECTOR ((Data_Width - 1) downto 0);
107
                Data_In : in STD_LOGIC_VECTOR ((Data_Width - 1) downto 0)
108
                );
109
    end component;
110
111
begin
112
113
    Clock_25MHz     : Clock port map (Clock_In, Clock_Lock, Clock_VGA, Reset);
114
    Clock_100Hz     : Clock_Divider port map(Clock_VGA, Clock_100, 25000000);
115
    VGA_Top         : VGA port map (Clock_VGA, Reset, '1', Zeichen_RAM, Farbe, Pixel, Zeile, HSync, VSync, RGB);
116
    Display         : Display_RAM port map (Clock_VGA, '1', std_logic_vector(to_unsigned(Pixel, 20)), Zeichen_RAM, "00000000");
117
    
118
    process(Clock_VGA)
119
    begin
120
        if rising_edge(Clock_VGA) then
121
            Zaehler <= Zaehler + 1;
122
            
123
            if(Zaehler > 7) then
124
                Zaehler <= 0;
125
                Pixel <= Pixel + 1;
126
            end if;
127
        end if;
128
    end process;
129
130
    -- Betriebsstatus
131
    Output(0) <= not Reset;
132
    Output(1) <= Clock_Lock;
133
134
end Top_Arch;

Aber ich bekomme immer einen Implementierungsfehler:

[Place 30-640] Place Check : This design requires more F7 Muxes cells 
than are available in the target device. This design requires 69904 of 
such cell types but only 8800 compatible sites are available in the 
target device. Please analyze your synthesis results and constraints to 
ensure the design is mapped to Xilinx primitives as expected. If so, 
please consider targeting a larger device.

Im Prinzip muss ich doch nur die Pixel zählen (mit jedem Clock einen 
Pixel) und bei 8 Pixeln wird eine Stelle im RAM weiter gesprungen.

Aber wo ist der Fehler?
Danke für die Hilfe!

von Duke Scarring (Gast)


Lesenswert?

Daniel K. schrieb:
> -- Target Devices:      XC7Z010CLG400-1
Wenn dies das richtige Device ist, hast Du laut Datenblatt 240 KB(yte) 
bzw. 60 BRAMs.


>             Addr_Width : integer := 20;
>             Data_Width : integer := 8
...
> type Display_RAM_Type is array (0 to (2**Address'length) - 1) of
> std_logic_vector(Data_In'range);
Hier verlangst Du vom Tool, Dir einen Speicher mit 2^20 Bytes zu 
erzeugen.
Den Rest darfst Du selber rechnen...

Duke

von Daniel K. (daniel_k80)


Lesenswert?

Ahh danke :)
Hab mal einen Blick auf die Post-Synthese geworfen und da wurde es auch 
angezeigt...konnte den Fehler halt nicht zuordnen...
Wie kann ich den dann jetzt einen Displayinhalt vernünftig anzeigen 
lassen, wenn ich kein RAM im FPGA implementieren kann?
Gibt es da eine Möglichkeit?

von Duke Scarring (Gast)


Lesenswert?

Daniel K. schrieb:
> Gibt es da eine Möglichkeit?
Ja, z.B. mit einem Zeichengenerator.
Oder man nutzt externen RAM.
Oder eine 'Funktion', die das Bild bei jedem Durchlauf neu generiert.

Duke

von peter (Gast)


Lesenswert?

SRAM von außen zuführen evtl.

Eigentlich brauchst du Screenram  4800 Byte, wo der AScii drin steht zb 
für A = 65, B = 66 usw. , alle Ramzellen (4800 Byte) füllen. Dann ein 
RAM , für 256 Zeichen sind das 8x256=2048 Byte wenn ein Zeichen 8 Byte 
hoch ist.

Mehr brauchst du nicht.
Ist merkwürdig, das dein Ding nicht soviel BRAM anlegen kann.

Gruss

von Daniel K. (daniel_k80)


Lesenswert?

peter schrieb:
> SRAM von außen zuführen evtl.
>
> Eigentlich brauchst du Screenram  4800 Byte, wo der AScii drin steht zb
> für A = 65, B = 66 usw. , alle Ramzellen (4800 Byte) füllen. Dann ein
> RAM , für 256 Zeichen sind das 8x256=2048 Byte wenn ein Zeichen 8 Byte
> hoch ist.
>
> Mehr brauchst du nicht.
> Ist merkwürdig, das dein Ding nicht soviel BRAM anlegen kann.
>
> Gruss

Ja genau so habe ich es bisher gemacht.
Ich habe mein Font-ROM da stehen die ASCII Zeichen drin (auch nach ASCII 
Tabelle). Dieses ROM ist 8x8096 groß (meine Zeichen sind 8x8 groß und 
ich habe die untersten drei Bits der Adresse vom Font-ROM für die Zeilen 
der Zeichen genommen und dann die obersten 8 Bits für die 256 Zeichen).
Wenn ich an meinem VGA-Controller nun als Zeichen die 65 angebe, so gibt 
er mir auf dem Display den Buchstaben "A" aus.

In meinem Display-RAM soll nun mein Bild stehen für ein 640x480 Monitor 
und idealerweise steht an jeder Stelle im RAM das Zeichen für 1 Zeichen 
(also ein 8x8 Feld) und diese Felder adressiere ich dann, lese das 
Zeichen aus und gib das Zeichen in den VGA-Controller, der es mir 
anzeigt.

Edit:
Mir ist gerade eingefallen....wenn ich ein 8x8 großes Zeichen habe, dann 
kann mein Bildschirm ja nur 80x60 Zeichen anzeigen.
Ich brauche also nur ein RAM, welches 80*60 groß ist mit einer Bitbreite 
von 8 (erst einmal Text only)
....Jetzt verstehe ich auch wo der Wert 4800 her kommt :/

: Bearbeitet durch User
von Daniel K. (daniel_k80)


Lesenswert?

Ok ich habe meinen Display-RAM nun implementiert bekommen und am 
Bildschirm werden jetzt auch vier Zeichen ausgegeben. Allerdings sieht 
es so aus, als ob die von unten nach oben aufgebaut werden und das immer 
abwechselnd, sprich erst Zeichen 1, dann Zeichen zwei, etc.
Wie bekomme ich das nun "schöner" hin? Ich kann ja keinen schnelleren 
Takt als die 25MHz vom VGA nehmen oder?
1
----------------------------------------------------------------------------------
2
-- Company:             www.kampis-elektroecke.de
3
-- Engineer:            Daniel Kampert
4
-- 
5
-- Create Date:         05.03.2015 13:21:32
6
-- Design Name: 
7
-- Module Name:         Top - Top_Arch
8
-- Project Name: 
9
-- Target Devices:      XC7Z010CLG400-1
10
-- Tool Versions:       Vivado 2014.4
11
-- Description: 
12
-- 
13
-- Dependencies: 
14
-- 
15
-- Revision:
16
-- Revision 0.01 - File Created
17
-- Additional Comments:
18
-- 
19
----------------------------------------------------------------------------------
20
21
library IEEE;
22
use IEEE.STD_LOGIC_1164.ALL;
23
24
-- Uncomment the following library declaration if using
25
-- arithmetic functions with Signed or Unsigned values
26
use IEEE.NUMERIC_STD.ALL;
27
28
-- Uncomment the following library declaration if instantiating
29
-- any Xilinx leaf cells in this code.
30
--library UNISIM;
31
--use UNISIM.VComponents.all;
32
33
entity Top is
34
    Port (  RGB         : out STD_LOGIC_VECTOR(15 downto 0);
35
            Input       : in STD_LOGIC_VECTOR(3 downto 0);
36
            HSync       : out STD_LOGIC;
37
            VSync       : out STD_LOGIC;
38
            Reset       : in STD_LOGIC;
39
            Clock_In    : in STD_LOGIC;    
40
            Output      : out STD_LOGIC_VECTOR(3 downto 0)
41
            );
42
end Top;
43
44
architecture Top_Arch of Top is
45
46
    signal Reset_In : std_logic;
47
    
48
    -- Clocksignale
49
    signal Clock_VGA    : std_logic;
50
    signal Clock_100    : std_logic;
51
    
52
    -- Systemsignale
53
    signal Clock_Lock : std_logic;
54
    
55
    -- Testsignale
56
    signal Display_Counter : integer := 0;
57
    signal Zaehler      : integer;
58
    signal Zeichen_RAM  : std_logic_vector(7 downto 0);
59
    signal Pixel    : integer := 0;
60
    signal Zeile    : integer := 1;
61
    signal Farbe    : std_logic_vector(15 downto 0) := x"F800";
62
    
63
    -- Erzeugung des 25,175MHz Taktes und einbinden des RAM Moduls
64
    component Clock is
65
        Port (  Clock_In    : in STD_LOGIC;
66
                Clock_Locked: out STD_LOGIC;
67
                Clock_Out   : out STD_LOGIC;
68
                Clock_Reset : in STD_LOGIC
69
                );
70
    end component Clock;
71
    
72
    component VGA is
73
        Generic (
74
                ROM_Address_Width   : integer := 11;
75
                ROM_Data_Width      : integer := 8;
76
                Char_Size           : integer := 8
77
                );
78
        Port (  Clock_VGA   : in STD_LOGIC;
79
                Reset       : in STD_LOGIC;
80
                Mode        : in STD_LOGIC; 
81
                Character   : in STD_LOGIC_VECTOR((ROM_Address_Width - 4) downto 0); 
82
                Color       : in STD_LOGIC_VECTOR(15 downto 0);
83
                Position    : in INTEGER;
84
                Zeile       : in INTEGER;
85
                HSync       : out STD_LOGIC;
86
                VSync       : out STD_LOGIC;
87
                RGB         : out STD_LOGIC_VECTOR(15 downto 0)
88
                );
89
    end component VGA;
90
    
91
    component Clock_Divider
92
        Port (  Clock_In : in  STD_LOGIC;
93
                Clock_Out : out  STD_LOGIC;
94
                Div : in  integer
95
                );
96
    end component;
97
    
98
    component Display_RAM
99
        Generic (
100
                Addr_Width : integer := 13;
101
                Data_Width : integer := 8
102
                );
103
        Port (  Clock : in STD_LOGIC;
104
                Read_Write : in STD_LOGIC;
105
                Address : in STD_LOGIC_VECTOR((Addr_Width - 1) downto 0);
106
                Data_Out : out STD_LOGIC_VECTOR ((Data_Width - 1) downto 0);
107
                Data_In : in STD_LOGIC_VECTOR ((Data_Width - 1) downto 0)
108
                );
109
    end component;
110
111
begin
112
113
    Clock_25MHz     : Clock port map (Clock_In, Clock_Lock, Clock_VGA, Reset);
114
    VGA_Top         : VGA port map (Clock_VGA, Reset, '1', Zeichen_RAM, Farbe, Pixel, Zeile, HSync, VSync, RGB);
115
    Display         : Display_RAM port map (Clock_VGA, '1', std_logic_vector(to_unsigned(Pixel, 13)), Zeichen_RAM, "00000000");
116
    
117
    process(Clock_VGA)
118
    begin
119
        if rising_edge(Clock_VGA) then
120
            Zaehler <= Zaehler + 1;
121
            
122
            if(Zaehler > 7) then
123
                Zaehler <= 0;
124
                Pixel <= Pixel + 1;
125
            end if;
126
            if(Pixel > 4) then
127
                Pixel <= 0;
128
            end if;
129
            
130
        end if;
131
    end process;
132
133
    -- Betriebsstatus
134
    Output(0) <= not Reset;
135
    Output(1) <= Clock_Lock;
136
137
end Top_Arch;

: Bearbeitet durch User
von Duke Scarring (Gast)


Lesenswert?

Da hilft Dir eine (Diagnose-)Testbench weiter, die in Deinem Fall sogar 
recht schnell erstellt ist.

Duke

von René D. (Firma: www.dossmatik.de) (dose)


Lesenswert?

Du kannst auch ander Pixelclocks wählen. Dann bist du bei anderen VGA 
Modi, die auch andere Auflösungen zulassen aber auch andere timings 
haben.

http://martin.hinner.info/vga/timing.html

von Daniel K. (daniel_k80)


Angehängte Dateien:

Lesenswert?

So ich habe den Code mal etwas umgebaut...
1
----------------------------------------------------------------------------------
2
-- Company:             www.kampis-elektroecke.de
3
-- Engineer:            Daniel Kampert
4
-- 
5
-- Create Date:         02.08.2014 13:17:51
6
-- Design Name: 
7
-- Module Name:         VGA - VGA_Arch
8
-- Project Name: 
9
-- Target Devices:      XC7Z010CLG400-1
10
-- Tool Versions:       Vivado 2014.4
11
-- Description:         VGA Interface for a 640 x 480 Pixel Screen
12
-- 
13
-- Dependencies: 
14
-- 
15
-- Revision:
16
-- Revision 0.01 - File Created
17
-- Additional Comments:
18
-- 
19
----------------------------------------------------------------------------------
20
21
library IEEE;
22
use IEEE.STD_LOGIC_1164.ALL;
23
24
-- Uncomment the following library declaration if using
25
-- arithmetic functions with Signed or Unsigned values
26
use IEEE.NUMERIC_STD.ALL;
27
28
-- Uncomment the following library declaration if instantiating
29
-- any Xilinx leaf cells in this code.
30
--library UNISIM;
31
--use UNISIM.VComponents.all;
32
33
entity VGA is
34
    Generic (
35
            Color_Width         : integer := 16;
36
            ROM_Address_Width   : integer := 11;
37
            ROM_Data_Width      : integer := 8;
38
            Char_Size           : integer := 8
39
            );
40
    Port (  Clock_VGA   : in STD_LOGIC;                                         -- Taktsignal für VGA-Logik
41
            Reset       : in STD_LOGIC;                                         -- Reset für VGA-Logik
42
            Mode        : in STD_LOGIC;                                         -- Auswahl Betriebsmodus, 0 -> Grafik, 1 -> Text
43
            Color       : in STD_LOGIC_VECTOR(15 downto 0);
44
            HSync       : out STD_LOGIC;                                        -- Ausgang für H-Sync Signal
45
            VSync       : out STD_LOGIC;                                        -- Ausgang für V-Sync Signal
46
            RGB         : out STD_LOGIC_VECTOR((Color_Width - 1) downto 0)      -- RGB Ausgang für das VGA-Signal
47
            );
48
end VGA;
49
50
architecture VGA_Arch of VGA is
51
    
52
    signal Counter: integer := 0;
53
    
54
    -- Display Cursor
55
    signal Cursor       : integer := 0;
56
    signal Position_Flag: std_logic;
57
58
    -- Koordinaten des Zeigers auf dem Bildschirm
59
    signal Pixel_x      : integer;                
60
    signal Pixel_y      : integer; 
61
    signal Zeile        : integer := 5;
62
    
63
    -- Font ROM
64
    signal ROM_Data     : std_logic_vector(0 to (ROM_Data_Width - 1));
65
    signal ROM_Address  : std_logic_vector(0 to (ROM_Address_Width - 1));
66
    signal ROM_Bit      : std_logic;
67
    signal Font_On      : std_logic;
68
    
69
    -- Display RAM
70
    signal Display_Address  : std_logic_vector(12 downto 0);
71
    signal Character        : std_logic_vector(7 downto 0); 
72
    signal Char_Counter     : std_logic_vector(10 downto 0);
73
 
74
    -- Adressierung für Zeile + Pixel 
75
    signal Row_Addr     : std_logic_vector(2 downto 0);
76
    signal Col_Addr     : std_logic_vector(2 downto 0);
77
78
    -- Einbinden des VGA-Controllers
79
    component VGA_Timing is
80
        Port (  HSync : out STD_LOGIC;
81
                VSync : out STD_LOGIC;
82
                Clock_VGA : in STD_LOGIC;
83
                Reset : in STD_LOGIC;
84
                x_out : out INTEGER;                
85
                y_out : out INTEGER 
86
                );
87
    end component VGA_Timing;  
88
    
89
    -- Font-ROM für VGA-Controller
90
    component Font_ROM is
91
        port (  ROM_Address : in STD_LOGIC_VECTOR (10 downto 0);
92
                ROM_Clock : in STD_LOGIC;
93
                ROM_DataOut : out STD_LOGIC_VECTOR (7 downto 0)
94
                );
95
    end component Font_ROM;
96
    
97
    -- Display RAM für das VGA Bild    
98
    component Display_RAM
99
        Generic (
100
                Addr_Width : integer := 13;
101
                Data_Width : integer := 8
102
                );
103
        Port (  Clock : in STD_LOGIC;
104
                Read_Write : in STD_LOGIC;
105
                Address : in STD_LOGIC_VECTOR((Addr_Width - 1) downto 0);
106
                Data_Out : out STD_LOGIC_VECTOR ((Data_Width - 1) downto 0);
107
                Data_In : in STD_LOGIC_VECTOR ((Data_Width - 1) downto 0)
108
                );
109
    end component;
110
111
begin
112
113
    VGA_Ctrl        : VGA_Timing port map (HSync, VSync, Clock_VGA, Reset, Pixel_x, Pixel_y);   
114
    Char_Font       : Font_ROM port map (ROM_Address, Clock_VGA, ROM_Data);
115
    Display         : Display_RAM port map (Clock_VGA, '1', "0000000000001", Character, "00000000");
116
117
    -- ROM auslesen
118
    Row_Addr    <= std_logic_vector(to_unsigned(Pixel_y, Row_Addr'length));
119
    ROM_Address <= Character & Row_Addr;
120
    Col_Addr    <= std_logic_vector(to_unsigned(Pixel_x, Col_Addr'length));
121
    ROM_Bit     <= ROM_Data(to_integer(unsigned(Col_Addr)));     
122
123
    Position_Flag <= '1' when ((Pixel_x >= Cursor) and (Pixel_x < (Cursor + Char_Size)) and (Pixel_y >= (8 * Zeile)) and (Pixel_y < (8 * Zeile) + Char_Size)) else '0';
124
125
    -- Display RAM auslesen
126
    --Display_Address <= "000" & std_logic_vector(to_unsigned((Pixel_x mod 8), 10));
127
128
    -- Farbausgabe
129
    process(Reset, Clock_VGA)
130
    begin
131
        if(rising_edge(Clock_VGA)) then
132
            if(Reset = '0') then
133
                RGB <= x"0000";
134
            else
135
                if(Pixel_x mod 8 = 7) then
136
                    Cursor <= Cursor + 1;
137
                end if;
138
                
139
                if(Cursor = 79) then
140
                    Cursor <= 0;
141
                end if;
142
            
143
                if((Position_Flag = '1') and (ROM_Bit = '1')) then
144
                    RGB <= Color;
145
                else
146
                    RGB <= x"0000";
147
                end if;
148
            end if;
149
        end if;
150
    end process;
151
  
152
end VGA_Arch;

Ich versuche nun das zweite Zeichen aus dem Display RAM auszulesen und 
dieses Zeichen auf der kompletten Displayreihe darzustellen (das ist ein 
A). Das Auslesen klappt schon mal und auch die Darstellung klappt mehr 
oder weniger gut (siehe Foto).
Leider flackern die Buchstaben noch recht stark und sind schwer zu 
erkennen...
Ich habe den Code auch mal simuliert und alle 8 Pixel wird der Cursor um 
eins hoch gezählt und dort soll dann der neue Buchstabe gezeichnet 
werden.
Leider klappt das nicht ganz so wunderbar....
Woran könnte das liegen?

: Bearbeitet durch User
von Duke Scarring (Gast)


Lesenswert?

Ich würde mich erstmal auf die Sync-Signale konzentrieren.
Lt. Deiner Simulation ist HSYNC = '1' und VSYNC = 'U'. Das macht mich 
stutzig...

Duke

von Daniel K. (daniel_k80)


Angehängte Dateien:

Lesenswert?

Hallo Duke,

ja aber nur die ersten paar Mikrosekunden. :) (im Anhang ist noch mal 
eine längere Simulation) - vielleicht wäre es besser dem Signal noch 
einen Startwert von '1' zu geben?.
Ich habe meinen Code noch mal etwas überarbeitet, nachdem ich von 
funkheld mal ein lauffähiges Beispiel bekommen habe, welches ich 
erfolgreich auf mein Board portieren konnte.
Ich habe nun für die x- und y-Koordinaten einen Typ "unsigned" 
genommen...laut Internet soll der Typ ohnehin besser zum Rechnen sein 
(?).
1
entity VGA is
2
    Generic (
3
            Color_Width         : integer := 16;
4
            ROM_Address_Width   : integer := 11;
5
            ROM_Data_Width      : integer := 8;
6
            Char_Size           : integer := 8
7
            );
8
    Port (  Clock_VGA   : in STD_LOGIC; 
9
            Reset       : in STD_LOGIC; 
10
            Mode        : in STD_LOGIC;
11
            Color       : in STD_LOGIC_VECTOR(15 downto 0);
12
            HSync       : out STD_LOGIC; 
13
            VSync       : out STD_LOGIC;
14
            RGB         : out STD_LOGIC_VECTOR((Color_Width - 1) downto 0) 
15
            );
16
end VGA;
17
18
architecture VGA_Arch of VGA is
19
20
    signal Pixel_x      : unsigned(9 downto 0);               
21
    signal Pixel_y      : unsigned(9 downto 0); 
22
    
23
    signal ROM_Data     : std_logic_vector(0 to (ROM_Data_Width - 1));
24
    signal ROM_Address  : std_logic_vector(0 to (ROM_Address_Width - 1));
25
    signal ROM_Bit      : std_logic;
26
    signal Row_Addr     : std_logic_vector(2 downto 0);
27
    signal Col_Addr     : std_logic_vector(2 downto 0);
28
       
29
    signal Display_Address  : unsigned(12 downto 0);
30
    signal Zeichen_Address  : unsigned(6 downto 0);
31
    signal Reihen_Address   : unsigned(5 downto 0);
32
    signal Character        : std_logic_vector(7 downto 0); 
33
34
    component VGA_Timing is
35
        Port (  HSync : out STD_LOGIC;
36
                VSync : out STD_LOGIC;
37
                Clock_VGA : in STD_LOGIC;
38
                Reset : in STD_LOGIC;
39
                x_out : out UNSIGNED(9 downto 0);                
40
                y_out : out UNSIGNED(9 downto 0) 
41
                );
42
    end component VGA_Timing;  
43
    
44
    component Font_ROM is
45
        port (  ROM_Address : in STD_LOGIC_VECTOR (10 downto 0);
46
                ROM_Clock : in STD_LOGIC;
47
                ROM_DataOut : out STD_LOGIC_VECTOR (7 downto 0)
48
                );
49
    end component Font_ROM;
50
      
51
    component Display_RAM
52
        Generic (
53
                Addr_Width : integer := 13;
54
                Data_Width : integer := 8
55
                );
56
        Port (  Clock : in STD_LOGIC;
57
                Read_Write : in STD_LOGIC;
58
                Address : in STD_LOGIC_VECTOR((Addr_Width - 1) downto 0);
59
                Data_Out : out STD_LOGIC_VECTOR ((Data_Width - 1) downto 0);
60
                Data_In : in STD_LOGIC_VECTOR ((Data_Width - 1) downto 0)
61
                );
62
    end component;
63
64
begin
65
66
    VGA_Ctrl        : VGA_Timing port map (HSync, VSync, Clock_VGA, Reset, Pixel_x, Pixel_y);   
67
    Char_Font       : Font_ROM port map (ROM_Address, Clock_VGA, ROM_Data);
68
    Display         : Display_RAM port map (Clock_VGA, '1', "0000000000010", Character, "00000000");
69
70
    Row_Addr    <= std_logic_vector(Pixel_y(2 downto 0));
71
    ROM_Address <= Character & Row_Addr;
72
    Col_Addr    <= std_logic_vector(Pixel_x(2 downto 0));
73
    ROM_Bit     <= ROM_Data(to_integer(unsigned(Col_Addr)));     
74
75
    Zeichen_Address <= Pixel_x(9 downto 3);
76
    Reihen_Address <= Pixel_y(8 downto 3);
77
        
78
    RGB <= Color when (ROM_Bit = '1') else x"0000";
79
80
end VGA_Arch;

Das oben gezeigte Beispiel gibt nun lauter "L" auf dem Bildschirm aus 
(da nutze ich noch die feste Adresse 0000000000010 um das dritte Zeichen 
im Displayspeicher auszulesen).

Jetzt habe ich aber ein Problem mit dem automatischen Auslesen des 
Displayspeichers.
Wenn ich nun statt "0000000000010" das Signal ""000000" & 
std_logic_vector(Zeichen_Address)" einsetze, bekomme ich das auf dem 
zweiten Foto gezeigte Phänomen, obwohl der komplette Displayspeicher 
leer ist (bis auf das zweite Zeichen, was immer noch ein "L" ist).
Wenn ich die Adressierung der Zeilen weg lasse müsste ich doch in jeder 
Zeile an der zweiten Stelle ein "L" stehen haben, da ja der Zähler 
"Zeichen_Address" jede Zeile von neuem anfängt zu zählen.
Aber anscheinend habe ich da noch einen Versatz drin und ich habe keine 
Idee wo der her kommt (in der Simulation ist das auch zu erkennen).

Vielleicht hat ja jemand eine Idee woher das kommen könnte :)
In der Zwischenzeit suche ich schon mal weiter :o

: Bearbeitet durch User
von Sigi (Gast)


Lesenswert?

Das ist ein typischer Latenzfehler: Du liest das Zeichen
aus einem Speicher (BlockRAM?) und dann das Zeichenpixel
aus einen Anderen (ebenfalls BlockRAM?).

Für das Zeichenpixel werden aber noch X- und Y-Koordinate
verwendet. Durch das Zeichen-RAM hst du jetzt eine Latenz
zu den Koordinaten. Aufheben kannst Du das, indem die
X- und Y-Koordinate (d.h. je 3 Bits) einmal (oder evtl.
mehrmals) pipelinest. Das "hebt" die Latenz auf.

von Daniel K. (daniel_k80)


Angehängte Dateien:

Lesenswert?

So neues update :)
Das Timing-Problem ist nun behoben....ich habe die x und y Koordinaten 
einmal durch nen Clock verzögert und dann war es weg (danke für den 
Tipp).
Bin auch schon fast am Ziel...ich habe jetzt mal das Wort "Hallo" 17x in 
das Display-RAM geschrieben (17*5 Zeichen = 85 Zeichen = 1 komplette 
Zeile + 1 Wort), aber das letzte "o" wird nicht angezeigt (dafür am 
Anfang ein "H" mehr), in der zweiten Zeile wird kein "Hallo" angezeigt 
und unten am Bildschirm habe ich weiße Punkte (siehe Screenshot).

Die Sourcen habe ich mal angehängt, da das sonst zu lang wird wenn ich 
diese immer poste...
Ich habe auch mal mein VGA Timing an das hier angepasst:

http://www.ece.unm.edu/~jimp/vhdl_fpgas/slides/VGA.pdf

Als Startpunkt für den Zähler habe ich jeweils die steigende Flanke vom 
Sync genommen, sprich in x-Richtung 48 Pixel, dann 640 sichtbare, dann 
16 nicht sichtbare und dann der Sync für 96 Pixel.
Analog bin ich beim V-Sync vorgegangen. Eventuell steckt da ja der 
Fehler?

: Bearbeitet durch User
von peter (Gast)


Lesenswert?

Hallo, das sieht ja gut aus.
Warum hast du VGA_Timing 2x drin?

Kannst du die VHD Font-Rom auch mal reinsetzen. Dann könnte man es mal 
als ganzes Testen.

Danke.

GRuss

von peter (Gast)


Lesenswert?

Wenn der Text nicht stimmt, musst du hier ein bisschen mit rumspielen.
Kann sein das der Monitor zu pingelig ist.

Gruss

WholeLine : integer     := 800;
VisibleArea_H : integer := 640;
BackPorch_H : integer   := 40;
SyncPulse_H : integer   := 96;

von peter (Gast)


Lesenswert?

-- Description:         Display-RAM for VGA-Core
--                      (640x480, Charsize 8x8 -> 80x40 Chars per 
Screen)

Hmmm..., bei Charsize 8x8 hast du 80x60 Chars....
Dann nimm Cahrrsize 8x16...

GRuss

von Daniel K. (daniel_k80)


Angehängte Dateien:

Lesenswert?

Hallo,

peter schrieb:
> Hallo, das sieht ja gut aus.
> Warum hast du VGA_Timing 2x drin?
>
> Kannst du die VHD Font-Rom auch mal reinsetzen. Dann könnte man es mal
> als ganzes Testen.
>
> Danke.
>
> GRuss

mist...ich hatte da noch was an der Datei geändert...dachte er hätte die 
vorhandene Datei überschrieben.
Ich habe es im Anhang noch mal komplett als ZIP-Datei hochgeladen.

Zu dem 80x40...da habe ich mich verschrieben :)
Es ist alles für 80x60 Zeichen ausgelegt.
Ich probiere in der Zeit mal etwas weiter :)

von Daniel K. (daniel_k80)


Lesenswert?

Daniel K. schrieb:
> Hallo,
>
> peter schrieb:
>> Hallo, das sieht ja gut aus.
>> Warum hast du VGA_Timing 2x drin?
>>
>> Kannst du die VHD Font-Rom auch mal reinsetzen. Dann könnte man es mal
>> als ganzes Testen.
>>
>> Danke.
>>
>> GRuss
>
> mist...ich hatte da noch was an der Datei geändert...dachte er hätte die
> vorhandene Datei überschrieben.
> Ich habe es im Anhang noch mal komplett als ZIP-Datei hochgeladen.
>
> Zu dem 80x40...da habe ich mich verschrieben :)
> Es ist alles für 80x60 Zeichen ausgelegt.
> Ich probiere in der Zeit mal etwas weiter :)

HA ein Problem habe ich schon mal gelöst :)
Im VGA-Timing musste
1
if((Pixel_Counter > (BackPorch_H + LeftBorder_H - 1)) and (Pixel_Counter < (VisibleArea_H + BackPorch_H + LeftBorder_H - 1))) then

durch
1
if((Pixel_Counter > (BackPorch_H - 1)) and (Pixel_Counter < (VisibleArea_H + BackPorch_H + LeftBorder_H - 1))) then

ersetzt werden.
Jetzt habe 16x "Hallo" in einer Zeile stehen. Fehlt nur noch das 17. 
"Hallo" in der zweiten Zeile

von peter (Gast)


Lesenswert?

Hallo, warum hastdu hier noch color drin:
Color       : in STD_LOGIC_VECTOR(15 downto 0);
Da steht doch schon RGB?

Wofür ist das?

Danke.
Gruss

 Port (  Clock_VGA   : in STD_LOGIC; 
-- Taktsignal für VGA-Logik
            Reset       : in STD_LOGIC; 
-- Reset für VGA-Logik
            Mode        : in STD_LOGIC; 
-- Auswahl Betriebsmodus, 0 -> Grafik, 1 -> Text
            Color       : in STD_LOGIC_VECTOR(15 downto 0);
            HSync       : out STD_LOGIC; 
-- Ausgang für H-Sync Signal
            VSync       : out STD_LOGIC; 
-- Ausgang für V-Sync Signal
            RGB         : out STD_LOGIC_VECTOR((Color_Width - 1) downto 
0)      -- RGB Ausgang für das VGA-Signal
            );

von Daniel K. (daniel_k80)


Lesenswert?

Hallo,

das ist quasi die Farbe die ich in dem Top_Design übergebe. RGB ist der 
Ausgang der auf den DAC geht und über Color sage ich welche Farbe er auf 
den DAC gibt.
Das kommt aber noch raus, wenn der Text + RAM läuft landet die Farbe mit 
im RAM und dann hole ich mir die da her.
Im Moment ist das einfach nur zum ausprobieren :)

von Sigi (Gast)


Lesenswert?

Daniel K. schrieb:
> Das Timing-Problem ist nun behoben....ich habe die x und y Koordinaten
> einmal durch nen Clock verzögert und dann war es weg

So wie ich das auf die Schnelle sehe, hast Du die X-/Y-Koordinaten
gepipelined, aber nicht die ROW-/COL-Koordinaten wie von mir
vorgeschlagen (ROW bzw. COL werden aus Pixel_x/Pixel_y generiert).
Du hast also eine weitere Latenz drin.

Und: Du müsstest für exaktes Timing auch HSYNC/VSYNC zweimal
verzögern, denn dein Zeichenpixel kommt zwei Takte später an.

Mach Dir am Besten dazu ein einfachen Datengraph, bei dem jeder
Kante die Anzahl Verzögerungen zugeordnet werden. Dann muss in
jeden Knoten alle einlaufenden Pfade die selbe Gesamtzahl an
Verzögerungen aufweisen, ansonsten muss gepipelined werden.

Kleine Nebenbemerkung: Dein Font-RAM hat 8 Bits für Datenausgang,
ändere das doch auf ein Bit um, dann ist die Ansteuerung evtl.
einfacher.

von Daniel K. (daniel_k80)


Lesenswert?

Hallo Sigi,

mmh ok dann hatte ich dich falsch verstanden. Ich habe es nun mal 
testweise so gemacht:
1
    process(Clock_VGA)
2
    begin
3
        if(rising_edge(Clock_VGA)) then
4
            Row_Addr_Delay <= std_logic_vector(Pixel_y(2 downto 0));
5
            Col_Addr_Delay <= std_logic_vector(Pixel_x(2 downto 0));   
6
        end if;
7
    end process;

Aber das hat die ganze Sache nur verschlimmert, wodurch der Text gar 
nicht mehr lesbar war :(
Das mit dem Datengraph verstehe ich nicht so ganz. Hast du da vielleicht 
mal ein Beispiel für mich, wo ich sehe wie du das meinst?

von Sigi (Gast)


Lesenswert?

Also wenn der Text überhaupt nichtmehr lesbar ist, dann sind
noch ein paar grössere Hauer drin.

Aber zum Graph bzw. zur Analyse (Ann.: Pixel-ROM liefert nur
ein Bit zurück), Ansätze bzw. Interpretationen gibt es so
viele wie Lehr/Leerbücher:
Ein Zustand sei eine Menge von Signalwerten, ein Übergang/Kante
sei die Verarbeitung inkl. Speicherung(en) und Weitergabe an den
nächsten Zustand (dann ist ein einfache Register eine Kante mit
Verzögerung 1, die Eingabe-/Ausgabe-Werte die Zustände).

Bei Dir besteht dann auf VGA_top-Ebene der Startzustand S1 aus
HSync, VSync, Pixel_x, Pixel_y. Das Auslesen des Zeichens
ist dann eine Kante zum nächsten Zustand S2 (Zeichen-Code), mit
D1 Latenz. Von da dann eine Kante für das Auslesen des
Font-Pixels (D2 latenz) nach S3 mit Font-Pixel. Jetzt hast Du
aber noch eine Kante von S1 nach S3, denn Pixel_x und Pixel_y
werden als ROW und COL für dein Font-ROM verwendet.

Jetzt gilt für Pixel:
  S1->S2->S3 hat D1+D2 Delay
  S1->S3 hat D1 Delay,
d.h. für dein Zeichen-Pixel werden Signalwerte von t-D1-D2
als auch von t-D1 verwendet, also müssen ROW und COL und D2
verzögert werden. Für HSync und VSync hast du 0 Latenz, d.h
beide Signale müssen um D1+D2 verzögert werden.

Für Dein Problem bzw. Design ist das natürlich übertrieben,
ein erfahrener Designer eine trivale Geschichte.
Wenn Du aber mehr als 10 Komponenten mit unterschiedlichsten
Delays hast, dann kommst Du um eine formalere Beschreibung
nicht rum.

nur als komplexeres Beispiel: Ich habe eine komplette
Graphikanwendung mit Text, Graphik, Overlay, Windows und
verschiedensten Algos wie Linie, Dreieck, Z/W-Buffer etc. mit
den unterschiedlichsten Verzögerungen. Ohne einen solchen
Ansatz wäre das nur noch ein wildes Basteln, und das für jede
beliebige Konfiguration (ich habe bestimmt schon >= 50 Stück).

Versuch Dir also die Abläufe bzw. Delays klarzumachen und
entsprechend zu korigieren.

von Daniel K. (daniel_k80)


Lesenswert?

Hallo Sigi,

danke für die ausführliche Erklärung :)
Das Verfahren wird mir aber leider noch nicht so recht deutlich. Hat 
dieses Verfahren einen speziellen Namen, welchen ich mal googlen könnte?
Dann kann ich mir ein bisschen dazu durchlesen :)
In der Zwischenzeit lasse ich das erstmal so "unsauber" und konzentriere 
mich darauf die Zeilenproblematik zu lösen (habe da gestern im Simulator 
schon die Ursache gefunden und muss nun nur noch eine Lösung 
erarbeiten).

Wenn das Ding dann so funktioniert werde ich die Timings schön machen. 
Habe gestern nämlich gemerkt, dass das Bild bei einem anderen Monitor 
etwas verschoben ist und so das erste "H" nur halb dargestellt wird.

von peter (Gast)


Lesenswert?

Das verschieben der Zeilen kann von Monitor zu Monitor verschieden sein.
Da musst du an deinen Timingschrauben drehen.

Mit deinem Clock verschlimmert es sich noch wenn du später dein VGA 
erweitern möchtest, PS2-Tastatur , Grafikausgabe und RS232 
(Datenübertragung vom PC)

Ich habe nur 80x30 Auflösung mit funktionierender PS2 Tastatur. Wenn ich 
mein ROM auf 2400 Zeichen erweitere (19200 Byte , geht noch mit dem DE0) 
dann kann ich sogar ein Bild ins ROM ablegen und die Screenbelegung wird 
einfach immer von 0-2400 hochgezählt statt einen bestimmten Text 
auszugeben.

Weiterhin habe ich es mal übertrieben und noch RS232-RX eingebaut und 
kann jetzt auch ein Grafikbild mit 640X240 übertragen vom PC aus zum ROM 
und es wird sauber dargestelt. Die Grafik-Bytes werden als 
Ascii-Zeichen(8 byte 1 Zeichen) übertragen.

GRuss.

von Sigi (Gast)


Lesenswert?

Hallo Daniel,

Daniel K. schrieb:
> Hat
> dieses Verfahren einen speziellen Namen, welchen ich mal googlen könnte?
> Dann kann ich mir ein bisschen dazu durchlesen :)

Dafür gibt's keine Namen, jeder Dozent hat da seine eigene/mehrere
Notationen. Und ein Buch bzw. Artikel kann ich Dir leider auch nicht
nennen.

Aber vlt. wird's ja einfacher, wenn man das Ganze auf der Zeitachse
betrachtet. Voraussetung für folgendes Beispiel ist, das FONT- als
auch CHAR-RAM jeweils 1 Takt brauchen und das FONT-RAM einen Pixel
zurückliefert:

-------------------------------------------------------------
time         :  .. t0 t1 t2 t3 t4 t5 t6 t7 t8 t9 .. .. .. ..
-------------------------------------------------------------
sync:
  hsync  out :  .. h0 h1 h2 h3 h4 h5 h6 h7 h8 h9 .. .. .. ..
  vsync  out :  .. v0 v1 v2 v3 v4 v5 v6 v7 v8 v9 .. .. .. ..

pos:
  x      out :  .. x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 .. .. .. ..
  y      out :  .. y0 y1 y2 y3 y4 y5 y6 y7 y8 y9 .. .. .. ..
-------------------------------------------------------------
delay1:
  x      in  :  .. x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 .. .. .. ..
  y      in  :  .. y0 y1 y2 y3 y4 y5 y6 y7 y8 y9 .. .. .. ..
  x1     out :  .. .. r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 .. .. ..
  y1     out :  .. .. s0 s1 s2 s3 s4 s5 s6 s7 s8 s9 .. .. ..

delay2:
  x      in  :  .. x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 .. .. .. ..
  y      in  :  .. y0 y1 y2 y3 y4 y5 y6 y7 y8 y9 .. .. .. ..
  x2     out :  .. .. .. t0 t1 t2 t3 t4 t5 t6 t7 t8 t9 .. ..
  y2     out :  .. .. .. u0 u1 u2 u3 u4 u5 u6 u7 u8 u9 .. ..

delay3:
  hsync  in  :  .. h0 h1 h2 h3 h4 h5 h6 h7 h8 h9 .. .. .. ..
  vsync  in  :  .. v0 v1 v2 v3 v4 v5 v6 v7 v8 v9 .. .. .. ..
  hsync3 out :  .. .. .. .. i0 i1 i2 i3 i4 i5 i6 i7 i8 i9 ..
  vsync3 out :  .. .. .. .. j0 j1 j2 j3 j4 j5 j6 j7 j8 j9 ..
-------------------------------------------------------------
char ram:
  x      in  :  .. x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 .. .. .. ..
  y      in  :  .. y0 y1 y2 y3 y4 y5 y6 y7 y8 y9 .. .. .. ..
  ascii  out :  .. .. a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 .. .. ..

font ram (error):
  x      in  :  .. x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 .. .. .. ..
  y      in  :  .. y0 y1 y2 y3 y4 y5 y6 y7 y8 y9 .. .. .. ..
  ascii  in  :  .. .. a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 .. .. ..
  pixel  out :  .. .. .. p0 p1 p2 p3 p4 p5 p6 p7 p8 p9 .. ..

font ram (ok):
  x1     in  :  .. .. r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 .. .. ..
  y1     in  :  .. .. s0 s1 s2 s3 s4 s5 s6 s7 s8 s9 .. .. ..
  ascii  in  :  .. .. a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 .. .. ..
  pix_ok out :  .. .. .. q0 q1 q2 q3 q4 q5 q6 q7 q8 q9 .. ..
-------------------------------------------------------------
vga_sync (error):
  hsync  in  :  .. h0 h1 h2 h3 h4 h5 h6 h7 h8 h9 .. .. .. ..
  vsync  in  :  .. v0 v1 v2 v3 v4 v5 v6 v7 v8 v9 .. .. .. ..
  hsync  out :  .. h0 h1 h2 h3 h4 h5 h6 h7 h8 h9 .. .. .. ..
  vsync  out :  .. v0 v1 v2 v3 v4 v5 v6 v7 v8 v9 .. .. .. ..

vga_color (error):
  x      in  :  .. x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 .. .. .. ..
  y      in  :  .. y0 y1 y2 y3 y4 y5 y6 y7 y8 y9 .. .. .. ..
  pixel  in  :  .. .. .. p0 p1 p2 p3 p4 p5 p6 p7 p8 p9 .. ..
  color  out :  .. .. .. .. c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ..

vga(error)   :
  hsync  out :  .. h0 h1 h2 h3 h4 h5 h6 h7 h8 h9 .. .. .. ..
  vsync  out :  .. v0 v1 v2 v3 v4 v5 v6 v7 v8 v9 .. .. .. ..
  color  out :  .. .. .. .. c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ..

vga_sync (ok):
  hsync3 in  :  .. .. .. .. i0 i1 i2 i3 i4 i5 i6 i7 i8 i9 ..
  vsync3 in  :  .. .. .. .. j0 j1 j2 j3 j4 j5 j6 j7 j8 j9 ..
  hsync3 out :  .. .. .. .. i0 i1 i2 i3 i4 i5 i6 i7 i8 i9 ..
  vsync3 out :  .. .. .. .. j0 j1 j2 j3 j4 j5 j6 j7 j8 j9 ..

vga_color (ok):
  x2     in  :  .. .. .. t0 t1 t2 t3 t4 t5 t6 t7 t8 t9 .. ..
  y2     in  :  .. .. .. u0 u1 u2 u3 u4 u5 u6 u7 u8 u9 .. ..
  pix_ok in  :  .. .. .. q0 q1 q2 q3 q4 q5 q6 q7 q8 q9 .. ..
  color  out :  .. .. .. .. c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ..

vga (ok):
  hsync3 out :  .. .. .. .. i0 i1 i2 i3 i4 i5 i6 i7 i8 i9 ..
  vsync3 out :  .. .. .. .. j0 j1 j2 j3 j4 j5 j6 j7 j8 j9 ..
  color  out :  .. .. .. .. c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ..
-------------------------------------------------------------

Alle Signalwerte bekommen einen Zeitstempel, der beim Verarbeiten
bzw. Auslesen aus RAM/ROM auf den nächsten Wert übertragen wird.
Ausserdem müssen alle Eingangsignale eines Verarbeitungsschritts
den selben Zeitstempel tragen! SEHR WICHTIG!!
<sync> und <pos> werden bei Dir durch VGA_timing generiert,
die Zeitstempel setze ich gleich den Zeitpunkten.
<delay1> bis <delay3> verzögern <pos>- und <sync>-Signale.
Und jetzt wird es interessant. Wärend <char ram> noch korrekt
arbeitet (a0 wird aus x0,y0 ein Takt später generiert), ist bei
<font ram (error)> ein Fehler. Denn p0 wird aus a0,x1,y1 bestimmt,
müsste aber aus a0,x0,y0 bestimmt sein! Und das setzt sich bei
der Ausgabe von <vga (error)> fort. Hier wird c0,h3,v3 zu einem
Zeitpunkt ausgegeben, es müsste aber c0,h0,v0 sein.
Bei mein <font ram (ok)> dageben wird q0 aus a0,r0,s0 bestimmt
(r,s sind verzögerte h,v!), ebenso wird von <vga (ok)> c0,i0,j0
als Color/HSync/VSync ausgegeben, d.h. alle Signale haben die
korrekten Zeitstempel.

Ich habe jetzt kein Vivado installiert, nur ISE, weiss also nicht,
wie deine BRAMs konfiguriert sind, d.h. meine Verzögerungen müssten
entsprechend angepasst werden.

Mach Dir einfach den Ablauf klar, sollte relativ einfach sein,
ist in etwa wie penibel Buchführung bzw. in der Autoproduktion
die Hochzeitszerimonie. Es ist nicht wie bei Software, wo eine
Funktion Werte zurückliefert und dann "wartet", bis sie wieder
aufgerufen wird. In Hardware werden IMMER Werte produziert, deshalb
ist nicht nur der Wert, sondern auch der Zeitstempel wichtig.

Und noch eine kleine Nebenbemerkung: Speicher Color/HSync/VSync
noch in Register bevor sie an die Pins gegeben werden, dann
werden alle 3 Signale etwa Zeitgleich und glitchfrei an Dein
TFT übertragen.

von Daniel K. (daniel_k80)


Lesenswert?

Hallo,

danke für die Ausführliche Erklärung. Ich schaue mal ob ich das so 
verstanden habe...
Ich nehme mein VGA-Timing als Basis, da dort zu jedem Clockzeitpunkt 
(die Zeiten t0 - tn) eine x und eine y Koordinate erzeugt werden.

Warum wird dann aber der H- und V-Sync mitgezogen? Der wird doch erst 
nach x-Takten ausgelöst?

Die Punkte delay 1-3 verzögern die entsprechenden Signale einfach um 1-3 
Zyklen. Die werden dann später gebraucht um aus dem RAMs die richtigen 
Daten zu holen.
Da die RAMs geclockt sind, kommen die Daten immer einen Taktzyklus 
später. Die Signale, welche als Vektoren genutzt werden, werden dabei 
als einzelnes Bit dargestellt. Bei meinem Font-RAM müssen dem 
entsprechen die Vektoren für Zeile 0 und Spalte 0, sowie das 
entsprechende Zeichen bei den Koordinaten (also meine erste Stelle aus 
dem Display-RAM) eingegeben werden. Einen Clockzyklus später kommt dann 
meine entsprechende Pixelzeile (also Pixel 7-0) aus dem RAM.
Da dieses Pixel dann aber jetzt schon mehrere Zyklen zu spät kommt 
(bedingt durch die RAMs) muss ich die entsprechenden Koordinaten für 
dieses Pixel so lange verzögern bis ich wieder ein Signal erhalte, was 
zeitgleich mit dem entsprechenden Pixel läuft (in dem Beispiel wäre es 
eine Verzögerung von 2 für die Koordinaten).
Und mit diesen verzögerten x-y Koordinaten erzeuge ich dann meine 
Synchronisationssignale, die auch noch durch einen Takt verzögert 
werden, damit sie mit der Farbe überein stimmen (aber wofür sind dann 
h0.... und v0...? Bei den Syncs komme ich noch etwas durcheinander).

Ist das so korrekt?
Wenn ja, dann mache ich das mal für mein Design neu und schaue ob ich es 
hin bekomme und danach versuche ich das mal umzusetzen.
Ist zwar wahrscheinlich bissl Overhead für sowas "simples" wie VGA, aber 
so lerne ich das wahrscheinlich am besten :)

von Sigi (Gast)


Lesenswert?

Hi,

so wie ich das auf die Schnelle sehe, hast Du es fast korrekt
wiedergegeben. Nur die Verzögerung der HSync-/VSync arbeitet
anders: Dein VGA_Timing generiert schon HSync und VSync, es
wird später nicht noch einmal generiert/berechnet, sondern nur
verzögert. Die Verzögerung ist wieder so eine Korrektheitsgeschichte.
Denn wenn Du Dein Design änderst (andere BRAMs mit mehr Latenz,
dann änder sich auch die Bildlage (Bild schiebt sich nach Rechts),
und genau das verhinderst Du mit einer flexiblen Verzögerung der
Sync-Signale. Du änderst also nur Dein Design, sondern passt die
Pipelines an die neue Latenz an und erhältst an immer der selben
Stelle auf dem TFT dein Bild.

Und ob Dein RAM jetzt getacktet ist oder nicht, spielt auch keine
Rolle. Nimm mal an, die RAMs sind ungetacktetes SRAM, dann erzeugt
Dein Design einen irre langen kombinatorischen Pfad (>>30-40 ns),
zwar mit den "zeitkorrekten" Werten, aber für höhere Auflösungen
viel zu langsam.

Dir scheint das jetzt als zu kompliziert für so eine "einfache"
Geschichte wie VGA-Textausgabe, aber bei vielen Designs kommt
es immer wieder vor, dass mehrerte Komponenten mit unterschiedlichen
Latenzen Signale liefern, die wieder in Phase gebracht werden
müssen, z.B. durch Pipelining.

Und für ein Neudesign: Nenn VGA_timing in VGA_CoreController um,
der erzeugt für eine vielzahl von neuen VGA-Controller (z.B.
Textausgabe, Graphikausgabe, einfache Farbbalken, SDRAM-Ansteuerung
etc.) die Basis-Signale (X-Pos,Y-Pos,H-Sync,V-Sync). Diese Signale
werden dann durch weitere Komponenten in die Farbsignale und die
verzögerten Sync-Signale transformiert, und zwar so, dass Dein
Bild immer konstant an einer exakten Stelle auf dem TFT erscheint.

P.S.: ich habe noch mal nach der Bezeichnung für obige Automaten
gesucht. Die werden z.B. auch gewertete/bewertete Automaten
genannt. E-Tech hat Schnittstellen zum MachBau und zur InfTech.
Da gibt's ähnliche Ansätze/Modelle. Die sind aber oft viel zu
kompliziert für so ein einfaches Problem, ich hab versucht, es
einfacher zu machen.

von Daniel K. (daniel_k80)


Lesenswert?

Ok wunderbar :)
Jetzt nur noch eine theoretische Frage...
Solche Analysen über Delays etc. werden wann im Design Flow gemacht?
Ich denke mal die macht man dann während der Entwicklung des Designs 
oder, da man vor der Entwicklung des Designs, also quasi bei der 
Überlegung was das Design können muss, ja nicht genau weiß was sich wie 
verzögert (außer man hat RAMs etc. wo man weiß das die ein Delay 
verursachen).

von Daniel K. (daniel_k80)


Angehängte Dateien:

Lesenswert?

Hallo,

ich bin gerade dabei mir die Simulation mit Hilfe deiner Tabelle genauer 
anzusehen und mittlerweile wird das doch schon recht deutlich wo die 
Probleme stecken :)
Ich habe mir auch noch mal im Vivado den Block-Memory angeschaut (siehe 
Screenshot).
Der hat anscheinend zwei Clocks als Delay...mal schauen ob ich das noch 
bisschen gedrückt bekomme.

von Daniel K. (daniel_k80)


Angehängte Dateien:

Lesenswert?

Daniel K. schrieb:
> Hallo,
>
> ich bin gerade dabei mir die Simulation mit Hilfe deiner Tabelle genauer
> anzusehen und mittlerweile wird das doch schon recht deutlich wo die
> Probleme stecken :)
> Ich habe mir auch noch mal im Vivado den Block-Memory angeschaut (siehe
> Screenshot).
> Der hat anscheinend zwei Clocks als Delay...mal schauen ob ich das noch
> bisschen gedrückt bekomme.

Hallo,

so anhand deiner Vorlage habe ich mir mal einen Ablauf erstellt (dort 
sind auch die zwei Zyklen Block Memory Latenz mit drin)....siehe Anhang 
(ist eine Textdatei).
Zudem habe ich mal versucht das ganze dann im Code einzubauen (siehe 
ebenfalls Anhang).
Aktuell habe ich auf dem Bildschirm noch Pixelfehler drin (ich gebe erst 
einmal wieder eine Zeile aus dem RAM auf der kompletten Bildschirmhöhe 
aus)...ich bin da noch am suchen aber vielleicht kannst du dir das ja 
schon mal anschauen, damit ich weiß ob ich damit richtig liege :)

: Bearbeitet durch User
von Daniel K. (daniel_k80)


Lesenswert?

So hab den Fehler doch schon gefunden :D
Ich hatte das hier stehen:
1
Row_Addr    <= std_logic_vector(Pixel_y_delay_1(2 downto 0));
2
ROM_Address <= Character & Row_Addr;
3
Col_Addr    <= std_logic_vector(Pixel_x_delay_1(2 downto 0));
4
ROM_Bit     <= ROM_Data(to_integer(unsigned(Col_Addr)));

Ich muss aber das zweite Delay nehmen:
1
Row_Addr    <= std_logic_vector(Pixel_y_delay_2(2 downto 0));
2
ROM_Address <= Character & Row_Addr;
3
Col_Addr    <= std_logic_vector(Pixel_x_delay_2(2 downto 0));
4
ROM_Bit     <= ROM_Data(to_integer(unsigned(Col_Addr)));

Und schon wird der Text schön angezeigt (sieht sogar besser aus als 
vorher...) :)
Wunderbar....noch ein paar mal mit dieser "Buchführung" arbeiten und 
dann sollte das sicher funktionieren.
Jetzt kann ich mich darauf konzentrieren die Sache rund zu machen etc. 
:)

Btw:
Gibt es eine Möglichkeit die ganzen Signale, die ich zum Verzögern 
verwende, schöner darzustellen bzw. zusammenzufassen?

: Bearbeitet durch User
von Daniel K. (daniel_k80)


Angehängte Dateien:

Lesenswert?

Heyho,

noch mal ein kurzes Update :)
Habe gestern noch etwas am Timing-Controller rum gearbeitet, da der 
Zeilenwechsel nicht geklappt hat....der hat mehrfach einen Offset von 80 
drauf gehauen, was daran lag, dass ich geschaut habe wann x(2 downto 0) 
= 0 war und diese Bedingung war über mehrere Taktzyklen aktuell...
Daher habe ich es jetzt so gemacht, dass der Counter pro Takt von 0-639 
zählt und dann bei 640 stehen bleibt und 640 quasi der "Reset"-Wert 
ist...
Jetzt klappt auch der Zeilenwechsel (siehe Fotos).

Ich habe nur noch am ersten Zeichen ein Pixel was zuviel ist (unter dem 
"H")...da muss ich noch schauen woher das kommt...ich denke aber mal das 
kommt vom Timing, da durch die getaktete Adresserzeugung ist alles 
wieder um einen Takt verschoben, aber das ist schnell behoben :)

Ich habe mal den Code ebenfalls hochgeladen, falls jemand Interesse hat!
Der nächste Schritt wird (neben der Behebung des Pixelfehlers) das 
einbringen von Farbiinformationen + Beschreiben des Display-RAMs und 
korrigieren der ASCII-Tabelle im Font-ROM sein.....aber es nimmt schon 
Formen an :)

: Bearbeitet durch User
von Daniel K. (daniel_k80)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

so ich habe das Display-RAM jetzt auch als BRAM ausgelegt, da ich 
ansonsten bei 51% Auslastung für Memory Lut gekommen wäre....
Bis auf einen kleinen Pixelfehler beim ersten Zeichen...aber da finde 
ich den Fehler nicht :( ...  mal schauen...
Ich habe jetzt mal einen Zähler aufgebaut, der einen festen Text aus dem 
Initialisierungsfile für das Display-RAM ausgibt und einen veränderbaren 
Text (einen Zähler) der ins Display-RAM geschrieben und danach angezeigt 
wird.

Ich lade es mal hoch, falls es sich jemand anschauen möchte.
Im Großen und Ganzen ist das Thema VGA damit für mich abgeschlossen 
(Grafikausgabe lasse ich erst einmal weg :) ).

Danke nochmal an alle beteiligten für eure Hilfe, wodurch ich ein ganzes 
Stück weiter gekommen bin!

von Sigi (Gast)


Lesenswert?

So, nach der Zeichen-/Font-RAM-Latenz-Problematik kann's ja weiter
gehen. Dein Problem ist jetzt, dass Du die Zeichen-Addresse korrekt
(bzw. Wert/Latenz) bestimmen musst. "VGA-Timing" liefert x/y-Pos,
aus den unteren 3 Bits wird das Pixel, aus den Bits 3..n-1 die
Zeichenaddresse. Und dass impliziert wieder Latenz.

Es gibt zwei einfache Möglichkeiten:
1. Je Zeile Wird ein Zähler, startend mit Offset, inkrementiert.
   Nach 8 Zeilen wird dann der Offset um z.B. 40 inkrementiert
   etc.
2. Du bestimmst aus den höheren Bits die Addresse direkt:
   2.1.: per einfacher Multiplikation (Verschwendung einer MULT-Unit)
   2.2.: bei z.B. 40 kann 40 in 32+8 zerlegt werden, d.h. die Mult
         kann durch 2 ADD ersetzt werden. Damit hat man nach
         2 Taktzyklen die Zeichenaddresse.

Also hast du 3 Aufgaben:
1. Zeichenaddresse bestimmen (1-2 Takte)
2. Zeichen lesen (1-2 Takte)
3. Font-Pixel lesen (1-2 Takte)
Plus jeweils x-/y-Pos-Pipelining.

Für 1. werden Bits 3..n benötigt, für 3. Bits 0..2, d.h. nur die
ersten 3 Bits der x-/y-Pos werden für's Pipelining benötigt. Gibt
also im Extremfall 6*2*3 Bits zum Speichern (HSync/VSync exkl.).

von peter (Gast)


Lesenswert?

Hallo, kannst du nur mal bitte die benötigten VHDL zum compilieren 
reinstellen?

danke.

Gruss

von Daniel K. (daniel_k80)


Lesenswert?

Hallo Peter,

ist alles in dem ZIP-File.
Unter VGA.srcs\sources_1\imports\new sind die beiden VHDL Files für den 
VGA.
Das Font-ROM und das Display-RAM ist als Block Memory ausgelegt. Da habe 
ich keine VHDL Files für, da ich das mit dem IP-Designer gemacht habe.
Unter VGA\VGA.srcs\constrs_1\new ist das entsprechende XDC-File für die 
IO Belegung.

von peter (Gast)


Lesenswert?

Jup, danke.

Gruss

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.