Forum: FPGA, VHDL & Co. Variabler Clockdivider in Verilog


von Stefan A. (king-crash)


Angehängte Dateien:

Lesenswert?

Hallo,

ich habe für einen Cyclone5 einen variablen Clockdivider geschrieben, 
der leider nur bei statischer Vorgabe funktioniert.
Die Idee ist, ich habe einen Divider den ich über eine extern anlegbares 
Bitmuster steuern kann.
Als Anhang habe ich die zwei verwendeten Dateien.
Das Ganze funktioniert, sobald ich in fpgatest.v:15 eine feste Zahl 
anstatt der Speicherzelle vorgebe, was allerdings nicht Sinn und Zweck 
der Sache ist. Der Crux ist dass es in der Simulation funktioniert. Wenn 
ich es aber auf den FPGA spiele bekommt der Divider immer 0 als 
Divisionswert.

Hat jemand eine Idee was ich da falsch mache?

von Duke Scarring (Gast)


Lesenswert?

Stefan A. schrieb:
> Die Idee ist, ich habe einen Divider den ich über eine extern anlegbares
> Bitmuster steuern kann.
Ok. Was willst Du mit dem resultierenden Takt anstellen?

Duke

von Vancouver (Gast)


Lesenswert?

Hm, Du deklarierst ein Register, das initial den Wert 2000 bekommt und 
sonst nicht mehr verändert wird. Sprich, es ist eigentlich kein 
Register. Das sollte zumindest eine Warning geben. Woher weißt Du, dass 
divider immer 0 bleibt? Pack das Register mal in ein sequential 
statement und schreib in jedem Takt 2000 hinein.

von Stefan A. (king-crash)


Lesenswert?

Das Ganze ist aus einem größeren Projekt, das einen konfigurierbaren 
UART mit CRC hat. Dort kann man über ein Dual Port RAM vom Prozessor aus 
Transferlänge und Clock einstellen.
Ich bin sicher, dass dort 0 steht, weil ohne das "if(divider == 0" kein 
takt mehr kommt weil "if(divider /2 -1) -> 0/2 -1 = 0xFFFF und der 
SignalTap Logic Analyzer von Quartus sagt das Gleiche.

von Stefan A. (king-crash)


Lesenswert?

Die Idee mit jeden Takt was reinschreiben war nicht schlecht.
Ich habe folgendes hinzugefügt:
1
always @ (posedge FPGA_CLK1_50)
2
  begin
3
  if(divider == 0)
4
    divider <= 1000;
5
  end
Und siehe da, ein Takt am Ausgang.
Allerdings nicht der für divider <= 1000, sondern divider <= 2000, wie 
bei initial.
Gibt es da Optimizer, die Amok laufen können?

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


Lesenswert?

Stefan A. schrieb:
> clock_out <= ~clock_out;
> Hat jemand eine Idee was ich da falsch mache?
Du erzeugst Takte, wo du mit Clock-Enables arbeiten müsstest. Das ist 
aber ein eher generelles Problem...

Stefan A. schrieb:
> Das Ganze ist aus einem größeren Projekt, das einen konfigurierbaren
> UART mit CRC hat. Dort kann man über ein Dual Port RAM vom Prozessor aus
> Transferlänge und Clock einstellen.
Dann musst du diesen Teil mit dem DPRAM auch noch implementieren. Durch 
das Weglassen dieses Interfaces beobachtest du hier ein simples 
"Wegoptimieren": weil du das Register divider nie verwendest (in Form 
von "verändern"), wird es hinfortoptimiert. Du solltest den Synthesizer 
zwingen, indem du z.B. einen Reset für divider einführt. Und bei deren 
Abwesenheit den Wert zuweist.

EDIT: schon gesehen, du hast es jetzt so gemacht... ;-)

Stefan A. schrieb:
> Gibt es da Optimizer, die Amok laufen können?
Das steht im Handbuch der Toolchain. Und ja, das ist ein 
Optimierungseffekt.

: Bearbeitet durch Moderator
von Stefan A. (king-crash)


Lesenswert?

Ok ich konnte das in meinen großen Programm jetzt nachvollziehen.
Mit volgendem Code funktioniert es:
1
    if(divider < 4)
2
      begin
3
      divider <= 1000;
4
      end

Allerdings in meinem Fall seltsam, da es auch ohne nicht wegoptimiert 
werden dürfte.
Ich habe kurz danach nämlich seit jeher folgendes Konstrukt:
1
    control_verarbeiten <= control_verarbeiten +1;
2
    case(control_verarbeiten)
3
...
4
...
5
      // Lowbyte von Divider liegt an
6
      7:  begin
7
        divider[7:0] <= mem_control_readdata;
8
        mem_control_address <= 0;
9
        end
10
      // Highbyte von Divider liegt an
11
      8:  begin
12
        divider[15:8] <= mem_control_readdata;
13
        end

Der Witz ist, das hat auch schon einmal funktioniert. Erst seit ich die 
CRC Funktion dazugebastelt habe klappt es nichtmehr. In der Simulation 
allerdings kein Problem.
Meiner Ansicht nach ein klarer Bug, wundert mich allerdings nicht so 
wirklich. Das Quartus ist allgemein sehr hakelig und stürzt auch 
regelmäßig ab.

von Lattice User (Gast)


Lesenswert?

initial Blocks sind im Allgemeinen nicht synthesierbar. (@VHDLer, das 
entspricht einem Process der nur einmal durchlaufen wird)

statt
1
reg [15:0] divider;
2
initial divider = 2000;
1
reg [15:0] divider = 0;
(Verilog 2001, sollten alle aktuellen FPGA Tools inzwischen können)

von Stefan A. (king-crash)


Lesenswert?

So, ich hab es gerade nochmal getestet.
Es gibt 2 Konstallationen die funktionieren:

1. Trivial
1
reg [15:0] divider = 2000;

2. Kurios
1
reg [15:0] divider;
2
initial divider = 2000;
3
4
always @ (posedge FPGA_CLK1_50)
5
  begin
6
  if(divider == 0)
7
    divider <= 0;
8
  end

Da wie in Version 2 ersichtlich die "initial" Anweisung offensichtlich 
ausgewertet wird (Takt wird tatsächlich durch 2000 geteilt) und das if 
an sich nutzlos ist, ist das meiner Auffassung nach ein Bug.


Besten Dank an Alle.

von Weltbester FPGA-Pongo (Gast)


Lesenswert?

Stefan A. schrieb:
> Da wie in Version 2 ersichtlich die "initial" Anweisung offensichtlich
> ausgewertet wird (Takt wird tatsächlich durch 2000 geteilt) und das if
> an sich nutzlos ist, ist das meiner Auffassung nach ein Bug.

Nö, weil Links die Zeit nach dem Takt und rechts die Zeit vor dem Takt.

Du verschleppst damit bei einem Zähler einen Takt und ob das hier 
richtig ist, wage Ich mal zu bezweiffeln. Du muss mit einem Takt Vorlauf 
denken, also:

"Wenn Zähler + Inkrement im nächsten Takt mehr als Limit, dann limit or 
wrap etc..."

von Weltbester FPGA-Pongo (Gast)


Lesenswert?

und? wie isses nun?

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.