Forum: FPGA, VHDL & Co. VHDL Integer Counter


von Hagen (Gast)


Lesenswert?

Hi Leute,

wenn ich in VHDL einen Counter mit

  signal Counter: integer range 0 to 115;

definiere und diesen nun im VHDL mit

  if Clock'Event and Clock = '1' then
    Counter <= Counter + 1;
  end if;

inkrementiere, bei welchem Wert läuft der Zähler über ?

Bei 115 +1 auf 0 oder erst bei 255 +1 = 0 weil ja dieser Counter mit 8
FF's realisiert werden muß.

Gruß Hagen

von Henrik (Gast)


Lesenswert?

Soweit ich weiß, müsste der counter den Wert 115 noch annehmen und dann
erst auf 0 gehen. Der range-Befehl müsste sich nicht nur auf die Anzahl
der FF's auswirken, sondern auch auf die Übergangslogik im Zähler
(vermute ich mal). Wenn nicht, so sollte beim Compilieren zumindest
eine Warnung kommen.

Gruß Henrik

von Hagen (Gast)


Lesenswert?

Fehler kommt nicht, und logisch wäre ein Überlauf beim Maximum der
Range. Allerdings die Zähler selber können nur bis 2^Anzhal FF -1
zählen, also immer eine Potenz von 2 an Schritten. Sogesehen müsste der
Fitter das berücksichtigen und einen Comparator nachschalten.
Nungut, meine Frage war nur um mir Zeit zu sparen, ich werden es ja eh
noch verifizieren müssen. Bis jetzt weis ich nur das die Anzahl der
benötigten Makrozellen sich nicht verändert hat, egal ob man im VHDL
den Zähler explizit per Comparator zurücksetzt oder bei Range
beschränkt. Schon mal ein gutes Zeichen und ich bin happy das sich hier
das VHDL/Fitter wenigsten logisch verhält.

Wenn ich es verifiziert habe melde ich mich nochmal.

Gruß Hagen

von Stefan (Gast)


Lesenswert?

Hallo,
ich bin relativ neu im umgang mit Programmierbaren logikbausteinen,
daher kann es gut sein das das was ich schreib nicht recht zu der
Fragestellung passt. Ich kann leider kein VHDL, ich nehme bis jetzt den
leichten weg über Schaltplaneingabe. Aber wenn man einen Zähler von
0-115 braucht, so benötigt man doch nur 7 FFs, und somit eine
Makrozelle weniger. Das rücksetzen würde ich per Festverdrahteter Logik
bei 116 machen, bzw zusammen mit dem Ausdekodierten Signal bei
Zählerstand 115 über ein AND mit dem Takt auf den Rücksetzeingang der
FFs.

mfg
Stefan

von Hagen (Gast)


Lesenswert?

Das ist schon richtig was du sagst.

In VHDL sähe es eben so aus

 signal XYZ: integer range 0 to 115;

Thats all, und wäre das was du im Schematic machen würdest.

Die Frage war/ist nun folgende:
So ein Integer benötigt immer 7 FF's, logisch es gibt keine 1/2 FF's
oder so. Somit geht der Wertebereich hardwaretechnisch immer von 0 bis
127 = 2^7-1, auch logisch.
Generiert nun das VHDL für obige Deklaration automatisch einen
Comparator der beim Inkrementieren überprüft ob Werte > 115 erreicht
wurden und setzt den Zähler auf XYZ = XYZ mod 116, zurück.

Normalerweise (händisch) würde es in VHDL so aussehen:

  signal XZY: integer range 0 to 127;

  XZY <= XYZ +x;
  if XYZ >= 116 then
    XZY <= XYZ - 116;
  end if;

Übrigens, empfinde ich die Programmierung in VHDL wesentlich einfacher
als die Schematas.

Gruß Hagen

von Henrik (Gast)


Angehängte Dateien:

Lesenswert?

@Stefan: "Das rücksetzen würde ich per Festverdrahteter Logik bei 116
machen" wieso? Das ist doch nur ein kleiner Eingriff in die interne
Tabelle für den nächsten Zustand. Das extern zu machen kostet eine
Macrozelle mehr.

@Hagen: Beide Möglichkeiten brauchen 7 Macrozellen (=>Anhang). Meine
bevorzugte Variante ist zwar länger aber wie ich meine auch besser zu
verstehen. Du solltest den Speicher für den Wert(Counter) nicht als
Signal deklarieren, sondern als variable, wenn du kurz darauf auf ihn
zugreifst.
Bsp:
Signal A integer ...;
...
(Annahme: A=5)
Process...
begin
...
A<=A+1;
if (A=6) then ... (wird nicht ausgeführt, da A erst am Prozessende
aktualisiert wird!)
end if;
end Process...

