Forum: FPGA, VHDL & Co. Led Matrix - Verbesserung/Tip/Rat zu Design


von kleiens Licht (Gast)


Lesenswert?

Ich arbeite mich langsam weiter in vhdl ein.
Mein momentanes Ziel ist Pong auf einem VGA Monitor - da ist der Weg 
noch weit.
Um weiter Erfahrung zu sammeln, habe ich vor eine 4x4 ledmatrix zu löten 
und dort Muster zeitgerecht drauf auszugeben. Die ist noch nicht fertig, 
somit wird erst simuliert.
Das Design unten sieht auch gut aus, ABER eine Frage habe ich. -daß- 
Variablen für Einsteiger Probleme darstellen habe ich des öfteren 
gelesen. Daß sie besser vermieden werden sollen auch, aber wie würde ich 
mein Mini Design angehen, damit ich in den steig komplexeren Designs 
(wenn das überhaupt geht) Fallen vermeide?
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.NUMERIC_STD.ALL;
4
5
6
entity leddisp is
7
   Generic(clkdelay : integer := 2);
8
    Port ( clk : in  STD_LOGIC;
9
           a : out  STD_LOGIC_VECTOR(3 downto 0);
10
           k : out  STD_LOGIC_VECTOR(3 downto 0));
11
end leddisp;
12
13
architecture Behavioral of leddisp is
14
signal ai : STD_LOGIC_VECTOR(3 downto 0) := "0111";
15
signal ki : STD_LOGIC_VECTOR(3 downto 0) := "1000";
16
signal clkcnt : integer range 0 to clkdelay := 0;
17
signal state : integer range 0 to 3 := 0;
18
begin
19
20
main_proc : process(clk) 
21
variable cnt : integer range 0 to 3 := 0;
22
begin
23
  if( rising_edge(clk) ) then
24
    if(clkcnt < clkdelay) then
25
      clkcnt <= clkcnt + 1;
26
    else
27
      clkcnt <= 0;  
28
      cnt := cnt + 1;
29
      
30
      case state is
31
        when 0 => ai <= ai(0)&ai(3 downto 1); if(cnt=3)then state<=1; cnt := 0; end if;
32
        when 1 => ki <= ki(0)&ki(3 downto 1); if(cnt=3)then state<=2; cnt := 0; end if;
33
        when 2 => ai <= ai(2 downto 0)&ai(3); if(cnt=3)then state<=3; cnt := 0; end if;
34
        when 3 => ki <= ki(2 downto 0)&ki(3); if(cnt=3)then state<=0; cnt := 0; end if;
35
      end case;
36
    
37
    end if;
38
  end if;
39
end process main_proc;
40
41
a <= ai;
42
k <= ki;
43
44
end Behavioral;

Ich mache das allein zu Hause, kein Team, keine Kollegen kein Mentor - 
mit meinen Problemen wäre ich allein, würde sie folglich ohne externes 
Wissen auch nciht klären können und daher bin ich sehr um Prävention 
bemüht....

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


Lesenswert?

kleiens Licht schrieb:
> Ich arbeite mich langsam weiter in vhdl ein.
Du brauchst keine Variable cnt. Warum nimmst du sie trotzdem?

> Das Design unten sieht auch gut aus
Das kann nichts kompliziertes machen, aber ich kapiere das nicht auf 
Anhieb. Und damit sieht es für mich nicht GUT aus... :-/
Nur weil alles in einer Zeile steht, wird es nicht besser.

> aber wie würde ich mein Mini Design angehen
Du solltest diese Vorteiler (clkcnt + cnt) aus der FSM herausnehmen und 
in einem eigenen Prozess nur ein Clock-Enable Flag erzeugen.

Du kannst unsigned Vektoren verwenden und die rotate_left() bzw. 
rotate_right() Funktionen aus der numeric_std.

Benenne deine Zustände nicht einfach mit Zahlen durch, sondern gib ihnen 
lesbare Namen.

Du solltest nicht jeden Zähler einfach cnt oder clkcnt bennnen. Denn 
was soll ein Zähler anderes zählen als Takte?

Einrückungen machen den Quelltext überschaubar. Das sieht aber soweit 
schon gut aus.

Schreib in einem Kommentar, was das Modul machen soll bzw. macht. Und 
auch, wo es Probleme gibt oder gegeben hat. Das hilft dir selber als 
Gedankenstütze.

von kleiens Licht (Gast)


Lesenswert?

