Hallo
Ich habe mal einen Einstieg in die FPGA-Welt gemacht und erst ein
bisschen LED's blinken lassen und Zeug gezählt und habe jetzt einen
Sende- und Empfangsbaustein für UART gebastelt. Der läuft in der
Simulation prima, aber ich habe einfach keinen Ansprechpartner für die
ganzen Stilfragen. Ich hätte also ganz gern, dass jemand das Design nach
groben Schnitzern durchsucht.
Vor allem habe ich in dem Design das erste Mal Tasks benutzt und mir
über CDC Gedanken gemacht:
-Zum Clockdomaincrossing wird ein UART-Bit beim Empfang mehrfach
abgetastet, wie oft kann man mit Clock_Divide festlegen. In der
Simulation hats mit ca. 10% Taktungenauigkeit noch funktioniert. Mit
Synchroclocks_After_Begin und Synchroclocks_Before_End legt man den
Bereich fest, in dem eine Flanke am RxD als Störung erkannt wird und
wann diese Flanke zur Taktsynchronisierung genutzt wird. Kommt eine
Flanke zum Empfangsbeginn oder nahe am Ende, ändert die Statemachine
ihren Zustand so, dass FPGA und der andere Teilnehmer wieder
synchronisiert sind.
-Die Tasks XXX_Wait zählen beim Senden und beim Empfangen mit, wie weit
das Senden oder Empfangen eines Bits schon ist.
-Zum Reset werden ebenfalls Tasks benutzt
-Das ganze läuft mit 8 Datenbits, einem Start- und einem Stopbit und
ohne Parity
Wie gesagt, in der Simulation läufts. Für einen richtigen Test habe ich
leider noch kein Board. Ich wollte erst sehen, wie hart das von euch
diskriminiert wird, was ich gemacht hab :D
Ich wollte es variabel machen: Die Baudrate ist dann
Eingangstakt/Clock_Divide
In der Testbench wars Eingangstakt = 500Mhz, ClockDivide = 10 =>
Baudrate von 50 Mhz
Wenn man CLock_Divide mit 435 wählt, bekommt man eine Baudrate von
114942,528736 und damit eine Abweichung von einem Prozent. Ich weiß, das
ist hart an der Grenze aber ich dachte es reicht noch. Und es ist doch
auch bei uCs so, dass der Systemtakt geteilt wird, um den UART-Takt zu
kriegen und man ihn nunmal nur durch ganzzahlige Werte teilen kann?
Wie mache ich es denn richtig?
Mein Ansatz war, dass man beim uC ja ebenfalls einen Zähler hat, der den
UART Takt generiert. Also der Systemtakt wird runtergeteilt. In meinem
Programm könnte man alternativ auch einen externen Takt zuführen, der
ein genaues Vielfaches der Baudrate ist und mit Clock_Divide ein genaues
zeitliches Verhalten und trotzdem die Mehrfachabtastung erzeugen könnte.
Joschua C. schrieb:> Mein Ansatz war, dass man beim uC ja ebenfalls einen Zähler hat, der den> UART Takt generiert. Also der Systemtakt wird runtergeteilt.
Ja, das passt schon...
Wenn man langfristig genau sein will, aber ein wenig Jitter erlauben
kann, dann ist eine DDFS für das Erzeugen des Clock-Enables auch eine
Möglichkeit. Damit lässt sich die Abweichung von der tatsächlichen
Baudrate in Grenzen halten, weil der Fehler nicht "abgeschnitten",
sondern über viele Zyklen hinweg aufsummiert wird.
Joschua C. schrieb:> Wenn man CLock_Divide mit 435 wählt
434 wäre dann schon der bessere Vorteiler für 115200 Bit/s. Da ist der
Fehler dann schon nur noch 6ppm und damit "besser" als die meisten
Quarzoszillatoren...
Hab bei Google nicht allzu viel zur DDFS gefunden: Heißt das ich
fenstere den Eingangstakt und setze ihn ganz kurz aus, wenn der UART
gerade nix macht, um die Phasenverschiebung zum korrekten Takt
aufzuheben? Hebt die Synchronisation durch das Startbit nicht diese
Synchronisation auf?
Du verwendest nur die DDFS zum genauen Erzeugung der 16 fachen Baudrate
für das Oversampling. Das Resynchronisieren auf die Flanke (so da eine
kommt) passiert ja auf einer ganz anderen Ebene erst innerhalb des
"Bitzählers"...
Aber um die DDFS zu erzeugen, brauche ich doch wieder einen Takt, der
ein ganzzahliges Vielfaches dieser 16-fachen Baudrate ist, die ich
erzeugen will? Wenn ich diesen Takt hätte, könnte ich ihn doch auch
gleich direkt in den UART einspeisen und statt dem Aufbau der DDFS
einfach Clock_Divide größer machen, um eine genaue Baudrate zu erhalten?
Joschua C. schrieb:> Aber um die DDFS zu erzeugen, brauche ich doch wieder einen Takt, der> ein ganzzahliges Vielfaches dieser 16-fachen Baudrate ist, die ich> erzeugen will?
Nein, du kannst bei der DDFS den Akku breiter machen und mit quasi mit
"Nachkommastellen" arbeiten. Du wirst aber wegen der "Nachkommastellen"
eben ab&zu einen "Sprung" im Signalverlauf haben. Eine einfach Skizze
hier:
Man sieht, dass die Frequenz über mehrerer Impulse betrachtet niedriger
geworden ist. Aber es kommt eben zusätzlich ab&zu ein "Jitterimpuls" mit
unterschiedlicher Länge rein. Der Jitter ist +-1/(2fclk), und damit bei
50MHz eben +-12,5ns.
Ah hey, danke für die Antwort. Habs gerafft :D
Noch irgendwelche Stilfehler? Kann man Tasks so einsetzten? Und passen
z.B. die non blocking assignments?