www.mikrocontroller.net

Forum: FPGA, VHDL & Co. einstellbarer Taktteiler in VHDL


Autor: Boris M. (borism)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

ich bin relativ neu hier - entschuldigt bitte wenn ich so etwas banales 
frage, aber ich konnte hier im Forum und mit google nichts finden was 
mir weiterhilft...
Ich habe zum spielen ein Spartan 3A DSP 1800 Board bekommen. Jetzt 
möchte ich den 125 MHz Systemtakt "einstellbar" runtertakten.
Hierzu möchte ich die 8 DIP-Schalter auslesen um mir so eine Frequenz 
zwischen 1 Hz und 256 Hz einstellen zu können.
Aber wie errechne ich mir in VHDL die entsprechenden Werte für meinen 
Zähler? Ich benutze zur Zeit nur Std_Logic_Vektoren - da ich mit integer 
range xxx to yyy große Probleme hatte.

Ich habe mir gedacht dass ich einen Zähler benutze - von der ersten 
Taktflanke (der 125 MHz Clock)bis zur Taktflanke für die halbe 
gewünschte Frequenz soll er das "neue" Taktsignal auf '0' setzten und 
von da bis zur Taktflanke bei der gewünschten Frequenz soll er das 
Taktsignal auf '1' setzten. (Ich hoffe ich konnte mich verständlich 
ausdrücken!) Hierzu müsste ich dann aber für jede Frequenz mit Potenzen 
rechnen - das scheint mir aber viel zu unübersichtlich (oder ich kenne 
die Befehle einfach nicht).
Alternativ habe ich an einen Automaten gedacht - der wird aber riesig 
groß...

Bin für jede Hilfe (auch Links) dankbar...

Gruß Boris

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

Bewertung
0 lesenswert
nicht lesenswert
Mach doch einfach einen counter der alle halbe Sekunde einen hochzählt.
Immer wenn der Zählerstand XOR deinen Dipswitches 0 ergibt toggelst du 
deinen Ausgang und resetest den Timer.

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich würde mal empfehlen mit dem unsigned Datentyp aus der numeric_std zu 
arbeiten. Das ist standardisiert und jedenfalls eher richtig als andere 
Dinge.


Zur Aufgabe: Vielleicht könntest du den Zähler mit dem 8 bit Wert der 
sich aus den DIP-Switches ergibt erhöhen, dann musst du dir einmal den 
Wert für 1 Hz ausrechnen und der Rest sollte sich von selbst ergeben. 
Dann vergleichen ob der Zählerwert größer-gleich dem Maximalwert ist und 
in Abhängigkeit davon togglen und den Zähler zurücksetzen.

Aber da gibts sicher schönere Lösungen.

Und daran denken dass während dem Umschalten der Dipswitches das ganze 
vmtl mal für kurze Zeit nicht ganz so glatt funktioniert hat. Aber das 
bleibt dir eh nicht erspart, wenn du die Switches nicht entprellst.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> um mir so eine Frequenz zwischen 1 Hz und 256 Hz einstellen zu können.
Das ist gar nicht mal sooo trivial wie es auf den ersten Blick aussieht, 
denn es sollen ja vermutlich die Frequenzen 1Hz, 2Hz, 3Hz, 4Hz, 5Hz ... 
256Hz erzeugt werden?

Es reicht nicht aus, einfach den Binärwert auf einen Reloadwert 
hochzumultiplizieren. Du brauchst eigentlich den Kehrwert des 
eingestellten DIP-(Frequenz-)Wertes. Ich könnte mir vorstellen, dass 
eine Lookup-Tabelle für die Reload-Werte Sinn machen könnte.

> da ich mit integer ... große Probleme hatte.
Wie Matthias schon sagte: die numeric_std bietet schöne (und definierte) 
Umrechnungen und Casts zwischen den Datentypen
integer <-> (un)signed <-> und std_logic_vector
an.

Autor: Boris M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielen Dank für eure Antworten!!!
Werde mich jetzt gleich mal an die Sache ran machen...