Ja stimmt, wenn man nicht dazu sagt, was beabsichtigt ist, kommt es 
etwas kryptisch daher.
Der Plan war als erste Übung die äußeren Leds rundlaufen zu lassen. Ein 
2d Lauflicht sozusagen.
Die Variablen benötige ich nicht. So weit versprochen - was tun? Wenn 
ich am Ende der Zeilen angekommen bin, zieht das dann eine 
Richtungsänderung nach sich, also anoden 8 mal schieben, dann wert nicht 
mehr ändern, kathoden 8 mal schieben, dann Anoden wieder zurück usw.
Die Anoden steuern pnp Transistoren und die Kathoden npn Transistoren 
darum wird eine 0 bzw 1 für die aktive Reihe durchgeschoben.
Also ich werde heute Abend versuchen, 2 Prozesse zu schreiben miteinbem 
der nur Takt teilt und einem der Zählschritte macht. Mir wäre aber an 
einer Art Bausatz-Wissen gelegen, um in Zukunft die Probleme 
kontrolliert in bekannte Teile zu zerlegen. Ich hoffe ihr, speziell 
Lothar, versteht was ich meine... Den weisen Professor ersetzen ;-)

In diesem Fall könnte ich mir vielleicht vorstellen nur einen Prozess 
zur Taktteilung und einen fürs schieben... denn wenn ich statt der 
Variable ein Signal nehme, bin ich ins schwimmen gekommen, wie oft denn 
nun zählen wegen des resultierenden Versatzes.
Außerdem habe ich unglücklicherweise das Buch zum nexys1200 Board und 
dort wird extrem viel mit Variablen gearbeitet - andere Punkte beißen 
sich z.B. auch mit den z.B. von Lothar stoisch genannten Punkten. Da 
muss ich ziemlich lange probieren, um die Beispiele umzusetzen. Und 
scheiter doch oft wegen einem Brett vorm Kopf.
Dennoch ist das Buch sehr schön, denn praktische Beispiele, wie 
Algorithmen umgesetzt werden, schnittstellen oder Ram sind rar gesäht.

von kleiens Licht (Gast)


Lesenswert?

"Du solltest diese Vorteiler (clkcnt + cnt) aus der FSM herausnehmen und
in einem eigenen Prozess nur ein Clock-Enable Flag erzeugen.

Du kannst unsigned Vektoren verwenden und die rotate_left() bzw.
rotate_right() Funktionen aus der numeric_std.
"

also diesen rat für mich oben zusammengefasst - werde ich also in 
Angriff nehmen.

von kleiens Licht (Gast)


Lesenswert?

Der dritte Post in Folge.... mit der Bitte um Entschuldigung.

Nun voll Tatendrang zu Hause angekommen und grandios gescheitert. Ich 
rudere GANZ weit an den Anfang denn folgendes wird durch ein "parse 
error, unexpected IDENTIFIER, expecting SEMICOLON" quittiert.
Ich komme einer Überarbeitung meines codes also nicht wirklich näher.

1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.NUMERIC_STD.ALL;
4
5
entity led_matrix is
6
    Port ( spalten :out STD_LOGIC_VECTOR(7 downto 0));
7
end led_matrix;
8
9
architecture Behavioral of led_matrix is
10
signal spalten_s : unsigned (7 downto 0) := "01111111";
11
begin
12
  
13
spalten <= (STD_LOGIC_VECTOR)spalten_s;
14
15
end Behavioral;



P.S. Wenn ich meine Hausaufgaben erledigt habe, überlege ich dann ob ich 
das Ergebnis poste. Hilft sicher anderen Anfängern auch weiter. Und 
hoffentlich wäre das dann cniht mein 4. post in Folge

von kleiens Licht (Gast)


Lesenswert?

1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.NUMERIC_STD.ALL;
4
5
entity led_matrix is
6
   Generic(TAKT_SHIFT : integer := 2);
7
    Port ( spalte : out STD_LOGIC_VECTOR(7 downto 0);
8
        zeile : out STD_LOGIC_VECTOR(7 downto 0);
9
        clk   : in STD_LOGIC);
10
end led_matrix;
11
12
architecture Behavioral of led_matrix is
13
signal spalte_s : unsigned (7 downto 0) := "01111111";
14
signal zeile_s  : unsigned (7 downto 0) := "10000000";
15
-- Takterzeugung
16
signal shift_clk : integer range 0 to TAKT_SHIFT := 0;
17
signal shift_en  : bit := '0';
18
--Zustände
19
signal geshiftet : integer range 0 to 7 := 0;
20
type states is(ZEILE_UNTEN, SPALTE_RECHTS, ZEILE_OBEN, SPALTE_LINKS);
21
signal state : states := ZEILE_UNTEN;
22
begin
23
24
clk_enable:process(clk) begin
25
  if( rising_edge(clk) ) then
