Hallo Leute, mal wieder eine Frage zum Frequenzteiler. Ich möchte folgendes aufbauen: Ich habe einen CPLD (Xilinx 9572), an einem Pin Liegt ein Takt an, an 8 Pins soll der Teilerwert anliegen und ein Pin als Ausgang. Ich habe schon gelesen, dass man am besten einen Vektor als Signal nehmen sollte und einfach die Bits an den Ausgang legt. Soetwas habe ich mal gemacht und das sieht so aus: entity counter is Port ( CLOCK : in std_logic; Teiler : in std_logic_vector(7 downto 0); Takt : out std_logic); end counter; architecture Behavioral of counter is signal count_val : std_logic_vector(7 to 0) := "00000000"; begin process (CLOCK) begin if CLOCK='1' and CLOCK'event then count_val <= count_val + 1; end if; if Teiler = 2 then TAKT <= count_val(1); end if; if Teiler = 4 then TAKT <= count_val(2); end if; if Teiler = 8 then TAKT <= count_val(3); end if; . . . . end process; End Behavioral; Ich habe es noch nicht probiert, müßte aber funktionieren. Wenn ich das so löse, bekomme ich aber nur die Werte /2, /4, /8 usw. raus. Wie muß ich das realisieren, wenn ich auch /6, /10 usw. haben will ??? Danke schon im voraus. Mattias
Hallo Mattias, ich würde die Sache folgendermaßen lösen: entity counter is Port ( CLOCK : in std_logic; Teiler : in std_logic_vector(7 downto 0); Takt : out std_logic); end counter; architecture Behavioral of counter is signal count_val : std_logic_vector(7 to 0) := "00000000"; signal s_takt : std_logic := '0'; begin process (CLOCK) begin if CLOCK='1' and CLOCK'event then if count_val = Teiler then count_val <= count_val + 1; s_takt <= not s_takt; end if; end if; end process; Takt <= s_takt; End Behavioral; => Teiler | Takt --------|----------- 0 | Clock / 2 1 | Clock / 4 2 | Clock / 6 3 | Clock / 8 ... Ich habe den Code nicht getestet, aber im Prinzip sollte es so funktionieren. Gruß Ines PS: Bei Deiner Beschreibung hat sich ein kleiner Fehler eingeschlichen. Mit der Anweisung if Teiler = 2 then TAKT <= count_val(1); end if; halbierst Du den Takt nicht, sondern viertelst ihn. count_val(0) macht die Halbierung.
Ähm - oder doch besser so :-)) if count_val = Teiler then count_val <= (others => 0); s_takt <= not s_takt; else count_val <= count_val + 1; end if;
Hallo Ines, die erste Variante funktioniert natürlich nicht, da count_val nie erhöt wird. Was bedeutet count_val <= (others => 0); Der compiler versteht das auch nicht. Gruß Mattias
Hallo, eigentlich muss es heißen count_val <= (others => '0'); (kleiner Fehler meinerseits :-) ) und ist gleichbedeutend mit count_val <= "00000000"; Vorteil: Man muss einfach nicht beachten, wie lang der Vektor count_val ist und kann sich beim Zählen der Nullen nicht vertippen. Es werden alle Bits des Vektors auf '0' gesetzt. Du kannst dieses Konstrukt auch hier verwenden: signal count_val : std_logic_vector(7 to 0) := (others => '0'); Dass die erste Variante nicht funktioniert war klar, deshalb habe ich sie ja auch gleich verbessert - hätte ich vielleicht deutlicher klar machen sollen. Ines
Hallo Ines, jetzt funktioniert es so wie es soll. Ich habe mal probiert, die Frequenz auch durch ungerade Werte zu teilen. Dazu muß jedes CLOCK event ausgewertet werden. So habe ich das gemacht: architecture Behavioral of counter is signal count_val : std_logic_vector(0 to 7) := "00000000"; signal s_takt : std_logic := '0'; begin process (CLOCK) begin if ((CLOCK='1' and CLOCK'event) OR (CLOCK='0' and CLOCK'event))then -- if CLOCK='1' and CLOCK'event then if count_val = (Teiler - 1) then count_val <= "00000000"; s_takt <= not s_takt; else count_val <= count_val + 1; end if; end if; end process; Takt <= s_takt; End Behavioral; In der Simulation geht das wunderbar. Beim Compilieren erhalte ich aber den Fehler: counter.vhd line 23: unsupported Clock statement. Es geht auch nicht mit CLOCK'event alleine. Geht das wirklich nicht, dass ich jede Flanke auswerte, oder ist das nur falsch geschrieben ??? Mattias
Hallo Mattias, nein, das geht wirklich nicht - keine Fehler in der Beschreibung (deshalb funktioniert auch die Simu). Du hast ein Register / FlipFlop beschrieben, dass auf beiden Clockflanken Daten übernehmen soll, also ein DDR-FF. In Hardware hast Du das aber nicht (ich kenne DDR-FFs nur bei einigen Bausteinen als Ausgangsregister an Pins, z.B. Spartan3 - korrigiert mich bitte jemand, wenn ich hier was Falsches erkläre). Deshalb kann das Synthesetool Deine Beschreibung nicht umsetzen und meckert dementsprechend. Gruß Ines
Durch ungerade Zahlen kann man auch problemlos teilen, nur dass dann der Duty Cycle nicht exakt 50% ist. Das mit den beiden Taktflanken in einem Prozess geht nur bei ganz wenigen PLDs (z.B. Cooolrunner-II von Xilinx). Sollte man so aber nicht machen. Statt dessen musst du zwei Prozesse beschreiben, einen mit fallender und einen mit steigender Taktflanke. Die Augänge werden dann kombinatorisch verknüpft. Und wenn mans richtg macht, ist der Ausgang auch glitchfrei. MFG Falk
Hallo Frank, was meinst Du damit, wenn man es richtig macht. Könntest Du mal ein Beispiel bringen ? Mattias
Ich heisse zwar Falk, ist aber unkritisch ;-) Wenn du beispielsweise eine Takt durch 3 teilen willst, kannst du mit der "normalen" Variante, also die nur mit steigender ODER fallender Flanke arbeitet nur die Muster 100, 110 erzeugen (als Zeitdigramm deines Ausgangs). Denn "halbe" Takte gibt es dabei nicht. Nun der Trick mit zwei Prozessen. Ein Prozesse steigender Taktflanke erzeugt das Muster 001. Ein zweiter Prozess mit fallender Taktflanke verzögert dieses Muster um 1/2 Takt. Die ODER-Verknüpfung der beiden bildet ein Taktsignal, das 3/2 Takte LOW und 3/2 Takte HIGH ist. ich habs nochmal versucht darzustellen, ist vielleicht ein wenig kryptisch. Der VHDL-Code sollte funtionieren, ist aber nicht getestet. Versuchs mal. Die Entity musst du selber schreiben, bin ich jetzt zu faul ;-) Nr. 1 2 3 4 5 6 TAKT 101010101010 P1 000011000011 P2 100001100001 P1 or P2 100011100011 -- VHDL start signal cnt: std_logic_vector(1 downto 0); signal P1, P2: std_logic; process(clk) begin if rising_edge(clk) then if cnt=2 then cnt=0 else cnt = cnt+1; end if; P1 <= cnt(1); end if; end process; P2: process(clk) begin if falling_edge(clk) then P2 <= P1; end if; end process; clk_div_3 <= P1 or P2; -- VHDL end MfG Falk P.S. Um diesen Frequenzteiler noch zu optimieren, kann und sollte man bei höheren Frequenzen (50MHz++) die beiden FlipFlops P1 und P2 per Hand in möglichst nah beieinanderliegende Slices/LEs platzieren, um den Einfluss von Laufzeiten zu minimieren.
Es gab mal diese kurze Applikation ( Design Brief 5, DB-5 )von National Semiconductor ein einstellbarer Teiler von 1-16 mit symmetrischem Ausgang für alle Teilfaktoren, auch ungerade. Allerdings wird der Clock hier über EXOR-Gatter geschickt, das kann man in CPLDs nur auf irgendwelchen Umwegen.
Hallo Falk, Deinen Code habe ich erfolgreich getestet (Simulation). Jetzt muss ich nur noch schauen, wie ich das ganze mit meinem Teiler flexibel von außen schaltbar machen kann. Das ist mir bisher noch nicht gelungen. Mattias
Das bleibt die aufgabe für den engagierten Basterl/Studenten/wasauchimmer. ;-) MfG Falk
Also ich habe das Programm auch mal getestet, aber irgendwie sagt der bei der Zeile: count_val <= count_val + 1; jedesmal Subprogram error: can't interpret subprogramm Call, kann mir da jmand weiter helfen?
So, ier noch mal das ganze Programm library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; entity Frequenzteiler is port( Reset: in std_logic; CLK1: in std_logic; -- Input Clock 1 MHz CLK2: out std_logic -- Output Clock 4 kHz ); end Frequenzteiler; architecture behv of Frequenzteiler IS SIGNAL var_zustands_vector: std_logic_vector (7 DOWNTO 0) := (others => '0'); SIGNAL s_takt : std_logic := '0' ; BEGIN PROCESS (Reset, CLK1) BEGIN IF Reset = '1' THEN var_zustands_vector <= "00000000"; ELSIF CLK1='1' and CLK1'event THEN var_zustands_vector <= var_zustands_vector + "00000001"; END IF; IF var_zustands_vector <="10000000" THEN s_takt<='1'; END IF; IF var_zustands_vector >="10000000" THEN s_takt<='0'; END IF; CLK2 <= s_takt; END PROCESS; END behv;
Probier mal das aus:
1 | library ieee; |
2 | use ieee.std_logic_1164.all; |
3 | use ieee.numeric_std.all; |
4 | |
5 | entity Frequenzteiler is |
6 | port( |
7 | Reset: in std_logic; |
8 | CLK1: in std_logic; -- Input Clock 1 MHz |
9 | CLK2: out std_logic -- Output Clock 4 kHz |
10 | );
|
11 | end Frequenzteiler; |
12 | |
13 | architecture behv of Frequenzteiler IS |
14 | SIGNAL var_zustands_vector: unsigned(7 DOWNTO 0) := (others => '0'); |
15 | SIGNAL s_takt : std_logic := '0'; |
16 | |
17 | BEGIN
|
18 | |
19 | synch : PROCESS (Reset, CLK1) |
20 | BEGIN
|
21 | IF Reset = '1' THEN |
22 | var_zustands_vector <= (OTHERS => '0'); |
23 | ELSIF rising_edge(CLK1) THEN |
24 | var_zustands_vector <= var_zustands_vector + 1; |
25 | END IF; |
26 | END PROCESS; |
27 | |
28 | CLK2 <= var_zustands_vector(7); |
29 | |
30 | END behv; |
Uups, ein Fehler:
1 | CLK2 <= var_zustands_vector(7); |
muss natürlich
1 | CLK2 <= NOT var_zustands_vector(7); |
heissen. Bedenke aber, dass man den erzeugten Takt nur als Clkenable-Signal weiterverwenden sollte...
> entity Frequenzteiler is > port( > Reset: in std_logic; > CLK1: in std_logic; -- Input Clock 1 MHz > CLK2: out std_logic -- Output Clock 4 kHz > ); > end Frequenzteiler; > architecture behv of Frequenzteiler IS SIGNAL var_zustands_vector: > std_logic_vector (7 DOWNTO 0) := (others => '0'); Ähhh, soll das ein Signal sein? Welches? Eine reine Typdefinition ist bissel sinnlos. > SIGNAL s_takt : std_logic := '0' > ; > BEGIN > PROCESS (Reset, CLK1) > BEGIN > IF Reset = '1' THEN > var_zustands_vector <= "00000000"; Wo ist die Definition? Soll das dort oben gewesen sein? > ELSIF CLK1='1' and CLK1'event THEN > var_zustands_vector <= var_zustands_vector + "00000001"; Schreisbt man sinnvolerweise als var_zustands_vector <= var_zustands_vector + 1; Dafür gibts ja die Bibliotheken. > END IF; > IF var_zustands_vector <="10000000" THEN s_takt<='1'; END IF; Dito hier, ma kann ganz normal mit Dezimalzahlen vergleichen. LESBARKEIT! > IF var_zustands_vector >="10000000" THEN s_takt<='0'; END IF; Kann man hier sinnvoll in ein IF THEN ELSE reinpacken. > CLK2 <= s_takt; > END PROCESS; >END behv; MFG Falk Und wo ist jetzt die Fehlermeldung?
hallo Ines, ich habe mir deinen Code mal angesehen, und soweit eigentlich ganz gut verstanden. Hab über das Altium Board einen Takt von 50MHz gegeben, welcher mit CLK_BRD abgegriffen wird. Mein problem ist jetzt, ihn auf 50Hz und 500kHz zu bringen. Will dafür das von dir oben geschriebene hernehmen, nur komm ich leider nicht dahinter, wie das funktionieren soll. könnte mir da bitte jemand helfen? Die Tabelle is soweit einsichtig, dass wenn ich den Teiler 3 hernehme, die Clock durch 8 geteilt wird. In meinem Fall (für die 500kHz) muss ich die Frequenz einmal mit 100 dividieren, was für mich einen Teiler von 40 bedeuten würde. Im 2. Fall (für die 50 Hz) muss ich die Frequenz ja durch 10^6 dividieren, was für mich also einen Teiler von 40000 beudeutet. Stimmt das, oder lieg ich da auch falsch?
@ Jonas: Woher hast du denn den Zombiethread? >> 07.12.2006 13:21 Beschreib doch besser mal, was du willst. Du hast ein FPGA (im Ursprungsthread gings um ein CPLD, das sind 2 unterschiedliche Welten), das mit 50MHz getaktet wird. Willst du jetzt innerhalb des FPGAs irgendwas mit 500kHz und 50Hz machen, oder willst du diesen Takt ausgeben? Wenns innerhalb des FPGAs sein soll, dann arbeitest du besser mit Clock-Enable, siehe Artikel FPGA und Taktung FPGA/CPLD
hab grad nen neuen thread aufgemacht, weil mir der etwas alt vorkamm....:)
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.