Forum: FPGA, VHDL & Co. Frequenzteiler 1:1000


von Martin S. (akandra)


Lesenswert?

Hallo liebe Community,

wie viele bin auch ich ein Frischling im VHDL und arbeite im Moment an 
einem einfachen Frequenzteiler 1:1000 der mir ein 1Mhz Takt in einen 
1kHz Signal umwandelt.
Laut Simmulation funktioniert es wie gewollt, allerdings hab ich lange 
wegen dem Counter herumprobieren müssen. Gibt es eventl. eine elegantere 
Lösung oder kann mein Code zu Problemen führen?

Vielen Dank für eure Hilfe und Zeit :)


Mfg
Martin

1
LIBRARY IEEE;
2
USE IEEE.std_logic_1164.all;
3
USE IEEE.std_logic_unsigned.all;
4
5
ENTITY clkgen IS
6
    PORT (
7
        clk_1us: IN STD_LOGIC;
8
        reset: IN STD_LOGIC;
9
        clk_1ms: OUT STD_LOGIC
10
    );
11
end clkgen;
12
13
14
ARCHITECTURE count_1k OF clkgen IS
15
    SIGNAL counter: STD_LOGIC_VECTOR(9 DOWNTO 0);
16
BEGIN
17
    PROCESS(clk_1us, reset)
18
    BEGIN
19
        
20
        IF (reset = '0') THEN                        -- asynchroner Reset
21
         counter <= (others => '0');
22
         clk_1ms <= '0';
23
            
24
        ELSIF (rising_edge(clk_1us)) THEN
25
            
26
            IF (counter < "1111100111") THEN         -- hochzählen bis 999
27
               counter <= counter + 1;
28
            ELSE                                     -- Zurücksetzen auf 0
29
               counter <= (others => '0');
30
            END IF;
31
                        
32
            IF (counter < "0111110100") THEN         -- '1' für counter < 499
33
               clk_1ms <= '1';
34
            ELSE                                     -- '0' sonst
35
                clk_1ms <= '0';
36
            END IF;
37
            
38
        END IF;
39
                    
40
    END PROCESS;
41
END ARCHITECTURE count_1k;

von Iulius (Gast)


Lesenswert?

>> kann mein Code zu Problemen führen?

wenn du den erzeugten Takt wirklich als Takt weiterverwendest, ja.


machs doch stattdessen so :

clk_1ms <= '1' when counter = '1111100111' else '0'

außerhalb des process, also als concurrent statement
und dann bei der Verwendung :

if rising_edge(clk_1us) then
 if clk_1ms = '1'
...


Das wäre ein klassisches enable.

von Michael O. (mischu)


Lesenswert?

1MHz sind nicht schnell in aktuellen Bauteilen, daher bekommst Du noch 
nicht die klassischen Probleme der Laufzeiten.

Deine Version mit einer Prüfung ">", "<" ist tunlichst zu vermeiden!
Das produziert einen deutlichen Aufwand an Logik. Um ein arithmetisches 
Größer zu prüfen, muss man z.B. die Zahlen voneinander subtrahieren und 
das Ergebnis auf >0 prüfen. Das bedeutet, dass neben dem Zähler noch 
weiter Volladierer benötigt werden.

Möchtest Du ein 1kHz Rechtecksignal erzeugen, so nimm einen Zähler bis 
500 und lass dein Ausgangssignal toggeln. Das Ende des Zählvorgangs 
prüfst Du mit einem "=".

