Variabler Clockdivider in Verilog

OP #4888545
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?
Angehängte Dateien:
Gast #4888592
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.
OP #4888646
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.
OP #4888672
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?
Moderator (Firma: Titel) Persönliche Seite #4888682
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.
OP #4888729
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.
Gast #4888854
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)
OP #4892131
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.
Gast #4892521
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..."

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren