Hallo,
ich habe einen UART-Transmitter und einen UART-Receiver in VHDL gebaut.
Der Eingangstakt liegt bei 50 MHz, und bei 16x-Abtastung brauche ich
einen Teiler von ~325, um auf 9600 Baud zu kommen. Soweit richtig?
Der Transmitter scheint zuverlässig zu funktionieren, ein
1
data <= x"30";
2
trigger <= '1' when ready = '1' else '0';
sendet einen unendlich langen String aus Nullen.
Der Receiver funktioniert auch, verliert aber nach einiger Zeit den Sync
(d.h. wenn ich Sender und Empfänger verbinde, dauert es knapp 80
Zeichen, dann kommt Müll). An sich taste ich jedes Bit mittig ab und
versuche, aufs nächste Startbit zu synchronisieren. Irgendwas mache ich
da aber falsch.
Wie machen das bessere UARTs? Der USB-Seriell-Wandler auf dem Board
schluckt meinen Transmittertest auch bei abweichendem Timing problemlos.
Ich habe außerdem die Vermutung, dass sowohl Transmitter als auch
Receiver besser gemacht werden könnten. Für Verbesserungsvorschläge bin
ich offen. :-)
Gruß,
svenska
S. R. schrieb:> dann kommt Müll
Und was kommt denn anstelle der erwarteten 0x30?
Was macht die Simulation in diesem Szenario? Ist die Umschaltung dieser
"enables" knapp beieinander?
> versuche, aufs nächste Startbit zu synchronisieren
Was passiert, wenn du 2 Stopbits sendest und dem Empfänger eine bessere
"Synchronisationschance" gibst?
> Wie machen das bessere UARTs?
Von meiner Implementation weiß ich, dass sie vielfach eingesetzt wird
und soweit problemlos läuft:
http://www.lothar-miller.de/s9y/categories/42-RS232
foobar schrieb:> Bin kein FPGA-Spezi, aber wenn ich das richtig sehe, synchronisiert dein> Receiver nach dem Stop-Bit nicht neu sondern machst einfach weiter.
Wenn ich das Enable nach dem Stopbit abschalte, bekomme ich meine
Test-Textdatei auch nicht korrekt zurück.
Allerdings ist der Fehler an einer anderen Stelle: Meine Zeilenenden
haben nur ein Byte (LF, weil Unix), mein Terminalprogramm (picocom)
erwartet aber beide Bytes (CRLF). Mit "--imap lfcrlf" passt jetzt alles.
Insofern lag es also tatsächlich daran (und an meiner Inkompetenz).
Danke für die Hilfe.
Lothar M. schrieb:>> dann kommt Müll> Und was kommt denn anstelle der erwarteten 0x30?
In der Simulation funktioniert alles. Im System kam die erste Zeile
sauber an, irgendwann fehlen ein paar Zeichen und schließlich kamen
Binärdaten, bis es irgendwann mit dem korrekten Text weiterging (für
eine gewisse Zeit).
Laut Taschenrechner müsste mein Teiler 50 MHz / (16 * 9600) = 325.5
sein. Mit 326 verliere ich viele Daten, mit 325 hin und wieder welche,
mit 324 nicht. Bisschen seltsam.
Lothar M. schrieb:>> Wie machen das bessere UARTs?> Von meiner Implementation weiß ich, dass sie vielfach eingesetzt wird> und soweit problemlos läuft:
Ja, an dem Empfänger habe ich mich ein bisschen orientiert. Ein Lob
übrigens auf deine Webseite. Danke.
Ansonsten habe ich noch immer das Gefühl, dass meine Implementation
irgendwie... ineffizient ist, aber immerhin funktioniert sie jetzt.
Also ein UART geht grob so:
Warten auf fallende Flanke.
Die Zeit von 1,5 ganzen Bits abwarten, bei 9600 Bd sind das also
1,5*104,2 us = 156.3 us
Dann nacheinander 9 Bits in ein Schieregister schieben (jeweils die Zeit
eines ganzen Bits warten).
Prüfen ob das 9te Bit eine "1" ist (Stoppbit).
Man ist jetzt in der Mitte vom Stoppbit. Also nochmal die Zeit eines
ganzen Bits warten, dann ist man ein halbes Bit hinter dem Stoppbit. Ab
jetzt kann eine neue Übertragung beginnen. Es geht also von vorne los,
es wird auf eine fallende Flanke gewartet.
Edit:
Die Idee ist, dass man durch das anfängliche Warten von 1,5 mal der
Dauer eines Bits alle weiteren Bits möglichst mittig erwischt wenn der
Pegel stabil anliegt.
Gustl B. schrieb:> Man ist jetzt in der Mitte vom Stoppbit. Also nochmal die Zeit eines> ganzen Bits warten, dann ist man ein halbes Bit hinter dem Stoppbit. Ab> jetzt kann eine neue Übertragung beginnen. Es geht also von vorne los,> es wird auf eine fallende Flanke gewartet.
Ein halbes Bit hinter dem Stopbit hat man aber die fallende Flanke des
nächsten Startbits vielleicht schon verpasst... Das kann nämlich auch
direkt am Stopbit anschließen.
https://upload.wikimedia.org/wikipedia/commons/thumb/f/f3/RS-232_timing.svg/440px-RS-232_timing.svg.png
Das erste Datenbit muss sogar direkt hinter dem Startbit kommen. Und die
Flanke von den Datenbits ist völlig egal. Es interessiert nur der Pegel.
Wenn die Leitung krasse Störungen hat kann man vielleicht noch gucken ob
sich der Pegel seltsam ändert, aber wenn die Hardware passt genügt es
jedes Bit nach dem Startbit einmal in dessen Mitte zu erfassen.
Im Anhang meine UART. Die ist getestet und funktioniert seit einigen
Jahren im Dauereinsatz. Auch am FT(2)232H mit 12 MBaud. Man kann da den
Takt und die Baudrate als Generic einstellen. Das ist jetzt vielleicht
keine solderlich elegante Beschreibung, ist schon alt. Aber wenn ihr da
echte Fehler drinnen findet, dann immer her damit.
> Man ist jetzt in der Mitte vom Stoppbit.
Eher unwahrscheinlich. Man synct sich auf die Mitte des Startbits, damit
man maximale Toleranz zu Taktunterschieden hat (schneller oder
langsamer). Die Unterschiede summieren sich und beim Stopbit hängt man
irgendwo im Bit, von ganz am Anfang bis ganz am Ende. Deshalb sollte man
nach samplen des Stopbits sofort wieder in den
"Warten-auf-Startbit-Flanke"-Zustand wechseln - da noch zu warten ist
kontraproduktiv.
Und wenn nach dem Startbit eine "0" (Low) gesendet wird? Dann kommt
keine Flanke. Tolle Wurst. Ausserdem sollten die Bits ziemlich sehr
genau ähnlich lange sein. Zumindest als ich das letzte mal nachgemessen
habe mit dem LA war das auch der Fall bei den CP2102, FT232R und
FT(2)232H Bausteinen. Da liegt man also immer ziemlich perfekt in der
Mitte.
OK, aber Quarze sind heute echt gut genug. Selbst wenn sich der Takt um
1% was echt krass viel ist unterscheiden sollte fällt das am Ende nicht
auf. Es macht jedenfalls keinen Sinn nach dem Startbit auf irgendwelche
Flanken zu warten, es könnte ja auch "00000000" gesendet werden.
Wenn deine Quarze so gut sind, kannst du ja gerne das "A" aus UART
weglassen und dir deine persönliche URT machen.
Und les bitte nochmal genauer was ich geschrieben habe - ich sagte
nirgendwo, dass man nach dem Startbit auf ne Flanke warten soll.
Nach dem Einlesen des Stopbits, das ja in der Mitte des Stopbits
passiert, macht man sich natürlich sofort bereit für das nächste
Startbit...
foobar schrieb:> Man synct sich auf die Mitte des Startbits
Man kann doch nicht auf die Mitte des Startbits synchronisieren wenn
man nicht weiß, wo es aufhören wird. Ich nehme deshalb die Startflanke,
lese dann nach einer halben Bitdauer das Startbit ein und schiebe es
einfach durch das Empfangswort, bis es wieder rausfällt.
S. R. schrieb:> Mit 326 verliere ich viele Daten, mit 325 hin und wieder welche, mit 324> nicht. Bisschen seltsam.
Das ist der Wert für den Empfänger? Welchen Wert hast du dann beim
Sender?
Lothar M. schrieb:>> Mit 326 verliere ich viele Daten, mit 325 hin und wieder welche, mit 324>> nicht. Bisschen seltsam.> Das ist der Wert für den Empfänger?> Welchen Wert hast du dann beim Sender?
Ja, der Wert wird für den Empfänger benutzt. Der Sender ist ein auf dem
Board verbauter CP2102 (USB-Seriell-Wandler).