Hallo zusammen,
ich benötige für ein Projekt einen Frequenzteiler und habe schon einige
Zeit hier im Forum gelesen, unten ist das Ergebnis. Leider sieht man
weder an den LED, noch in dem Xilinx ISE Simulator irgendeine Reaktion
(die '1' für die LED 7 natürlich ausgenommen). Liegt es daran, dass ich
immer nur für einen Takt eine 1 ausgebe? Das müsste aber ja im Simulator
zu sehen sein, oder?
Muss ich es eigentlich wirklich auf so viele Zähler aufteilen?
Besten Dank
Marco
_______________________________________________________________________
entity frequenz is
Port ( takt, reset : in STD_LOGIC;
led1 : out STD_LOGIC;
led2 : out STD_LOGIC;
led3 : out STD_LOGIC;
led4 : out STD_LOGIC;
led5 : out STD_LOGIC;
led6 : out STD_LOGIC;
led7 : out STD_LOGIC);
end frequenz;
architecture Behavioral of frequenz is
signal f10m, f1m, f100k, f10k, f1k, f100, f10, f1: std_logic_vector(3
downto 0);
signal ci10m, ci1m, ci100k, ci10k, ci1k, ci100, ci10, ci1: std_logic;
begin
teiler10m: process (reset, takt, f10m)
begin
if reset ='1' then
f10m <= "0000";
else
if rising_edge(takt) then
if f10m = 4 then
f10m <="0000";
else
f10m <= f10m + 1;
end if;
else
f10m <= f10m;
end if;
end if;
end process teiler10m;
ci10m<='1' when f10m = 4 else '0';
teiler1m: process (reset, takt, f1m, ci10m)
begin
if reset ='1' then
f1m <= "0000";
else
if rising_edge(takt) and ci10m = '1' then
if f1m = 9 then
f1m <="0000";
else
f1m <= f1m + 1;
end if;
else
f1m <= f1m;
end if;
end if;
end process teiler1m;
ci1m<='1' when (f1m = 9 and ci10m='1') else '0';
teiler100k: process (reset, takt, f100k, ci1m)
begin
if reset ='1' then
f100k <= "0000";
else
if rising_edge(takt) and ci1m = '1' then
if f100k = 9 then
f100k <="0000";
else
f100k <= f100k + 1;
end if;
else
f100k <= f100k;
end if;
end if;
end process teiler100k;
ci100k<='1' when (f100k = 9 and ci1m='1') else '0';
teiler10k: process (reset, takt, f10k, ci100k)
begin
if reset ='1' then
f10k <= "0000";
else
if rising_edge(takt) and ci100k ='1' then
if f10k = 9 then
f10k <="0000";
else
f10k <= f10k + 1;
end if;
else
f10k <= f10k;
end if;
end if;
end process teiler10k;
ci10k <='1' when (ci100k='1' and f10k = 9) else '0';
teiler1k: process (reset, takt, f1k, ci10k)
begin
if reset ='1' then
f1k <= "0000";
else
if rising_edge(takt) and ci10k = '1' then
if f1k = 9 then
f1k <="0000";
else
f1k <= f1k + 1;
end if;
else
f1k <= f1k;
end if;
end if;
end process teiler1k;
ci1k<='1' when (f1k = 9 and ci10k='1') else '0';
teiler100: process (reset, takt, f100, ci1k)
begin
if reset ='1' then
f100 <= "0000";
else
if rising_edge(takt) and ci1k='1' then
if f100 = 9 then
f100 <="0000";
else
f100 <= f100 + 1;
end if;
else
f100 <= f100;
end if;
end if;
end process teiler100;
ci100<='1' when (f100 = 9 and ci1k='1') else '0';
teiler10: process (reset, takt, f10, ci100)
begin
if reset ='1' then
f10 <= "0000";
else
if rising_edge(takt) and ci100='1' then
if f10 = 9 then
f10 <="0000";
else
f10 <= f10 + 1;
end if;
else
f10 <= f10;
end if;
end if;
end process teiler10;
ci10<='1' when (f10 = 9 and ci100='1') else '0';
teiler1: process (reset, takt, f1, ci10)
begin
if reset ='1' then
f1 <= "0011";
else
if rising_edge(takt) and ci10='1' then
if f1 = "1100" then
f1 <="0011";
else
f1 <= f1 + 1;
end if;
else
f1 <= f1;
end if;
end if;
end process teiler1;
ci1<='1' when (ci10='1' and f1 = 9) else '0';
led1 <= ci1;
led2 <= ci10;
led3 <= ci100;
led4 <= ci1k;
led5 <= ci10k;
led6 <= ci100k;
led7 <= '1';
end Behavioral;
_______________________________________________________________________
In welchem Buch hast du solche Konstrukte schon mal gesehen?
1
ifreset='1'then
2
f10m<="0000";
3
else
4
ifrising_edge(takt)then
5
iff10m=4then
6
f10m<="0000";
7
else
8
f10m<=f10m+1;
9
endif;
10
else-- !!!! Was soll denn das? Wenn keine steigende Taktflanke?
11
f10m<=f10m;
12
endif;
13
endif;
Auch das ist eher selten zu sehen:
1
ifrising_edge(takt)andci10='1'then
Du hast trotzdem Glück gehabt: die Synthese kann das heutzutage...
Warum machst du nicht erst mal nur einen einzigen Teiler?
Und wenn der läuft machst du die weiteren?
Ich würde das übrigens so angehen:
1
useieee.numeric_std.all;
2
:
3
:
4
signalc1,c10,c100:integerrange0to9:=0;
5
:
6
-- Einer
7
processbegin
8
waituntilrising_edge(clk);
9
led1<='0';
10
if(c1<9)then
11
c1<=c1+1;
12
else
13
c1<=0;
14
led1<='1';
15
endif;
16
endprocess;
17
18
-- Zehner
19
processbegin
20
waituntilrising_edge(clk);
21
led2<='0';
22
if(c1=9)then
23
if(c10<9)then
24
c10<=c10+1;
25
else
26
c10<=0;
27
led2<='1';
28
endif;
29
endif;
30
endprocess;
31
:
BTW: warum fänst du bei den LEDs mit 1 an?
Mach das besser gleich von vornm weg mit 0..7 statt mit 1..8!!
vielen Dank schonmal für die Hilfe...
Die Reduzierung des Taktes bis auf 1 Hertz funktioniert jetzt. Nun habe
ich versucht nach dem Frequenzteiler auf 10 Hz einen 2Hz-Takt wie folgt
zu generieren:
1
processbegin
2
waituntilrising_edge(clk);
3
clk_2<='0';
4
if(c10>4)then
5
clk_2<='1';
6
else
7
clk_2<='0';
8
endif;
9
endprocess;
dabei soll das High Signal für die gleiche Zeit anliegen wie das Low
Signal.
leider funktioniert es aber nicht so wie es soll...
Für mich sieht es so aus, als ob die LED durchgehend leuchtet.
Sorry, was machst du da? Du musst das Signal der LED zuweisen und zudem
machst du damit ein 40%, 60% Teilerverhältnis.
Wenn du den Takt herunterteilen willst, so solltest du darauf achten
eine Gated Clock zu vermeiden. D.h. mit einem Zähler runterteilen und
ein enable-Pulsemuster generieren und alles mit EINER Clock takten. Denn
jeder Taktübergang ist eine potentielle Fehlerquelle.
Ja, das Signal weise ich später der LED zu, das ist ja erstmal nicht so
wichtig. Daher hatte ich es auch nicht gepostet.
Ist es wirklich ein 40/60 Verhältnis? So wie ich es verstehe habe ich
für 0-4 ein LOW Signal und für 5-9 ein High Signal.
Was meinst du mit enable Pulsmuster?
M. N. schrieb:> leider funktioniert es aber nicht so wie es soll...> Für mich sieht es so aus, als ob die LED durchgehend leuchtet.
Und was sagt die Simulation?
Stimmt, ergibt doch 50:50 Teilung. Du teilst also von 10 Hz auf 5 Hz
runter.
Wenn du einfach nur einen Takt runterteilen willst, aber Probleme mit
Gated Clock vermeiden willst, so verwende das von mir unten
vorgeschlagene Konstrukt. Natürlich lassen sich auch mehrere Divider
kaskadieren.
@Lothar
über einen solch langen Zeitraum kann ich doch garnicht simulieren oder?
also ich benutze das Xilinx ISE Webpack 10.1. Oder ist es möglich direkt
nur die letzten beiden Frequenzteiler zu simulieren, ohne die restlichen
Vorgeschalteten und den 50MHZ clk als Quelle?
Muss ich es vielleicht mit einem anderen Programm simulieren?
@Sym
stimmt, das ist falsch, aber das wären so wie ich es oben geschrieben
habe dann 1Hz und nicht 5. Dann werde ich ja mit meinem 10 Hz Takt nicht
glücklich oder? Ich kann ja nicht bis 2,5 zählen lassen.
Kann man dann das "enable" für weitere Counter im Design und auch als
2.Clock in anderen Components benutzen?
Also wenn ich in einer anderen Component einen Zähler habe der mit einem
anderen Takt als der sys-Takt zählen soll? Natürlich hat dieser Zähler
im Component 2 Taktanschlüsse. sys_CLK und div_CLK.
Sollte das gehen?
Noch eine Frage an die Experten:
Wie kann man da sicher sein, dass dann diesen div_CLK im Design auch als
eine solcher speziellen Clock-Net geroutet wird??
Grüße Steffen
Steffen H. schrieb:> Natürlich hat dieser Zähler im Component 2 Taktanschlüsse.> sys_CLK und div_CLK.
Was ist div_CLK? Ein Ausgang?
> Noch eine Frage an die Experten:> Wie kann man da sicher sein, dass dann diesen div_CLK im Design auch als> eine solcher speziellen Clock-Net geroutet wird??
Indem du für abgeleitete Takte einen DCM (Taktmanager) nimmst.
> Sollte das gehen?
Zeig doch mal ein Beispiel, wie du das meinst...
>Was ist div_CLK? Ein Ausgang?
Ja, der div_CLK ist ein Ausgang und gleichzusetzen dem "enable" aus
obrigem Beispielcode.
> Wie kann man da sicher sein, dass dann diesen div_CLK im Design auch als> eine solcher speziellen Clock-Net geroutet wird??>Antwort: Indem du für abgeleitete Takte einen DCM (Taktmanager) nimmst.
Ich weiß nicht ob Lattice sowas hat. Ich arbeite mit einem Lattice XP
FPGA. Das hat 2 PLL-Module und vier (glaub ich) Clock-Select Module wo
man 2 Takt-Signale einspeist und die dann Umschalten kann ohne
irgendwelche Glitches zu bekommen.
>Zeig doch mal ein Beispiel, wie du das meinst...
Ein Beispiel hab ich noch nicht. Ich plane erst noch mein Design auf
Papier. Und da bin ich jetzt bei dem zu verwenden variabelen Takt
angekommen den ich in den Meisten Teilen meines Designs nutzen will um
bestimmte Aktionen auszuführen.
Heut abend oder morgen hab ich dann vielleicht auch schon mal ein wenig
Code.
Grüße Steffen
Hab das Gefühl, dass sobald man was von Lattice schreibt hier nix mehr
zurück kommt..
> Wie kann man da sicher sein, dass dann diesen div_CLK im Design auch als> eine solcher speziellen Clock-Net geroutet wird??>Antwort: Indem du für abgeleitete Takte einen DCM (Taktmanager) nimmst.
Bei Lattice XP heißen das übrigens DCS. Sind im XP 8 Stück vorhanden.
Man hat mehrere Modi zum einstellen. Also entweder zwischen 2
verschiedene Takten mit "SEL" umschalten, Takt abschalten, oder einfach
nur als Buffer. (siehe Bilder)
Im Beitrag TitelBeitrag "Mehrere Takte aus Referenztakt teilen (PLL)" hab
ich es dann noch folgendermaßen gesehen:
1
-- evtl. nötig, wenn die Synthese den neuen Takt nicht selber erkennt
2
-- attribute buffer_type: string;
3
-- attribute buffer_type of cdiv: signal is "bufg";
Ich glaube es hat weniger mit Lattice zu tun, als mit fehlenden
Zusatzinformationen, wie Beispielcode oder eine ausführliche
Beschreibung. Einfach mit den Signalnamen eines eigenen Designs um sich
werfen bringt einen nicht wirklich weiter ;)
Prinzipiell empfehle hier als ersten ein gutes Buch zum Thema VHDL und
etwaigen Design Guidelines vom entsprechenden FPGA-Hersteller. Hier
scheint es dem ein oder anderen am Verständnis der Beschreibungssprache
und der resultierenden Hardwarestruktur zu mangeln ... was ich
prinzipiell nicht verurteile. Jeder fängt mal an. Allerdings
disqualifiziert man sich selbst, wenn noch nicht einmal die Grundlagen
vorhanden sind!
@Steffen H.
Was die Sache mit einem enable für 2 Clock-Domains angeht. Hier solltest
du dir sicher sein, das beide Domains aufeinander einsychronisiert sind.
So etwas macht man für gewöhnlich über mehrere Sync-Stages.
Metastabilität ist ein weiteres Stichwort.
>Ich glaube es hat weniger mit Lattice zu tun, als mit fehlenden>Zusatzinformationen, wie Beispielcode oder eine ausführliche>Beschreibung. Einfach mit den Signalnamen eines eigenen Designs um sich>werfen bringt einen nicht wirklich weiter ;)
Ich hab noch keinen Code getippt, da ich erstmal alles auf papier male
und mir sozusagen schon vorher Gedanken drüber mache, ob es so überhaupt
geht oder wie ich es überhaupt realisieren möchte/kann. Ich häng mal
meine Skizze mit an.
>Prinzipiell empfehle hier als ersten ein gutes Buch zum Thema VHDL
Hehe, das bekomm ich erst zu Weihnachten ;)
>Was die Sache mit einem enable für 2 Clock-Domains angeht. Hier solltest>du dir sicher sein, das beide Domains aufeinander einsychronisiert sind.>So etwas macht man für gewöhnlich über mehrere Sync-Stages.>Metastabilität ist ein weiteres Stichwort.
Ich glaube, da haben wir uns falsch verstanden. Das "enable" ist gleich
dem "ce" aus hier schon oft angegebenen anderen Designs wo es um
Taktteilung ging die syncron laufen sollen. Nach dem Motto:
Component Taktteiler:
1
entityTaktteileris
2
Port(
3
CLK:instd_logic;
4
enable:outstd_logic);
5
endTaktteiler;
6
7
architectureVerhaltenofTaktteileris
8
9
constantcnt_div:integer:=16;-- Teilerverhältnis
10
signalcnt:integerrange0tocnt_div-1;-- Zähler für Teiler
11
signalce:std_logic;
12
13
begin
14
15
process(clk)-- Clock Enable Generator
16
begin
17
ifrising_edge(clk)then
18
ifcnt=cnt_div-1then
19
enable<='1';
20
cnt<=0;
21
else
22
enable<='0';
23
cnt<=cnt+1;
24
endif;
25
endif;
26
endprocess;
27
enable<=ce;
28
29
endVerhalten;
Das "enable" kommt vom Taktteiler, einer anderen Component. Und hier
z.B. in wieder einer anderen Component wird er genutzt.
1
entityIRGENDWASis
2
Port(
3
CLK:instd_logic;
4
enable:instd_logic);
5
endIRGENDWAS;
6
7
architectureVerhaltenofIRGENDWASis
8
begin
9
10
process(clk)
11
begin
12
ifrising_edge(clk)then
13
ifenable='1'then
14
15
-- Aktionen hier einfügen, welche mit langsamen Takt laufen
Hier mal ein anderer Ansatz.
Component "ClockManager" Ich weiß nur noch nicht so Recht wie ich das
umsetzen soll.
Die PLL ist kein Problem. Da gibt es ja den CoreGen.
Clock_Div:
Dies soll ein variabeler Counter werden der mit dem Prescaler
eingestellt wird. Der Prescaler soll mal von einer anderen Component
"Serial_Interface" zur Verfühgung gestellt werden. "update" kommt
ebenfalls daher. Es ist für genau einen "sys_CLK" auf '1' wenn ein neuer
"Prescaler" durch das ser.Interface zur Verfühgung steht. Damit will ich
sicherstellen, dass ein neuer Divider-Wert erst übernommen wird, wenn
der resultierende "div_CLK" von 1->0 geht. Der "RESET" Eingang ist mit
dem LOOK der PLL verbunden um sicherzustellen, dass erst nach hochfahren
der PLL der Counter anfängt zu laufen und auch durch LOOK resetet wird.
DCS:
DCS sollte wieder über den CoreGen zu bewerkstelligen sein. Hoffe ich
jedenfalls mal. Der Enable Anschluss "en_CLK" ist zum Abschalten der
"var_CLK" gedacht, da ich bestimmte Teilprozesse nicht ständig am laufen
haben will die mit dem "var_CLK" getaktet werden sollen. Der DSC routet
mir vor allem den "var_CLK" auf ein CLOCK-NET. Zumindest hab ich das so
aus dem Datasheet herausgelesen.
Was sagt ihr zu diesen Ansatz?
Grüße Steffen
Ach ja, nicht wundern mit dem RST bei der PLL. Steht ebenfalls so im
Datasheet.
The PLL reset occurs under two conditions. At power-up an internal
power-up reset signal from the configuration block resets the PLL. The
user controlled PLL reset signal RST is provided as part of the PLL
module that can be driven by an internally generated reset function or a
pin. This RST signal resets all internal PLL counters.
Note: For LatticeECP/EC, RST must be asserted to re-start the locking
process after losing lock. Refer to the LatticeECP/EC Family Data Sheet
for the RST pulse width requirement. For LatticeXP, RST may be tied to
GND.
Ich hab das Datenblatt nur mal schnell überflogen. So wie es scheint ist
ein DCS nichts anderes als ein Multiplexer für 2 Clocks. So wie es in
deinem Design aussieht willst du ein selbst erzeugtes Signal (div_CLK)
als Eingang für eine solche DCS nehmen. Ich habe große Zweifel ob das
überhaupt funktioniert. Meines Wissens kann ein Clocknet nur über
dedizierte Takteingänge gespeist werden. Ein beliebiges Signal an einer
PLL bzw. als Taktquelle sollte der Compiler als Fehler quittieren. Aber
ich kann mich auch irren. So tief ist mein Wissen dann wieder auch nicht
:)
Wenn du wirklich einen variablen Takt in einem System brauchst, dann
solltest du mal prüfen ob die PLLs auch während des Betriebs
umkonfiguriert werden können. Bei Altera ist das z.B. möglich. Wenn ich
das noch richtig im Kopf habe.
Frage: Wofür brauchst du diesen variablen Takt überhaupt? Sollen damit
andere Teile des Designs betrieben werden oder geht der Takt nur auf
einen Ausgangstreiber?
>Wenn du wirklich einen variablen Takt in einem System brauchst, dann>solltest du mal prüfen ob die PLLs auch während des Betriebs>umkonfiguriert werden können.
Die PLL kann man umkonfigurieren. Aber der ClockDivider hat da auch so
seine Grenzen und ist deshalb nicht brauchbar für meinen gewollten
variablen Takt. Der Teilt bloß in 2er Schritten und das bloß bis 30.
Siehe:
The CLKOP Divider values are 2, 4, 6, 8,..32 (2, 4, 6, 8..30 for
LatticeXP devices) if CLKOS is not used. The CLKOP Divider values are 2,
4, 8, 16, 32 (2, 4, 8, 16 for LatticeXP devices) if CLKOS is used. Und
den mit der PLL erzeugte System Takt "sys_CLK" von 100 Mhz brauch ich
zusätzlich im System.
>Frage: Wofür brauchst du diesen variablen Takt überhaupt? Sollen damit>andere Teile des Designs betrieben werden oder geht der Takt nur auf>einen Ausgangstreiber?
Der soll nacher mal mein Sample- oder Recordingtakt werden. Das heißt,
ein Trigger, das Data-pre-Register und der Adresszähler für das interne
Dualport Blockram sollen sollen damit versorgt werden.
Ich werd nochmal überprüfen mit welchen Signalen ich den DCS versorgen
kann.
Gruß
Steffen
>So wie es in deinem Design aussieht willst du ein selbst erzeugtes Signal >(div_CLK) als Eingang für eine solche DCS nehmen. Ich habe große Zweifel ob >das
überhaupt funktioniert. Meines Wissens kann ein Clocknet nur über >dedizierte
Takteingänge gespeist werden. Ein beliebiges Signal an einer
>PLL bzw. als Taktquelle sollte der Compiler als Fehler quittieren.
Ich glaube es geht. Wenn man sich mal das primäre Clock Net anschaut,
kann man wie ich das sehe auch vom general Routing zu den DCS gelangen.
Oder irre ich mich da?
Steffen H. schrieb:> Der soll nacher mal mein Sample- oder Recordingtakt werden. Das heißt,> ein Trigger, das Data-pre-Register und der Adresszähler für das interne> Dualport Blockram sollen sollen damit versorgt werden.
Warum nimmst du nicht einfach einen festen Takt und regelst das über
Enable-Signale?
Steffen H. schrieb:> Ich glaube es geht. Wenn man sich mal das primäre Clock Net anschaut,> kann man wie ich das sehe auch vom general Routing zu den DCS gelangen.> Oder irre ich mich da?
Stimmt, sie tatsächlich danach aus. Versuch macht klug :)
Verwende doch enable Signale anstatt den Takt wirklich runter zu teilen
(wie in meinem Beispiel und dem von Steffen). Vorteil der Enable
Signale: Alles arbeitet synchron mit einem Takt und du ersparst dir die
Taktübergänge, die eine potentielle Fehlerquelle in der realen Hardware
sind. Natürlich kann man chip enables auch problemlos beliebig oft
kaskadieren, was bei Gated Clocks Probleme bringen kann.
Ob Lattice, Xilinx, Altera und was auch immer ist egal. Chip enables
werden meist nativ von den Zellen unterstützt und sind somit meist die
beste Lösung.
Hallo und einen schönen 3.Advent
Ich hab mich mal an meinen CLOK_DIV herangewagt. Hab es jetzt
Tatsächlich über Clock-enable gemacht. Laut Simulation scheint es zu
funktionieren. Wäre schön, wenn nochmal jemand über den Code schauen
könnte und eventuell Fehler entdeckt weil man das einfach so nicht macht
wie ich es lösen will.
when"10100"=>cnt_div<=4000000-1;-- 20 | 20 hz | 1 s
63
when"10101"=>cnt_div<=8000000-1;-- 21 | 10 hz | 2 s
64
when"10110"=>cnt_div<=20000000-1;-- 22 | 4 hz | 5 s
65
whenothers=>
66
endcase;
67
else
68
ifcnt=cnt_divthen-- Wenn cnt = Teilerwert
69
cnt<=0;
70
ce<='1';
71
else
72
cnt<=cnt+1;
73
ce<='0';
74
endif;
75
endif;
76
endif;
77
endif;
78
endprocess;
79
80
81
process(CLKIN)-- Enable CLKCE out
82
begin
83
ifrising_edge(CLKIN)then
84
ifen_CLK='1'then
85
CLKCE<=ce;
86
else
87
CLKCE<='0';
88
endif;
89
endif;
90
endprocess;
91
92
endVerhalten;
Zur Beschreibung:
Die Taktteilung soll über CLKCE im weiteren System erfolgen. Es kommen
also für genau einen Haupttakt (CLKIN) CLKCE Impulse die abhängig vom
gewählten Prescaler PRESC ein bestimmtes Pausenverhältnis haben. CLKCE
wird wenn en_CLK = 1 ist ausgegeben.
Über UPDATE wird ein neuer Prescaler übernommen.
Was sagt ihr zu dieser Lösung?
Grüße
Steffen
Sieht soweit ganz fernünftig aus. Den zweiten Prozess könntest du dir
eigentlich sparen und durch ein Concurrent Statement erreichen.
1
CLKCE<=cewhenen_CLK='1'else'0';
Einfach innerhalb des architecture body schreiben. Also außerhalb des
Pozesses. Muss man nicht so machen, erspart aber die zusätzliche
Pufferung und somit die Verzögerung am Ausgang.