Autor: Schrotty (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich halte auch eine Lookup-Tabelle für das Einfachste.
Einfach einmalig für jede DIP-Einstellung den etnsprechenden Reload oder 
Overflow Wert berechnen und dann den Counter immer mit diesem Wert 
laufen lassen.
Oder du berechnest den Overflow-Wert zur Laufzeit.

125 000 000 / (Dip-switch * 2) - 1
Die Multiplikation kannst auch durch ein "Schieben" ersetzen.

Also auf den so errechneten Wert zählen, dann ausgang toggeln, Zähler 
zurücksetzen und wieder von vorne anfangen, zu zählen.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 125 000 000 / (Dip-switch * 2) - 1
> Die Multiplikation kannst auch durch ein "Schieben" ersetzen.
Ja, aber das mit der Division wird lustig   ;-)

Autor: Schrotty (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ja ich kenn jetzt den Spartan nicht und weiss nicht, ob der 
Multiplizierer hat. Dann wäre das kein Problem ist ja kein Fliesskomma 
und nix. Also ich seh die Divishon nicht als soo stressig. Und selbst, 
wenn man sie "konventiell" durchführen muss, da keine Multiplizierer 
vorhanden, kann man ja nen langsamen Takt wählen oder in merhreren 
Zyklen durchführen.

Ich hab hier in meinem aktuellen Design ne fixed-point Multiplikation 
drin (32 Bit x 16 Bit) und die läuft in konventioneller Hardware ohne 
Probleme mit 50 MHz auf einem Lattice XP

Und hier wäre es ja nur ne Multiplikation mit 8 Nachkommastellen (8 Bit 
Dip-switch)
Also ich seh in dem Multiplizierer/ Dividierer gar kein Problem.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Also ich seh die Divishon nicht als soo stressig.
Du solltest da schon den bisherigen Wissenstand unseres Delinquenten in 
Betracht ziehen:
>> Ich habe zum spielen ein Spartan 3A DSP 1800 Board bekommen.
>> Bin für jede Hilfe (auch Links) dankbar...

> ... ob der Multiplizierer hat.
Multiplizierer gibts. Die laufen mit +100MHz.
Aber du mußt durch die DIP-Schalter teilen.
Wie würdest du deine Berechnung durchführen?


> Also ich seh in dem Multiplizierer/ Dividierer gar kein Problem.
Ich bei den Multiplizierern auch nicht.
Das kann ich in VHDL einfach so hinschreiben
   y <= a*b;
Dazu brauche ich noch nicht mal einen Takt, denn die Multiplikation ist 
eine rein kombinatorische Angelegenheit.

Aber zeig mir doch mal eine Division, die genauso einfach geht.
   y <= a/b;
Allerdings gilt als Rahmenbedingung: Zweierpotenzen (2,4,8,16...) kann 
das Tool schon von alleine  ;-)

