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.
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
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
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;
> 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