26
    if( shift_clk < TAKT_SHIFT ) then
27
      shift_clk <= shift_clk + 1;
28
      shift_en <= '0';
29
    else
30
      shift_clk <= 0;
31
      shift_en <= '1';
32
      if(geshiftet < 7) then        --ich zähle die shift operationen mit und ändere alle 8 mal den Zustand
33
        geshiftet <= geshiftet + 1; --warum es nicht funktioniert, z.B. in zeile_s das unterste bit anzugucken
34
      else                   --und wenn dieses 0 wird in SPALTE_RECHTS zu gehen weiß ich noch nicht
35
        geshiftet <= 0;
36
      end if;
37
    end if;
38
  end if;
39
  end process clk_enable;
40
41
leds_shiften : process(clk, shift_en) begin
42
  if(rising_edge(clk) and shift_en = '1') then
43
    case state is
44
      when ZEILE_UNTEN => zeile_s <= rotate_right(zeile_s, 1);
45
                    --if(zeile_s(0)='0') then
46
                    if(geshiftet = 7) then
47
                      state <= SPALTE_RECHTS;
48
                    end if;
49
      when SPALTE_RECHTS => spalte_s <= rotate_right(spalte_s, 1);
50
                    --if(spalte_s(0)='1') then
51
                    if(geshiftet = 7) then
52
                      state <= ZEILE_OBEN;
53
                    end if;
54
      when ZEILE_OBEN    => zeile_s <= rotate_left(zeile_s, 1);
55
                    --if(zeile_s(7)='0') then
56
                    if(geshiftet = 7) then
57
                      state <= SPALTE_LINKS;
58
                    end if;
59
      when SPALTE_LINKS  => spalte_s <=  rotate_left(spalte_s, 1);
60
                    --if(spalte_s(7)='0') then
61
                    if(geshiftet = 7) then
62
                      state <= ZEILE_UNTEN;
63
                    end if;
64
    end case;
65
  end if;
66
  end process leds_shiften;
67
68
69
zeile  <= STD_LOGIC_VECTOR(zeile_s);
70
spalte <= STD_LOGIC_VECTOR(spalte_s);
71
72
end Behavioral;

Ich habe versucht die Anregungen umzusetzen. Wie ihr am Code seht, bin 
ich  noch nicht rundum zufrieden, aber ich probiere weiter.
Vielen, vielen Dank an Lothar ich habe mich in diesem Thread wirklich 
nciht gerade empfohlen und werde mich jetzt erst mal in ein ganz tiefes 
Loch verkriechen :-(

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


Lesenswert?

kleiens Licht schrieb:
> Ich habe versucht die Anregungen umzusetzen.
Na bitte: geht doch...
Und jetzt das Ganze hübsch simulieren... ;-)
Dann wirst du das auch noch herausfinden:
>> warum es nicht funktioniert, z.B. in zeile_s das unterste bit anzugucken
>> und wenn dieses 0 wird in SPALTE_RECHTS zu gehen weiß ich noch nicht
Als Tipp: das hat sicher was mit der Latency und dem shift_en zu tun...

kleiens Licht schrieb:
> leds_shiften : process(clk, shift_en) begin
>   if(rising_edge(clk) and shift_en = '1') then
Schreib das besser wie "der Rest der Welt":
1
leds_shiften : process(clk) begin -- nur der Takt in der Sensitivliste, dann sieht jeder: voll synchron das Ding
2
  if rising_edge(clk) then
3
     if (shift_en = '1') then ...

von kleiens Licht (Gast)


Lesenswert?

Ich habe das Design nun lauffähig bekommen. Nicht umständlich Schritte 
zu zählen ist doch definitiv schöner: einmal intuitiver und auch 
Ressourcensparender. Ich habe nur ein cpld vor mir liegen.
Die ordentlichere Variante hat zwar ungefähr 4 mal so lange wie das 
hingefetzte gedauert, aber das wird der lerneffekt hoffenltich 
mittelfristig wieder wett machen.