Autor: Schrotty (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Dazu brauche ich noch nicht mal einen Takt, denn die Multiplikation ist
eine rein kombinatorische Angelegenheit.
Richtig, ich wollte damit nur ausdrücken, dass die kombinatorische 
"Tiefe" so gering ist, dass der Pfad durch den Multiplizierer in einem 
50MHz Desing läuft. Also kein Pfad im Multiplizierr länger als 20 ns ist

> Aber zeig mir doch mal eine Division, die genauso einfach geht.
Recht hast, da war ich etwas vorschnell. Ne Division durch 5 wird schon 
echt bescheiden gg

Autor: Duke Scarring (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eine Division durch einen festen Wert lässt sich schön auf eine 
Multiplikation zurückführen: z.B. 1/5 ~ 1/4 ~ 2/8 ~ 3/16 ~ 6/32 ~ 13/64 
~ 26/128 ~ 51/256
Man muss nur nach der benötigten Genauigkeit gucken.

Duke

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dann braucht Boris aber Sekundenkleber für die DIP-Schalter,
denn die bleiben ja im Nenner... ;-)

 1/6 ~ 43/256
 1/7 ~ 37/256
 1/9 ~ 28/256
1/10 ~ 26/256
Auch mit diesen Zahlen gibt es nicht die direkte Zuordnung von
DIP-Schalter zu Faktor.

Autor: Boris M. (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo nochmal...

Hab da nochmal eine Anfängerfrage.
Wenn ich die IEEE's NUMERIC_STD benutze kann ich (wenn ich dass richtig 
verstanden habe) folgende Operationen durchführen (+,-,*,/,rem,mod) 
jedoch nur wenn ich unsigned und signed Variblen benutze.
Jetzt habe ich aber das Problem, dass ich meine DIP-Schalter als 
STD_LOGIC_Vector(7 downto 0) declariert habe. Wie wandele ich die um?
Meine Versuche in VHDL enden leider mit einer Fehlermeldung:

FATAL_ERROR:Xst:Portability/export/Port_Main.h:143:1.17 - This 
application has discovered an exceptional condition from which it cannot 
recover.  Process will terminate. For technical support on this issue, 
please open a WebCase with this project attached at 
http://www.xilinx.com/support.

Liegt dass an meinem Code (siehe Anhang)???

Autor: Jan M. (mueschel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Wie wandele ich die um?
unsigned(signalname)  bzw. in die andere Richtung
std_logic_vector(signalname)


Der Error ist wohl eher ein Fehler von ISE, vielleicht mal ein Cleanup 
Project Files machen, oder das Programm neu starten...

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
   if count < ((125000000 / signed_DIP) - 1) then
Das wird nicht gehen.
Eine Division wird in dieser Art von der Synthese nicht unterstützt.
Nur Divisionen durch konstante Zweierpotenzen werden synthetisiert.

Autor: Boris M. (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Jan,
danke für deine schnelle Antwort...

Cleanup Project Files hat leider nicht geholfen...
Durch Probieren habe ich herausgefunden dass es wohl an dieser Zeile 
liegt:

if count < (125000000 / signed_DIP) then

wenn ich hier signed_DIP durch eine Zahl (z.B. 10 ersetze) klappt alles 
wunderbar. Nur ist es ja mein Ziel den Divisor über die DIP-Schalter 
einzulesen...
Oder kann ich die DIP-Schalter schon als SIGNED bzw. UNSIGNED einlesen?

Hab den aktuellen Code als .txt mal angehängt - vielleicht mache ich ja 
etwas Grundsätzliches falsch...

Meine ISE kennt wohl kein UNSIGNED? Ist im Code nicht farbig 
Dargestellt... Oder fehlt mir hierzu eine Bibliothek?

Autor: Boris M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Lothar... Da war ich wohl zu langsam...

Schade dann war mein Gedanke mal wieder falsch...

Habe noch die Idee die Division durch eine Schleife an Subtraktionen 
durchzuführen und mit einem Zähler hoch zu zählen. Das Ergebnis wird 
zwar nicht sehr genau - aber ich denke dass wird mir für den Anfang 
erstmal reichen...

Autor: Joko (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Boris

wieviel DIP-Schalter hast Du denn?

Zur Not eine Funktion schreiben, die für alle möglichen Werte
von "signed_DIP" eine Näherung für "125000000 / signed_DIP"
errechnet, dann ein ROM deklarieren, dessen Inhalt sich durch
Aufruf der o.a. Funktion ergibt: in einem BlockRAM lassen sich
immerhin 18kBits speichern - z.B: 1024 x 18 Bit oder 2048 x 9 Bit

Gruß
Jochen

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Habe noch die Idee die Division durch eine Schleife an Subtraktionen
> durchzuführen und mit einem Zähler hoch zu zählen.
Ja, der pragmatiche Ansatz, so wird es gehen.

> Das Ergebnis wird zwar nicht sehr genau ...
Das Ergebnis wird genauso genau, wie bei einer integer-Division zu
erwarten.
1 / 2           = 0 Rest 1
234566 / 234567 = 0 Rest 234566

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

Bewertung
0 lesenswert
nicht lesenswert
anbei ein Beispiel zur Umrechnung
DIP => 1/DIP via BlockRAM

PAR-Ergebnis auf Spartan3:

Device Utilization Summary:
   Number of BUFGMUXs                        1 out of 8      12%
   Number of External IOBs                  21 out of 124    16%
      Number of LOCed IOBs                   0 out of 21      0%
   Number of RAMB16s                         1 out of 4      25%

gut - es könnte auch noch 'generisch' gemacht werden, aber immerhin...

Gruß
Jochen

Autor: Boris M. (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Joko,

ich werde mir mal deinen Code anschauen - mal sehen ob ich da mit meinem 
bisschen VHDL noch mitkomme. Habe bis jetzt nur mal kurz mit einem 
XC9572 gearbeitet. Demnächst soll ich aber mit dem Spartan 3A bzw. einem 
Virtex zu recht kommen. Deshalb hat mir mein Kollege - der mir das alles 
bei bringen soll ein paar Aufgaben gegeben bis er aus dem Urlaub wieder 
da ist...(siehe Anhang - für die die es interessiert).

Habe mal meine Idee programmiert, bekomme aber eine Fehlermeldung die da 
lautet:

ERROR:Place:1018 - A clock IOB / clock component pair have been found 
that are not placed at an optimal clock IOB /

Hier der Code dazu:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
--use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

use IEEE.NUMERIC_STD.all;

---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity toplevel is
  Port (  LEDs_out          :      out  Std_Logic_Vector (7 downto 0);
        DIP_Switches      :      in    Std_Logic_Vector (7 downto 0);
--        Push_Button_Reset    :      in    Std_Logic;
        reset            :      in    Std_Logic;
--        RS232            :      inout Std_Logic_Vector (xxx);

        CLK            :      in    Std_Logic);
end toplevel;

architecture Behavioral of toplevel is

signal LEDs_in  :  Std_Logic_Vector (7 downto 0) := (others => '0');
signal count  :  integer range 0 to (125000000/2-1);
signal frequenz_zaehler  :  integer range 0 to (125000000/2-1);

--für die Schleife der Subtraktion
signal x  :  integer range 0 to (125000000);
signal y  :  integer range 0 to (125000000);
signal A  :  integer range 0 to (125000000);
signal B  :  integer range 0 to (125000000);

signal sub_fertig  :  STD_LOGIC := '0';

begin

process(reset,CLK)
begin
  if reset = '1' then
    count <= 0;
    LEDs_in <= DIP_Switches;
    sub_fertig <= '0';
    A <= 125000000;  --Clock 125MHz
    B <= 2;    --doppelte gewünschte Frequenz hier 1 Hz
    y <= 0;    --Schleifenzähler
    x <= A;    --Abbruchkriterium für die Schleife (x>=A)
  elsif rising_edge(CLK) then
    if sub_fertig = '0' then
      if x >= B then
        y <= y + 1;
        x <= A - B;
        A <= x;
      else
        sub_fertig <= '1';
        frequenz_zaehler <= y ;
      end if;
    elsif sub_fertig = '1' then
      if count < frequenz_zaehler then
        count <= count +1;
      else
        LEDs_in <= LEDs_in(6 downto 0) & LEDs_in(7);
        count <= 0;
      end if;
    end if;
  end if;
end process;

LEDs_out <= LEDs_in;
end Behavioral;

Autor: Boris M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Jochen,
vielen dank für dein Beispiel Divide_ROM aber das ist glaube ich noch 
etwas zu hoch für mich...

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So nicht:
use IEEE.STD_LOGIC_1164.ALL;
--use IEEE.STD_LOGIC_ARITH.ALL;

use IEEE.STD_LOGIC_UNSIGNED.ALL;  -- nicht beide
use IEEE.NUMERIC_STD.all;         -- Libs parallel verwenden

Eher so:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.ALL;

> ERROR:Place:1018 - A clock IOB / clock component pair have been found
> that are not placed at an optimal clock IOB /
Erst danach wirds interessant ;-)
Wo ist dein Takteingang?

Eine Suche im Forum ergibt z.B. den 
Beitrag "ERROR:Place:1018"

Autor: Joko (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
letzlich 'löst' dieses Schnipsel auch eine andere Aufgabe als die,
die Du (nachträglich) veröffentlicht hast...

Was in meinem Bespiel gemacht wird, ist einfach eine
'vorab-Berechnung' von einer Funktion - hier
- Nenner: konstanter, zur Synthesezeit einstellbarer Wert
- Zähler: alle möglichen Werte von 0..2047 (11 Bit)
- Ausgabe: 9-Bit Wert mit Zähler/Nenner

Innerhalb der Funktions-Deklaration kann man (fast) jede beliebige
Funktion implementieren, die zur Lösung einer Umrechnung benötigt
wird (hier wurde der Einfachheit halber nur Zähler/Nenner berechnet...

Viel Erfolg
Jochen

Autor: Boris M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Lothar: vor meiner nächsten Frage möchte ich mich erstmal bei Dir für 
die vielen Antworten DANKEN ! ! ! Gerade als Anfänger macht man häufig 
fehler die nicht passieren sollten oder fragt das ein oder andere 
mehrmals bevor man es richtig versteht...

>library IEEE;
>use IEEE.STD_LOGIC_1164.ALL;
>use IEEE.numeric_std.ALL;<
Habe die IEEE.STD_LOGIC_UNSIGNED.ALL jetzt auskommentiert.

>Wo ist dein Takteingang?
Mein Takteingang ist CLK (auf dem Board F13)

>Erst danach wirds interessant ;-)
Habe gerade erst rausgefunden, dass ich immer nur einen Teil der 
Warnings und Errors gesehen habe. Mal sehen ob ich das Problem nicht 
selbst lösen kann. Liest sich eigentlich recht einfach...

Hier die komplette Fehlermeldung:
ERROR:Place:1018 - A clock IOB / clock component pair have been found 
that are not placed at an optimal clock IOB /
   clock site pair. The clock component <reset_IBUF_BUFG> is placed at 
site <BUFGMUX_X2Y11>. The IO component <reset> is
   placed at site <J17>.  This will not allow the use of the fast path 
between the IO and the Clock buffer. If this sub
   optimal condition is acceptable for this design, you may use the 
CLOCK_DEDICATED_ROUTE constraint in the .ucf file to
   demote this message to a WARNING and allow your design to continue. 
However, the use of this override is highly
   discouraged as it may lead to very poor timing results. It is 
recommended that this error condition be corrected in
   the design. A list of all the COMP.PINs used in this clock placement 
rule is listed below. These examples can be used
   directly in the .ucf file to override this clock rule.
   < NET "reset" CLOCK_DEDICATED_ROUTE = FALSE; >

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was passiert, wenn du den Reset synchron machst?
process(reset,CLK)
begin
  if rising_edge(CLK) then

    if sub_fertig = '0' then
      if x >= B then
         :
         :
      end if;
    end if;

    if reset = '1' then  -- RESET Synchron
      count <= 0;
      :
      :
      x <= A;    --Abbruchkriterium für die Schleife (x>=A)
    end if;

  end if;
end process;

Autor: Boris M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Was passiert, wenn du den Reset synchron machst?

Jetzt funktioniert es ohne die Fehlermeldung.
DAnn kann ich ja die DIP_Schalter zum einstellen jetzt hinzufügen:)
Das Problem, dass ich meist zuviele IF-Anweisungen verschachtel hatte 
ich schon bei meinem XC9572...

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> dass ich meist zuviele IF-Anweisungen verschachtel hatte
Der Fehler kommt nicht vom "Verschachteln", sondern von der ungünstigen 
Eingangs-Pin-Position des Reset-Signals. Aber mach ruhig auch in Zukunft 
den Reset synchron, am besten vor Verwendung das Reset-Signal noch über 
2 FFs durchtakten.

Antwort schreiben

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

Wichtige Regeln - erst lesen, dann posten!

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

Formatierung (mehr Informationen...)

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




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

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