Das ist zwar in erster Linie ein Problem der Simulation, man sollte es
aber trotzdem vermeiden.

Gruß Henrik

von Hagen (Gast)


Lesenswert?

Ob Variable oder Signal war für meine Frage erstmal unwichtig :) Klar in
meinem konkreten Fall MUSS es ein Signal sein, einfach weil es per
externem Takt inkrementiert werden soll. Es sei denn ich hätte da eine
Lücke in meinem VHDL Wissen und man kann Variablen (nicht shared
Variablen) global im behavioral benutzen und per externem Clock
inkrementieren ??

Gruß Hagen

von Max Müller (Gast)


Lesenswert?

Geht doch einfach mal von einem SImulator wie Modelsim aus.
Da würdest du einen Fehler bekommen, da wenn der Zählerstand 115 ist
beim nächsten Inkrement 116 nicht mehr im Range deines Subtypes ist.

Die besten Erfahrungen hab ich mit folgender Beschreibung.

if(rising_edge(clk)) then
   if(counter < 115) then
      counter <= counter +1;
   else
      counter <= 0;
   end if;
end if;

Dann stimmt das ganze beim Simulieren und wird auch richtig
syntetisiert.

Gruß

Max

von Henrik (Gast)


Lesenswert?

Das kannst du!(Über einen kleinen Umweg) In dem Prozess in meinem Code
steht: "output<=counter;".
Es ist egal, ob output ein Ausgang der Entity oder ein internes Signal
ist. Damit ist der Wert des Zählers überall (im Behavorial) verfügbar.
Natürlich ist das auch ein wenig umständlicher, aber es vereinfacht das
Nachvollziehen des Codes, wenn man sicher sein kann, dass man ein Signal
immer wie eine Leiterbahn ansehen kann.
Bei diesem Problem kann man es am besten wie Max mit einer einfachen
if-Schleife machen. Wenn die Anforderungen anden Zähler aber wachsen
und man z.B. einen ladbaren Up-Down-BCD-Zähler mit Set und Reset haben
will,
hat man irgendwann soviele if-Schleifen, dass es vielleicht den
beliebten "bad decription error" gibt. Dann ist das Problem sehr
einfach mit einer case-Anweisung zu lösen (Das Thema hatten wir hier
kürzlich sogar 2 mal).

Gruß Henrik

von Hagen (Gast)


Angehängte Dateien:

Lesenswert?

Hi Henrik,

ok anbei mal mein akademisches Testprojekt. Im speziellen ging es mir
um HCounter und VCounter des VHDL's.
Ich wüsste jetzt nicht wie man diese in Variablen statt Signale
umwandeln könnte, zumindestens meckert Xilinx's WEBPack wenn ich dies
versuche. Aus "Sicherheitsgründen" habe ich mich nun doch für normale
std_logic_vector für die Zähler entschieden.

Achso, nicht lachen über den Source, ich bin noch am üben :=)

Gruß Hagen

von Henrik (Gast)


Angehängte Dateien:

Lesenswert?

Warum sollte ich lachen? "ich bin noch am üben :=)" da sind wir ja
schon zu zweit.

Habe nur minimale Änderungen vorgenommen. Die Zähler laufen jetzt über
Variablen. Als ich VCount als Variable mit der Breite 7Bit (Vorgabe)
initialisierte und am Ende mit VCounter verband, kam beim Compilieren
eine seltsame Warnung, die vorher nicht kam: "VCountER assigned, but
never used!". Das habe ich überprüft und es stimmte nicht. VCounter
wurde benutzt! Dann bemerkte ich, dass die 7Bit Variable mit einem Wert
von 506 verglichen wurde (wozu man ja mindestens 9 Bit braucht!). Als
ich daraufhin die Variable und das Signal auf 9 Bit erweiterte
verschwand diese Meldung wieder. Scheint ein kleiner Fehler im Webpack
zu sein, dass hier die falsche Warnung erscheint.

Gruß Henrik

von Hagen (Gast)


Lesenswert?

Nee diese "Warnung" ansich war schon gut den es war ja schließlich
definitiv ein Programmfehler. Ich habe auch lange überlegt was der
"Fehler" bedeutete und schlußendlich meinen Fehler so gefunden.