SIGNAL   count_1khz : std_logic;
SIGNAL   count_exp  : STD_LOGIC;
SIGNAL   count      : STD_LOGIC_VECTOR(9 DOWNTO 0);
CONSTANT count_RLD  : STD_LOGIC_VECTOR(count'range):(others =>'0');
CONSTANT count_END  : STD_LOGIC_VECTOR(count'range):="0111110100";

if (rising_edge (clock)) then
   if(count_exp = '1') then
       count_1khz <= not count_1khz;
       count <= count_RLD;
   else
       count <= count +1;
   endif;
endif;

count_exp <= '1' when count = count_END else '0';

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


Lesenswert?

Oder so:
1
LIBRARY IEEE;
2
USE IEEE.std_logic_1164.all;
3
USE IEEE.std_logic_unsigned.all;
4
5
ENTITY clkgen IS
6
    PORT (
7
        clk_1us: IN STD_LOGIC;
8
--        reset: IN STD_LOGIC; -- wozu ein Reset?
9
        clk_1ms: OUT STD_LOGIC
10
    );
11
end clkgen;
12
13
ARCHITECTURE count_1k OF clkgen IS
14
    SIGNAL counter: integer range 0 to 499 := 0;
15
    signal clk1ms: STD_LOGIC := '0';
16
BEGIN
17
    PROCESS(clk_1us)
18
    BEGIN
19
        IF (rising_edge(clk_1us)) THEN
20
            IF (counter < 499) THEN         -- hochzählen bis 499
21
               counter <= counter + 1;
22
            ELSE                            -- Zurücksetzen auf 0
23
               counter <= 0;
24
               clk1ms <= not clk1ms;
25
            END IF;
26
        END IF;
27
    END PROCESS;
28
    clk_1ms <= clk1ms;
29
END ARCHITECTURE count_1k;
Das gibt einen 50% Takt.
Der macht allerdings innerhalb eines CPLDs oder FPGAs keinen Sinn. Dort 
arbeitet man mit 1 Mastertakt und Clock-Enables. Und das wäre dann mein 
Ansatz:
1
ARCHITECTURE count_1k OF clkgen IS
2
    SIGNAL counter: integer range 0 to 999 := 0;
3
BEGIN
4
    PROCESS(clk_1us)
5
    BEGIN
6
       wait until rising_edge(clk_1us);
7
       IF (counter < 999) THEN
8
           counter <= counter + 1;
9
           clken_1ms <= '0';
10
        ELSE              
11
           counter <= 0;
12
           clken_1ms <= '1';
13
        END IF;
14
    END PROCESS;
15
END ARCHITECTURE count_1k;

EDIT:
@ mischu
> Deine Version mit einer Prüfung ">", "<" ist tunlichst zu vermeiden!
> Das produziert einen deutlichen Aufwand an Logik.
Das solltest du dir aber noch mal ansehen...
Ich habe das auch mal geglaubt. Aber in der Tat ist es so, dass nur 
selten mehr Logik verbraucht wird.

von Martin S. (akandra)


Lesenswert?

Vielen Dank, das hilft mir auf jeden Fall!

Noch dazu:
> Das gibt einen 50% Takt.
> Der macht allerdings innerhalb eines CPLDs oder FPGAs keinen Sinn. Dort
> arbeitet man mit 1 Mastertakt und Clock-Enables.

Ich stelle mit der Funktion den Haupttakt zu Verfügung, da ich einen 
1Mhz Oszillator habe, aber der "Mastertakt" bei 1kHz sein soll.

von Michael O. (mischu)


Lesenswert?

@Martin
Nur VHDL oder einer idealen Simulation macht es keinen Unterschied, ob 
Du Dein 1kHz Signal als Clockquelle nimmst, oder 1MHz mit einem 1kHz 
Enablepuls.
Auf der konkreten Hardware sieht dies häufig anders aus.
Clocksignale sind sehr kritisch bezüglich Flankensteilheit, Jitter und 
Laufzeiten. Daher sind in CPLDs/FPGAs sogenannte Clocknetzwerke 
aufgebaut. Das sind spezielle Leitungen die zum Verteilen eines Taktes 
an möglichst alle FlipFlops genutzt werden können. Leider gibt es davon 
nur sehr wenige Leitungen (so etwa 2-16 je nach Baustein).
Man nimmt gerne eine dieser Leitungen, um dem gesammten Chip einen 
Mastertakt vorzugeben. Sofern Du nur wenig Logik mit dem 1kHz Signal 
ansteuern willst, nur lokal geroutet wird. Wie gesagt, bei 1kHz wird es 
noch keine Probleme geben. Wenn Du aber morgen auf deutlich höhere 
Frequenzen umsteigst, wirst Du dich wundern.

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


Lesenswert?

Martin Spider schrieb:
> Ich stelle mit der Funktion den Haupttakt zu Verfügung, da ich einen
> 1Mhz Oszillator habe, aber der "Mastertakt" bei 1kHz sein soll.
Dann nimm besser den 1 MHz als Mastertakt und lass alles andere über 
Clock-Enables laufen. Die Stromaufnahme steigt dadurch nicht 
(signifikant), weil ja trotz des hohen Mastertaktes die FFs nur im 1 kHz 
Takt umgeschaltet werden.

von theo (Gast)


Lesenswert?

Hätte da auch mal ne Frage:
Wie verhält sich das den im Quellcode vom Lothar Miller, mit den 
vorbelegten Signalen auf 0?
Ist es nicht so, dass man dies vermeidet, da es ansonsten nicht 
synthesefähig ist?

Laß mich da gern eines besseren belehren.

von Iulius (Gast)


Lesenswert?

welcher Teil soll nicht synthesefähig sein ?


die Initialisierung des Integer auf 0 ist kein Problem, im FPGA starten 
eh alle FFs mit den Werten die man angibt, egal was.

Bei ASICs ist das ggf anders, vielleicht hast das von dort aufgeschnappt 
?

von theo (Gast)


Lesenswert?

Achso und demnach ist es dann auch bei dem weiter oben benannten Signal 
okay?:
signal clk1ms: STD_LOGIC := '0';

Wieder was gelernt.

von D. I. (Gast)


Lesenswert?

Lothar Miller schrieb:
> Martin Spider schrieb:
>> Ich stelle mit der Funktion den Haupttakt zu Verfügung, da ich einen
>> 1Mhz Oszillator habe, aber der "Mastertakt" bei 1kHz sein soll.
> Dann nimm besser den 1 MHz als Mastertakt und lass alles andere über
> Clock-Enables laufen. Die Stromaufnahme steigt dadurch nicht
> (signifikant), weil ja trotz des hohen Mastertaktes die FFs nur im 1 kHz
> Takt umgeschaltet werden.

Da hätte ich noch eine Frage.
Angenommen ich hätte einen 200MHz Takt aber mir würde es reichen wenn 
alles mit 100MHz läuft, dann kann ich ja überall mit CE arbeiten.
"Merkt" die Synthese bzw. das P&R dass ich nur mit 100MHz arbeiten will? 
Ich frage in Hinblick auf Static Timing Constraints usw. da es manchmal 
doch recht knifflig ist so wenig Logikstufen wie möglich zu haben um 
nicht zu langsam zu werden.

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


Lesenswert?

> "Merkt" die Synthese bzw. das P&R dass ich nur mit 100MHz arbeiten will?
Das kommt darauf an...
> Ich frage in Hinblick auf Static Timing Constraints
Dafür gibt dann "Multi Cycle Constraints", dort gibst du z.B. an, dass 
eine FSM das Ergebnis der Logik erst 2 Takte später braucht.

Aber 200MHz auf dem ganzen Design sind grenzwertig. Da wäre bei Xilinx 
ein DCM das Richtige, um die hohe Frequenz auf 100MHz herunterzusetzen. 
Takte, die über den DCM verwaltet werden, können dann auch von der 
Toolchain richtig in die Timing Constraints eingerechnet werden.

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


Lesenswert?

> vorbelegten Signalen auf 0?
> Ist es nicht so, dass man dies vermeidet, da es ansonsten nicht
> synthesefähig ist?
Nicht alle Tools können beliebige Vorgabewerte umsetzen (Xilinx kanns), 
aber 0 ist ein Defaultwert bei allen SRAM-basierten FPGAs.
Für andere Werte gilt: einfach ausprobieren  ;-)

Vorbelegt werden können natürlich nur getaktete Signale, denn nur dort 
ist ein Speicherglied beteiligt. Kombinatorische Signale werden sowieso 
sofort aus den Eingangswerten neu berechnet:
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.NUMERIC_STD.ALL;
4
5
entity Test is
6
    Port ( i1  : in  STD_LOGIC;
7
           i2  : in  STD_LOGIC;
8
           i3  : in  STD_LOGIC;
9
           o1  : out  STD_LOGIC;
10
           o2  : out  STD_LOGIC;
11
           o3  : out  STD_LOGIC := '1';
12
           clk : in  STD_LOGIC);
13
end Test;
14
15
architecture Behavioral of Test is
16
signal o2c : std_logic := '1';
17
begin
18
   o1 <= i1;
19
20
   process begin
21
      wait until rising_edge(clk);
22
      o2c <= i2;
23
   end process;
24
   o2 <= o2c;
25
26
   process begin
27
      wait until rising_edge(clk);
28
      o3 <= i3;
29
   end process;
30
end Behavioral;
o1 kann (weil kombinatorisch) natürlich nicht vorbelegt werden.
o2 kann ebenfalls nicht vorbelegt werden. Allerdings gibt es ein lokales 
Signal o2c, das initialsiert werden kann.
o3 kann direkt vorbelegt werden.

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.