Dank noch einmal, aber ich habe es soeben auch mit gemischten Gefühlen 
gestartet. Einmal froh, daß es nun klappt. (Stichwort Latenz ich leite 
den Zustandswechsl nun einfach eine Shiftposition vor Endposition ein) 
aber auch mit einem schalen Gefühl, weil es mir eben (noch?) nicht 
gelingt, dieses Problem zu 100% zu durchschauen.
Das kann ja nicht die Praxis sein einfach mal aus Gefühl früher oder 
später etwas zu erledigen, weil sich da sicher irgendwas beim Ablauf 
beißt...

von Boris (Gast)


Lesenswert?

Hallo "kleines Licht",

zeig doch mal deinen Code! Dann kann man dir vielleicht noch den ein 
oder anderen Tip geben, bzw. oder dir sagen warum es klappt.

>Das kann ja nicht die Praxis sein einfach mal aus Gefühl früher oder
>später etwas zu erledigen, weil sich da sicher irgendwas beim Ablauf
>beißt...

Da hast du Recht, dass ist nicht die Praxis... Aber als "Anfänger" (so 
wie ich bestimmt auch noch einer bin) macht man hin und wieder 
Denkfehler. Das bleicbt nicht aus.

PS: Weißt du wie dein CPLD intern Aufgebaut ist? Wenn nicht gebe ich dir 
den Tip das heraus zu finden. So kannst du Ressourcen sparen in dem du 
synthesefreundlichen VHDL Code schreibst. Auch das RTL-Schematic, 
welches du dir mit der ISE anschauen kannst sagt dir ob du das bekommst 
was du in VHDL umschrieben hast...

Gruß Boris

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


Lesenswert?

kleiens Licht schrieb:
> Ich habe das Design nun lauffähig bekommen.
Zeig doch mal deinen Code, um die Sache hier abzurunden... ;-)

> Das kann ja nicht die Praxis sein einfach mal aus Gefühl früher oder
> später etwas zu erledigen
Du wist das einfach verinnerlichen, dann ist das kein Gefühl mehr... ;-)

von kleiens Licht (Gast)


Lesenswert?

sehr gern obwohl so 98% das Selbe ;-)
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.NUMERIC_STD.ALL;
4
5
entity led_matrix is
6
   Generic(TAKT_SHIFT : integer := (2**17)-1);
7
    Port ( spalte : out STD_LOGIC_VECTOR(7 downto 0);
8
        zeile : out STD_LOGIC_VECTOR(7 downto 0);
9
        clk   : in STD_LOGIC);
10
end led_matrix;
11
12
architecture Behavioral of led_matrix is
13
signal spalte_s : unsigned (7 downto 0) := "01111111";
14
signal zeile_s  : unsigned (7 downto 0) := "10000000";
15
-- Takterzeugung
16
signal shift_clk : integer range 0 to TAKT_SHIFT := 0;
17
signal shift_en  : bit := '0';
18
--Zustände
19
type states is(ZEILE_UNTEN, SPALTE_RECHTS, ZEILE_OBEN, SPALTE_LINKS);
20
signal state : states := ZEILE_UNTEN;
21
begin
22
23
clk_enable:process(clk) begin
24
  if( rising_edge(clk) ) then
25
    if( shift_clk < TAKT_SHIFT ) then
26
      shift_clk <= shift_clk + 1;
27
      shift_en <= '0';
28
    else
29
      shift_clk <= 0;
30
      shift_en <= '1';
31
    end if;
32
  end if;
33
  end process clk_enable;
34
35
leds_shiften : process(clk, shift_en) begin
36
  if(rising_edge(clk) and shift_en = '1') then
37
    case state is
38
      when ZEILE_UNTEN => zeile_s <= rotate_right(zeile_s, 1);
39
                    if(zeile_s(1)='1') then
40
                      state <= SPALTE_RECHTS;
41
                    end if;
42
      when SPALTE_RECHTS => spalte_s <= rotate_right(spalte_s, 1);
43
                    if(spalte_s(1)='0') then
44
                      state <= ZEILE_OBEN;
45
                    end if;
46
      when ZEILE_OBEN    => zeile_s <= rotate_left(zeile_s, 1);
47
                    if(zeile_s(6)='1') then
48
                      state <= SPALTE_LINKS;
49
                    end if;
50
      when SPALTE_LINKS  => spalte_s <=  rotate_left(spalte_s, 1);
51
                    if(spalte_s(6)='0') then
52
                      state <= ZEILE_UNTEN;
53
                    end if;
54
    end case;
55
  end if;
56
  end process leds_shiften;