Das man Variablen so innerhalb eines Prozesse benutzen kann war mir
schon klar.

"-- das ist NICHT wie bei C-Variablen, wo diese nach dem verlassen der
Schleife gelöscht würden!"

Das aber die "lokale" Variable eines Prozesses ihren "Zustand"
Prozessübergreifend speichern kann aber nicht. Danke für diese Info,
das werde ich nochmal verifizieren. Denn schlußendlich würde das ja
bedeuten das ich die komplette Logik des HCounter/VCounter in einen
eigenen Prozess packen könnte und so die externen Signal
wegrationalisieren kann. Allerdings ganz so sicher bin ich mir da noch
nicht, ich hatte die VHDL Dokus anders interpretiert (aus Sicht eines
Programmieres auf PC's)

Gruß Hagen

von Henrik (Gast)


Lesenswert?

"Das aber die "lokale" Variable eines Prozesses ihren "Zustand"
Prozessübergreifend speichern kann aber nicht." Wie ist das gemeint?

Gruß Henrik

von Hagen (Gast)


Lesenswert?

Ok es geht um zwei Punkte in deinen Änderungen:

  variable HCount: std_logic_vector(9 downto 0); -- das ist NICHT wie
bei C-Variablen, wo diese nach dem verlassen der Schleife gelöscht
würden!
  -- horizontal sync
  begin
    if Enable = '0' then
      HCount := (others => '0');
    else
      if Clock'Event and Clock = '1' then
        if HCount < 824 then
          HCount := HCount + 1;
 -- bereits hier darst du auf den neuen Wert von HCount zugreifen, da
dieser bei Variablen sofort
 -- aktualisiert wird, im Gegensatz zu einem Signal!

1.) das lokale Variablen ihren Zustand innerhalb des Prozesses
beibehalten. Gut das ist einfach ein "Denkfehler" von mir der einen
Process als langjähiger "sequentiell" denkender Programierer eher als
Funktion betrachtet, statt einem parallel laufendem Thread (im
übertragenem Sinne).

2.) dein zweiter Kommentar das man bei Veränderungen von Variablen
sofort danach "sequentiell" weitere Berechnungen durchführen darf.
Dieser Kommantar macht mich ziemlich stutzig da ich davon ausging das
dies auch auf Signale zutrifft.

ich habe mein Design nun mal in verschiedenen Konfigurationen
verändert. Benutze ich Variablen so verbrauche ich die gleichen
Resourcen es ändert aber sich das maximale Timing zu Ungunsten, es wird
ca. 50% langsammer.
Dann habe ich einfach mal wieder mit Signalen für HCounter/VCounter
benutzt aber diesemal in nur zwei Prozessen berechnet. Dieses Design
verbraucht die gleichen Resourcen ist aber wieder genauso schnell wie
das alte.

Immerhin komme ich bei einem XC95144 auf 133 Makrozellen und einem
maximalem Clock von 83 MHz das wären 161Hz Framerate des VGA
Controllers. Die Reduktion auf max. 34Mhz Clock wenn ich Variablen
benutze könnte störedn sein beim multiplexten Zugriff auf das externe
10ns SRAM.

Gruß Hagen

von Brice (Gast)


Lesenswert?

Hallo leute.Ich muss ein counter als endliche automaten realisieren.Wer
könnte mir dabei helfen??
danke

von Axel Meineke (Gast)


Lesenswert?

Na da können wir dir bestimmt helfen. Du sollst eine State Machine
basteln? Wo hängst du fest? Was klappt nicht? Schilder dein problem mal
etwas genauer bitte.

von Brice (Gast)


Lesenswert?

Ich muss ein Zähler entwickeln,der auf Tastesndruck gestartet und
gestoppt wird.Weiterhin soll dieser Zäler durch betätigen einer
weiteren taste zurückgesetzt werden können.der wert des zählers soll in
hexadezimaler darstellung gegeben werden

Ich soll also das modul counter als endliche automaten realisieren.Ich
weiss wie ein endlichen automaten lauft,und wie ein counter lauft,aber
hänge trotzdem fest.

danke

von Henrik (Gast)


Lesenswert?

Du programmierst einen normalen Zähler mit Reset und Enable. Dann
deklarierst du inder architecture "type Zustaende is (Zaehle, Warte,
Null); signal Zustand : Zustaende;"
Wenn jetzt irgendwas ausserhalb passiert setzt du diese Zustände mit
"Zustand<=Zaehle ;--(oder Warte oder Null)".
Dieser Zustand wird vom Zähler dann bei jeder Takt-Flanke abgefragt und
die entsprechende Aktion ausgeführt.
Was soll denn "...wert des zählers soll in hexadezimaler darstellung
gegeben werden" bedeuten? Logikbausteine können nur Bitmuster
rausgeben. Decodieren mußt du das schon selbst.

