Forum: FPGA, VHDL & Co. Frequenzteiler


von M. N. (marco2228)


Lesenswert?

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;
______________________________________________________________________ 
_

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

In welchem Buch hast du solche Konstrukte schon mal gesehen?
1
  if reset ='1' then
2
    f10m <= "0000";
3
  else
4
    if rising_edge(takt) then
5
      if f10m = 4 then
6
        f10m <="0000";
7
      else
8
        f10m <= f10m + 1;
9
      end if;
10
    else        -- !!!! Was soll denn das? Wenn keine steigende Taktflanke?
11
      f10m <= f10m;
12
    end if;
13
  end if;


Auch das ist eher selten zu sehen:
1
    if rising_edge(takt) and ci10='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
  use ieee.numeric_std.all;
2
  :
3
  :
4
  signal c1, c10, c100 : integer range 0 to 9 := 0;
5
  :
6
  -- Einer
7
  process begin
8
     wait until rising_edge(clk);
9
     led1 <= '0';
10
     if (c1 < 9) then 
11
        c1 <= c1 + 1;
12
     else             
13
        c1 <= 0;
14
        led1 <= '1';
15
     end if;
16
  end process;
17
  
18
  -- Zehner
19
  process begin
20
     wait until rising_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
        end if;
29
     end if;
30
  end process;
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!!

von M. N. (marco2228)


Lesenswert?

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
 process begin
2
  wait until rising_edge(clk);
3
  clk_2 <= '0';  
4
  if (c10>4) then 
5
    clk_2 <= '1';
6
  else
7
    clk_2 <= '0';
8
  end if;
9
end process;

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.

von Sym (Gast)


Lesenswert?

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.

von M. N. (marco2228)


Lesenswert?

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?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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?

von Sym (Gast)


Lesenswert?

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.
1
constant c_div : integer := 1000;
2
3
signal div : integer range 0 to c_div-1;
4
signal enable : std_logic;
5
6
-- process to divide clock
7
p_mydivider : process (clk, rst)
8
begin
9
  if rst = '0' then
10
    div <= 0;
11
    enable <= '0';
12
  elsif clk'event and clk = '1' then
13
    enable <= '0';
14
    if div /= 0 then
15
      div <= div - 1;
16
    else
17
      div <= c_div - 1;
18
      enable <= '1';
19
    end if;
20
  end if;
21
end process p_mydivider;
22
23
24
--process with virtually divided clock
25
p_slow: process (clk, rst)
26
begin
27
  if rst = '0' then 
28
  elsif clk'event and clk = '1' then
29
    if enable = '1' then
30
      -- your code here
31
    end if;
32
  end if;
33
end process p_slow;

von M. N. (marco2228)


Lesenswert?

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

von Steffen H. (avrsteffen)


Lesenswert?

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

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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

von Steffen H. (avrsteffen)


Lesenswert?

>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

von Steffen H. (avrsteffen)


Angehängte Dateien:

Lesenswert?

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 Titel Beitrag "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";

von mac4ever (Gast)


Lesenswert?

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.

von Steffen H. (avrsteffen)


Lesenswert?

>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
entity Taktteiler is
2
   Port(
3
       CLK    : in std_logic;
4
       enable : out std_logic);
5
end Taktteiler;
6
7
architecture Verhalten of Taktteiler is
8
9
constant cnt_div : integer:=16;                   -- Teilerverhältnis
10
signal   cnt     : integer range 0 to cnt_div -1; -- Zähler für Teiler
11
signal   ce      : std_logic;
12
13
begin 
14
15
  process(clk) -- Clock Enable Generator 
16
  begin
17
    if rising_edge(clk) then
18
      if cnt = cnt_div -1 then
19
        enable  <= '1';
20
        cnt <= 0;
21
      else
22
        enable  <= '0';
23
        cnt <= cnt +1 ;
24
      end if;
25
    end if;
26
  end process;
27
enable <= ce;
28
29
end Verhalten;

Das "enable" kommt vom Taktteiler, einer anderen Component. Und hier 
z.B. in wieder einer anderen Component wird er genutzt.
1
entity IRGENDWAS is
2
   Port(
3
       CLK    : in std_logic;
4
       enable : in std_logic);
5
end IRGENDWAS;
6
7
architecture Verhalten of IRGENDWAS is
8
begin
9
10
process(clk)
11
begin
12
  if rising_edge(clk) then
13
    if enable='1' then
14
 
15
    -- Aktionen hier einfügen, welche mit langsamen Takt laufen
16
    -- ***1
17
 
18
    end if;
19
  end if;
20
end process;
21
22
end Verhalten;
Sollte das so gehen?

Grüße Steffen

von Steffen H. (avrsteffen)


Angehängte Dateien:

Lesenswert?

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

von Steffen H. (avrsteffen)


Lesenswert?

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.

von mac4ever (Gast)


Lesenswert?

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?

von Steffen H. (avrsteffen)


Lesenswert?

>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

von Steffen H. (avrsteffen)


Angehängte Dateien:

Lesenswert?

>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?

von mac4ever (Gast)


Lesenswert?

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 :)

von Sym (Gast)


Lesenswert?

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.

von Steffen H. (avrsteffen)


Angehängte Dateien:

Lesenswert?

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.
1
library ieee;
2
use ieee.std_logic_1164.all;
3
--use ieee.std_logic_arith.all;
4
use ieee.std_logic_unsigned.all;
5
use ieee.numeric_std.all;
6
7
entity CLOCK_DIV is
8
9
port( 
10
  CLKIN    : in std_logic ; -- 100Mhz kommt von PLL
11
  UPDATE    : in std_logic ; -- Impuls 1 Taktzyklus lang
12
  RST    : in std_logic ; -- kommt von LOOK der PLL
13
  en_CLK    : in std_logic ; -- Enable CLKCE out
14
  PRESC    : in std_logic_vector ( 4 downto 0 ); -- Prescaler
15
  CLKCE    : out std_logic  ); -- Clock enable (chip enable)
16
17
end;
18
19
architecture Verhalten of CLOCK_DIV is
20
21
22
signal  cnt_div  : integer range 0 to 20000000-1;  -- Teilerverhältnis
23
signal  cnt  : integer range 0 to 20000000-1; -- Zähler für Teiler
24
signal  ce      : std_logic := '0';
25
26
27
begin
28
29
30
31
process(CLKIN,RST) -- Clock Enable Generator 
32
  begin
33
    if RST = '1' then  -- asynchroner Reset: = LOOK und kommt von PLL
34
       ce <= '0';
35
       cnt <= 0;
36
    else
37
      if rising_edge(CLKIN) then
38
         if UPDATE ='1' then
39
      cnt <= 0;
40
      ce <= '1';
41
      case PRESC is --                        PRESC|fSAMPLE | t/div
42
      when "00000" => cnt_div <=        0;   --  0 |  80Mhz | 250ns  
43
      when "00001" => cnt_div <=        2-1; --  1 |  40Mhz | 500ns
44
      when "00010" => cnt_div <=        4-1; --  2 |  20Mhz |   1µs
45
      when "00011" => cnt_div <=        8-1; --  3 |  10Mhz |   2µs
46
      when "00100" => cnt_div <=       20-1; --  4 |   4Mhz |   5µs
47
      when "00101" => cnt_div <=       40-1; --  5 |   2Mhz |  10µs
48
      when "00110" => cnt_div <=       80-1; --  6 |   1Mhz |  20µs
49
      when "00111" => cnt_div <=      200-1; --  7 | 400khz |  50µs
50
      when "01000" => cnt_div <=      400-1; --  8 | 200khz | 100µs
51
      when "01001" => cnt_div <=      800-1; --  9 | 100khz | 200µs
52
      when "01010" => cnt_div <=     2000-1; -- 10 |  40khz | 500µs
53
      when "01011" => cnt_div <=     4000-1; -- 11 |  20khz |   1ms
54
      when "01100" => cnt_div <=     8000-1; -- 12 |  10khz |   2ms
55
      when "01101" => cnt_div <=    20000-1; -- 13 |   4khz |   5ms
56
      when "01110" => cnt_div <=    40000-1; -- 14 |   2khz |  10ms
57
      when "01111" => cnt_div <=    80000-1; -- 15 |   1khz |  20ms
58
      when "10000" => cnt_div <=   200000-1; -- 16 | 400 hz |  50ms
59
      when "10001" => cnt_div <=   400000-1; -- 17 | 200 hz | 100ms
60
      when "10010" => cnt_div <=   800000-1; -- 18 | 100 hz | 200ms
61
      when "10011" => cnt_div <=  2000000-1; -- 19 |  40 hz | 500ms
62
      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
      when others =>
66
      end case;
67
   else
68
           if cnt = cnt_div then  -- Wenn cnt = Teilerwert
69
              cnt <= 0;
70
        ce <= '1';
71
          else
72
              cnt <= cnt +1 ;
73
        ce <='0';
74
          end if;
75
  end if;
76
      end if;
77
    end if;
78
  end process;
79
80
81
process(CLKIN) -- Enable CLKCE out
82
  begin
83
  if rising_edge(CLKIN) then
84
    if en_CLK = '1' then
85
    CLKCE <= ce;
86
    else
87
    CLKCE <= '0';
88
    end if;
89
  end if;
90
  end process;
91
92
end Verhalten;
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

von mac4ever (Gast)


Lesenswert?

Sieht soweit ganz fernünftig aus. Den zweiten Prozess könntest du dir 
eigentlich sparen und durch ein Concurrent Statement erreichen.
1
CLKCE <= ce when en_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.

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.