57
58
59
zeile  <= STD_LOGIC_VECTOR( zeile_s);
60
spalte <= STD_LOGIC_VECTOR( spalte_s);
61
62
end Behavioral;

P.S. Der Buchstabendreher ist nicht -ganz- unbeabsichtigt, aber dennoch 
nett gemeinter Hinweis.

P.P.S sehr gute Hilfe auch für Trottel wie mich, da muss ich mich 
anmelden

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


Lesenswert?

Du bekommst das "gefühlte" Verhalten weg, wenn du quasi einen 
"voreilenden Gehorsam" in jeden State einbaust:
1
      when ZEILE_UNTEN => 
2
                    if(zeile_s(0)='1') then
3
                      state    <= SPALTE_RECHTS;
4
                      spalte_s <= rotate_right(spalte_s, 1);
5
                    else
6
                      zeile_s  <= rotate_right(zeile_s, 1);
7
                    end if;
8
      when SPALTE_RECHTS => 
9
                    if(spalte_s(0)='0') then
10
                      state    <= ZEILE_OBEN;
11
                      zeile_s  <= rotate_left(zeile_s, 1);
12
                    else 
13
                      spalte_s <= rotate_right(spalte_s, 1);
14
                    end if;
15
      when ZEILE_OBEN    => 
16
                    if(zeile_s(7)='1') then
17
                      state    <= SPALTE_LINKS;
18
                      spalte_s <=  rotate_left(spalte_s, 1);
19
                    else
20
                      zeile_s  <= rotate_left(zeile_s, 1);
21
                    end if;
Aber da gefällt mir deine Version eigentlich besser.

Eine andere wesentlich elegantere Möglichkeit wäre, den gesamten Prozess 
mit voller Geschwindigkeit laufen zu lassen und mit dem shift_en nicht 
den gesamten Prozess zu beeinflussen, sondern nur das Schieben (denn 
daher hat shift_en ja auch den Namen):
1
leds_shiften : process(clk, shift_en) begin
2
  if rising_edge(clk) then
3
    case state is
4
      when ZEILE_UNTEN => 
5
                    if (shift_en = '1') 
6
                      zeile_s <= rotate_right(zeile_s, 1);
7
                    end if;
8
                    if (zeile_s(0)='1') then
9
                      state <= SPALTE_RECHTS;
10
                    end if;
11
      when SPALTE_RECHTS => 
12
                    if (shift_en = '1') 
13
                      spalte_s <= rotate_right(spalte_s, 1);
14
                    end if;
15
                    if (spalte_s(0)='0') then
16
                      state <= ZEILE_OBEN;
17
                    end if;
18
      when ZEILE_OBEN    => 
19
                    if (shift_en = '1') 
20
                      zeile_s <= rotate_left(zeile_s, 1);
21
                    end if;
22
                    if (zeile_s(7)='1') then
23
                      state <= SPALTE_LINKS;
24
                    end if;
25
      when SPALTE_LINKS  => 
26
                    if (shift_en = '1') 
27
                      spalte_s <=  rotate_left(spalte_s, 1);
28
                    end if;
29
                    if (spalte_s(7)='0') then
30
                      state <= ZEILE_UNTEN;
31
                    end if;
32
    end case;
33
  end if;
34
  end process leds_shiften;
Ich würde das so machen, und das deckt sich auch eher mit deiner 
Denkweise. Und mit ein wenig Übung wird auch aus einem kleien Licht ein 
Großes...  ;-)

von kleiens Licht (Gast)


Lesenswert?

Bei deiner letzten Lösung verschiebt sich der Zustandswechsel dann aber 
auch einen Takt hinter das shiften auf bit 0, oder?
Macht nur nichts, weil die shift_en Signale ohnehin mehrere Takte 
auseinander liegen.
Ich frage nur, um etwas mehr Verständnis reinzubekommen. Es könnte ja 
auch sein, daß nicht ein so derart runtergeteilter Takt für Aktionen 
genutzt wird, sondern z.B. eben ein Takt was ausmacht.

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


Lesenswert?

kleiens Licht schrieb:
> Bei deiner letzten Lösung verschiebt sich der Zustandswechsel dann aber
> auch einen Takt hinter das shiften auf bit 0, oder?
Ja.

> Macht nur nichts, weil die shift_en Signale ohnehin mehrere Takte
> auseinander liegen.
Sehr viele sogar...  ;-)
Mindestens 1 wäre aber wirklich nötig.

> eben ein Takt was ausmacht.
Klar: das muss man sich dabei im Hinterkopf behalten.

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.