Gruss Henrik

von Michael (Gast)


Lesenswert?

Hi

@ Hagen

Ich würde das mit den Counter anders machen. Zähl doch einfach von 115
auf 0. Ich denke mal das spart noch mal Logik, da der Vergleich jetz
nicht mehr if(x < 115) lautet, sondern (if x = 0). Ich glaube das
benötigt weniger Logik, habe es selber aber noch nicht ausprobiert.
Besonders wenn die Zähler größer werden, ist dies sicherlich eine
sinvolle Lösung.

if(rising_edge(clk)) then
   if(counter = 0) then
      counter <= counter - 1;
   else
      counter <= 115;
   end if;
end if;


oder eine andere sehr interessante Lösung:

Stellt Dir mal die Zahl in Binär vor (sagen wir mal 2765)Dies
entspricht binär "101011001101" Dann machst Du folgendes

testsignal <= Counter(11) & Counter(9) & Counter(7) & Counter(6) &
Counter(3) & Counter(2)& Counter(0);

Somit wird das Signal "testsignal" nur dann '1' wenn der Zähler das
richtige Binärmuster besitzt. Die Abfrage lautet dann so:

if(testsignal = '1') then
   Counter <= (others => '0');
else
   Counter <= Counter + 1;
end if;

Gruss

Michael

von Hagen (Gast)


Lesenswert?

@Michael: ich weis, aber leider hilft dieser Trick nicht immer :) Das
liegt aber daran das die Fitter im WebPack und Quartus bei solchen
Sachen echt clever sind. Man kann eine AND/OR/XOR/Komparator Abfrage so
kompliziert wie möglich machen, die beiden Fitter finden meistens das
entsprechende Optimum. Zumindestens ist das meine Erfahrung mit der
Software.

Nun, warum ich aber aufwärts zähle hat einen anderen Grund. Der
HCounter und VCounter dienen als Pixel-Address-Counter. Besonders wenn
man zb. mit Auflösungen von 256,512,1024 Pixel pro Zeile arbeitet ist
das ideal. Desweiteren würde ein Downcounter zwar die eine Abfrage
vereinfachen, aber normalerweise muß man diesen Counter an mehreren
Punkten abfragen. Eben zum Zeitpunkt des Front Porch, Back Porch, Sync
Pulses und des sichtbaren Pixelbereiches.

Würde man einen Downcounter benutzen so wird zwar an einer Stelle alles
einfacher dafür aber an anderen Stellen eben komplizierter.

Davon absehen, ich habe es probiert :) Es brachte exakt die gleichen
Fitting Ergebnisse.

Wichtiger nach meiner Erkenntisse ist der Unterschied zwischen Abfragen
wie

if Counter >= x then oder if Counter <= x then ;

zu Abfragen wie

if Counter > x then oder if Counter < x then ;

da konnte ich Unterschiede im Resourcenverbrauch feststellen, obwohl
ich mir diese nicht so recht erklären kann.

Gruß Hagen

von Michael (Gast)


Lesenswert?

Hi Hagen

Meine Erfahrungen haben gezeigt, dass man bei sehr großen Zählern sehr
viele Ressourcen einsparen kann, wenn man es mit der Verknüpfung macht.
Jedoch ist das auch schon zwei Jahre her. Vielleicht sind die Tools
jetzt besser geworden. Ich werde gleich mal ein Beispiel ausprobieren
und dann posten. Bin selber mal gespannt.

Ich merke schon Du steckst sehr tief in dem Thema, das finde ich sehr
gut, denn ich arbeitet auch schon etwas länger mit VHDL und genau dann
stellt man sich die Fragen, wie kann ich das Design optimierern um mehr
Geschwindigkeit aus dem Design zu holen. Nur leider gibt es noch zu
wenig Fachleute in Deutschland. Ich hatte Vorlesungen über VDHL, aber
über einfache Beispiele ist man leider nicht hinausgekommen. Das
Problem ist halt, dass man einfach kaum Literatur findet, die einem da
weiterhilft.

Sag mal in welcher Stadt wohnst Du. (nicht zufällig in Lübeck)

Gruss

Michael

von Michael (Gast)


