Forum: FPGA, VHDL & Co. Frequenzteiler durch gerade Zahlen


von Mattias (Gast)


Lesenswert?

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

von Ines (Gast)


Lesenswert?

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.

von Ines (Gast)


Lesenswert?

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

von Mattias (Gast)


Lesenswert?

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

von Ines (Gast)


Lesenswert?

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

von Mattias (Gast)


Lesenswert?

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

von Ines (Gast)


Lesenswert?

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

von Falk (Gast)


Lesenswert?

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

von Mattias (Gast)


Lesenswert?

Hallo Frank,
was meinst Du damit, wenn man es richtig macht. Könntest Du mal ein 
Beispiel bringen ?

Mattias

von Falk (Gast)


Lesenswert?

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.




von Christoph db1uq K. (christoph_kessler)


Angehängte Dateien:

Lesenswert?

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.

von Christoph db1uq K. (christoph_kessler)


Angehängte Dateien:

Lesenswert?

hier noch die 2.Seite mit der Funkrtionsbeschreibung.

von Mattias (Gast)


Lesenswert?

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

von Falk (Gast)


Lesenswert?

Das bleibt die aufgabe für den engagierten 
Basterl/Studenten/wasauchimmer.

;-)

MfG
Falk

von tosten (Gast)


Lesenswert?

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?

von tosten (Gast)


Lesenswert?

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;

von T.M. (Gast)


Lesenswert?

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;

von T.M. (Gast)


Lesenswert?

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

von Falk (Gast)


Lesenswert?

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

von Jonas (Gast)


Lesenswert?

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?

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


Lesenswert?

@ 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

von Jonas (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.