Lesenswert?

So habe mal als erstes folgendes erstellt:

signal  COUNTER    : std_logic_vector(11 downto 0);
signal  S_NEW_CLK  : std_logic;

begin

NEW_CLK <= S_NEW_CLK;

process (CLR,CLK,COUNTER,S_NEW_CLK)

 begin

    if(CLR = '1')then
       COUNTER <= (others => '0');
       S_NEW_CLK <= '0';
    elsif(CLK'event and CLK = '1')then
       if(COUNTER = "100111111100")then -- 2556
          COUNTER <= (others => '0');
          S_NEW_CLK <= not S_NEW_CLK;
       else
          COUNTER <= COUNTER + 1;
       end if;
    end if;
end process;

Diese Variante benötigt 27 4-Input-LUTs und 13 Slice FF. Es ist eine
maximale Frequenz von 115,44 MHz möglich. Ich habe ISE auf "Speed"
gestellt und er soll die optimale Lösung finden.

Danach habe ich zum Vergleich die andere Variante getestet.


signal  COUNTER    : std_logic_vector(11 downto 0);
signal  S_NEW_CLK  : std_logic;
signal  TEST       : std_logic;

begin

TEST <= COUNTER(11) and COUNTER(8) and COUNTER(7) and COUNTER(6) and
COUNTER(5) and COUNTER(4) and COUNTER(3) and COUNTER(2);
NEW_CLK <= S_NEW_CLK;

process (CLR,CLK,COUNTER,S_NEW_CLK)

 begin

    if(CLR = '1')then
       COUNTER <= (others => '0');
       S_NEW_CLK <= '0';
    elsif(CLK'event and CLK = '1')then
       if(TEST = '1')then -- 2556 100111111100
          COUNTER <= (others => '0');
          S_NEW_CLK <= not S_NEW_CLK;
       else
          COUNTER <= COUNTER + 1;
       end if;
    end if;
end process;

Die zweite Variante benötigt 25 4-Input-LUTs und 13 Slice FF. Es ist
eine maximale Frequenz von 109,9 MHz möglich.

So was aber auch. Ich denke mal das der Zähler noch zu klein ist, Aber
wenn man einen sehr großen Teiler benötigt, dann ist diese Variante
sicherlich besser. :-)

Vielleicht kann man die "ANDs" noch zusammenfassen, so dass
vielleicht noch mehr speed drin ist.

Gruss Michael

von Hagen (Gast)


Lesenswert?

>> Sag mal in welcher Stadt wohnst Du. (nicht zufällig in Lübeck)

nee auf halber Strecke zum anderen Ende der Republik, in Eisenach.

Ich mache es bei der Optimierung immer so das verschiedene Sachen
austeste. Zum Glück ist es nur Hobby, professionell könnte man sich
nicht so viel Zeit nehmen.

Aber meistens sitze ich an ganz anderen Problemen: sowas wie "verdammt
die funktionale Simulation macht alles richtig, aber die Timing
Simulation ist komplett verhunzt". Besonders wenn es um BiDir TriState
Sachen geht scheint es sehr große Unterschiede zwischen Altera/Xilinx -
ModelSim/Altera Simulator - CPLD's und FGPA's zugeben.

Ich habe einige kleinere Sache mit CPLD's gemacht, bin aber immer
wieder zu schnell an die Grenzen gestossen. Ehrlich gesagt: sobald die
Logik/FSM ein bischen komplizierter wird reichen CPLD's nicht mehr
aus. Den Schritt hin zu FPGA wage ich aber noch nicht, kostet ja noch
mehr Zeit und Geld und selber dann was bauen ist mit BGA nun auch nicht
so einfach.

Von daher reichen CPLD's für mich um simple Addressdekoder, Memory
Mapped Controller und Taktteiler zu programmieren. Ne I2C Slave
Porterweiterung wäre noch denkbar, da ich noch zu viele CPLD's
rumliegen habe.

Zur Zeit versuche ich anscheindend das unmögliche, ich möchte einen
simplen Level-Shifter hinbekommen, sprich zwei Pins sind intern
miteinander verbunden aber beide sind inout und TriState. Sinn und
Zweck der Sache ist es bei meinem aktuellen Projekt die 4 noch freien
Pins als Level-Shifter von 5V auf 3.3V zu benutzen. Für SPI/TWI ja kein
Problem da das alles unidirekional ist, aber schön wäre es eben wenn
man's für I2C auch hinbekäme.

Gruß Hagen

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.