Hallo,
ich habe eine von microcontroller.net verlinke UART folgendermaßen
leicht verändert: Das MSB wird zuerst gesendet. (siehe Beispiel x"AA")
Das Klappt so weit. Aber der Empgang funktionert nicht. Könnte mir
jemand sagen woran es liegt?
Ich habe es jetzt so umgeschrieben:
TXD <= txsr(txsr'left);
txd_tmp <= txsr(txsr'left);
Das Ergebnis sieht folgendmaßen aus(s. Anhang)
Wo liegt jetzt noch der Fehler?
Warum fängt der Empfang erst beim 4.Bit an und müsste es nicht in der
Bitmitte sein?
Denn die geht ja von 'U' nach '0'... :-o
Sieh dir auch mal die internen Signale an: txbitcnt und rxbitcnt
BTW:
Irgendwie scheint mir der Empfänger (bezogen auf den Sender) mit einer
falschen Baudrate zu laufen... :-/
> if (rxd_sr(3 downto 2) = "01") then
Du strocherst aber arg im Trüben... :-/
Kurz und gut: Das Startbit ist eine fallende Flanke.
Dein Problem ist, dass eine Flanke von 'U' nach '0' eben gerade
keine fallende Flanke ist (ich meine, so was schon mal geschrieben zu
haben...).
Initialisiere doch einfach mal das txsr mit dem Ruhepegel:
signal txsr : std_logic_vector (9 downto 0) := (others=>'1');
Mit angehängtem Quellcode "UART.vhd" habe ich jetzt das das Ergebnis
"Simulation4.jpeg".
Es sieht fast gut aus. Nur gibt es denke ich noch das Problem mit der
Abtastung in dr Bitmitte. Wieso ist diese aber auch unbegint notwendig?
Und es wird irgendwarum erst die die zweite negative Flanke erkannt!?
Gruß
> Nur gibt es denke ich noch das Problem mit der Abtastung in dr Bitmitte.
Als Tipp: das rxd_sr bringt dir 4 Takte Latency.
Mach das mal kürzer:
1
signalrxd_sr:std_logic_vector(1downto0):="11";-- Flankenerkennung und Eintakten
2
:
3
rxsr<=rxd_sr(rxd_sr'left-1)&rxsr(1);-- rechts schieben, weil LSB first
4
:
5
if(rxd_sr="10")then-- fallende Flanke Startbit
> ... Abtastung in dr Bitmitte. Wieso ist diese unbegint notwendig?
Stell dir mal vor, der Sender sendet mit 3% Fehler (z.B. 9900Bits/sec
statt mit 9600Bits/sec). Kannst du dir jetzt vorstellen, welchen Vorteil
die Abtastung in der Bitmitte hat?
Das Resultat ist dieses. (siehe Anhang)
Der Sender ist in meinem Fall ja eine UART in einem FPGA-implementiert.
Un dwird zu Testzwecken auch nur so mit einer konstanten Baudrate
versendet. Da kann ich doch mit einer Fehlerrate von nahezu 0% rechnen!?
Für die Praxis ist das natürlich sinnvoll.
Warum zählt txbitcnt eigentlich bis 10 es sind ja keine 11Bit pro Frame?
> Das Resultat ist dieses. (siehe Anhang)
Der Abtastzeitpunkt ist schon besser. Jetzt kontrollierst du noch,
weshalb du lauter 'U' eintaktest, dann bist du fertig.
> Warum zählt txbitcnt eigentlich bis 10
Hmm... weil es so beschrieben ist? :-/
Ganz einfach: während txbitcnt=0..9 werden Bits übertragen
(1 Startbit, 8 Datenbits, 1 Stopbit).
txbitcnt=10 ist der Ruhezustand des Senders.
> Jetzt kontrollierst du noch,> weshalb du lauter 'U' eintaktest, dann bist du fertig.
Meines Erachtens nach werden keine 'U' eingetaktet. Gesendet wird ja
kein 'U' und dasselbe Signal wird auch eingetaktet.
Ich habe das mal früher so gelöst: Meine Lösung basierte auf einem
Multiplexer. Und einem Counter. Durch den Countervergleich gibt der
Multiplexer immer das entsprechende Bit an den Ausgang weiter. Das Start
und Stopbit erzeuge ich so gleich automatisch mit. Das Mit dem Counter
muß noch mal üßberprüft werden, habe das mal schnell gemacht. Ich weiß
das die Lösung mit dem Schieberegister sicherlich schneller geht. Dies
ist jedoch mal ein anderer Ansatz.
if(CLK_RS232'event and CLK_RS232 = '0')then
if(CLR = '1')then
TXD <= '1';
elsif(S_START_OUTPUT = '1')then
case S_COUNTER is
when "0000" => TXD <= '0';
when "0001" => TXD <= S_OUTPUT_BUFFER(0);
when "0010" => TXD <= S_OUTPUT_BUFFER(1);
when "0011" => TXD <= S_OUTPUT_BUFFER(2);
when "0100" => TXD <= S_OUTPUT_BUFFER(3);
when "0101" => TXD <= S_OUTPUT_BUFFER(4);
when "0110" => TXD <= S_OUTPUT_BUFFER(5);
when "0111" => TXD <= S_OUTPUT_BUFFER(6);
when "1000" => TXD <= S_OUTPUT_BUFFER(7);
when "1001" => TXD <= '1';
when others => NULL;
end case;
else
TXD <= '1';
end if;
end if;
end process;
if(CLK_RS232'event and CLK_RS232 = '0')then
if(CLR = '1')then
S_START_OUTPUT<= '0';
S_COUNTER <= "0000";
elsif(START = '1')then
S_START_OUTPUT<= '1';
S_COUNTER <= S_COUNTER + 1;
end if;
end if;
Aus meiner Sicht ist es immer wichtig einen syncronen Reset einzubauen,
damit es nicht zu undefinierten Zuständen kommen kann.Somit hat man auch
mal die Möglichkeit sich neu zu syncronisieren.
Dies Variante habe ich auch schon auspropiert. Klappt auch gut. Das ist
ja aber nur der Sender. Der funktioniert bereits. Es geht hier um den
Empänger!!!
H.H.
Nochmal zum Thema zurück:
> Jetzt kontrollierst du noch, weshalb du lauter 'U' eintaktest, dann bist > du
fertig.
Meines Erachtens nach werden keine 'U' eingetaktet. Gesendet wird ja
kein 'U' und dasselbe Signal wird auch eingetaktet.
> Aus meiner Sicht ist es immer wichtig einen syncronen Reset einzubauen,> damit es nicht zu undefinierten Zuständen kommen kann.
Ein "wirklicher" Reset sind nur sehr selten nötig. Oft braucht den der
Entwickler nur für seinen Reset-Taster. Dazu gibt es ein schönes Paper
von Xilinx:
http://www.xilinx.com/support/documentation/white_papers/wp272.pdf
Fazit: When creating each section of a design, simply ask, “Does this
bit need to be reset”?
> Meines Erachtens nach werden keine 'U' eingetaktet.
Die Simulation sagt was anderes :-o
> Die Simulation sagt was anderes :-o
Ich verstehe nicht es nicht.
wenn ich die Parameter ändere wie du es vorgeshclagen hast:
signal rxd_sr : std_logic_vector (1 downto 0) := "11"; --
Flankenerkennung und Eintakten
:
rxsr <= rxd_sr(rxd_sr'left-1) & rxsr(1); -- rechts schieben, weil
LSB first
:
if (rxd_sr = "10") then -- fallende Flanke Startbit
...dann erhalte ich für das eintakten 'U', wenn es auf die
Ursprünglichen Werte gesetzt wird. ist die Abtastung zwar nicht in der
Mitte, aber kein 'U'!
Ich habe keine Ahnung woran es jetzt liegt!???????
> Und wenn das nichts hilft, hindert dich keiner, in der simulation mal> das rxd_sr genauer anzuschauen...
Es scheinst sich mit
rxd_sr <= rxd_sr(0) & txd_tmp;
irgendwie nichts zu tun...
rxd_sr sieht doch gut aus...
Da ist der Fehler:
rxsr <= rxd_sr(rxd_sr'left-1) & rxsr(1);
Du schiebst in die falsche Richtung. Probier mal:
rxsr <= rxd_sr(1) & rxsr(rxsr'left downto 1); -- rechts schieben,
weil LSB first
Bitte nicht einfach Copy-Paste machen und alle Fehler mitkopieren... :-/
Habe
> rxsr <= rxd_sr(1) & rxsr(rxsr'left downto 1);
probiert. Es funktiont ab dem zweiten Frame!
Es müsste so auch in Ordung sein, da ich sowieso eine Endlosschleife
habe.
Noch eine Modifikation:
letztendlich soll bei
Generic ( Quarz_Taktfrequenz : integer := 50000000; --Hertz
Baudrate : integer := 12000000 -- Bits/S
);
empfangenwerden
Es funktioniert zwar noch, aber selbst beim 2. Frame ist die Abtastung
nicht wie im vorigen Bild "Simulation7" etwa in der Mitte. Sie es
rutscht dann richtung nächstes Bit.
Kann man da was machen
> Kann man da was machen
Wenn du unbedingt (selber schuld) diese Geschwindigkeit asynchron
fahren willst, und damit zufrieden bist, dass die simulation schön
aussieht, dann solltest du hier was machen:
1
rxcnt<=((Quarz_Taktfrequenz/Baudrate)-1)/2;-- erst mal nur halbe Bitzeit abwarten
Probiers mal so:
1
rxcnt<=2;-- erst mal nur halbe Bitzeit abwarten
Nimm eine vernünftige Baudrate. 12MBit/s sind zu schnell für eine RS232
Schnitte. Hier solltest du dir ein sinnvolles Interface aussuchen. Z.B.
ein synchrones Interface wie SPI. Wenns unbedingt asynchron sein soll,
dann mit Manchester-Codierung, damit pro Bit wieder aufsynchronisiert
werden kann.
beim Syntaxcheck ist jetzt doch noch ein Fehler aufgetreten der für die
Simulation scheinbar keine Rolle gespielt hat:
Line 113. Size of concat operation is different than size of the
target.
Er bezieht aich auf diese Zeile im Sendungsprocess:
txsr <= txsr(txsr'left-1 downto 1) & '1';
Weis im Moment nicht wied er zu beseitigen wäre.
Nochmal zu diesem Thema:
Bisher habe ich AA übertragen, da hat alles funktioniert:
Übertrage ich jetzt x"C2" kommt am Emfänger nichts mehr an???
Die UART ist dich nicht nur zum Empfang von x"AA" geeignet?
Gruß
Du hast ein Problem mit der Schieberichtung:
C2 = 11000010
43 = 01000011
Siehst du was?
Wenn du 71 sendest wirst du 8E empfangen usw.usf.
Fazit: wenn der Sender das MSB zuerst rausschiebt, dann sollte der
Empfänger auch das MSB zuerst empfangen...
1
txsr<=txsr(txsr'left-1downto1)&'1';-- links schieben, mit MSB beginnen
2
3
rxsr<=rxd_sr(1)&rxsr(rxsr'leftdownto1);-- rechts schieben, weil LSB first
Mach das Empfangsregister doch so:
1
rxsr<=rxsr(rxsr'leftdownto1)&rxd_sr(1);-- links schieben, weil MSB first
PS: Phänomenal, dass du das nicht selber siehst ;-)
Naja seht es mal so : bei jedweder möglichen Frage in Zusammenhang mit
Uart die jemals wieder auftreten könnte darf auf diesen Thread verwiesen
werden :)
Eine weitere Frage:
Das Startbit des UART-Signals ist nicht genauso lang wie die Datenbits.
Das macht mir Probleme, wenn ich es Manchestercodieren will, weil da
alle Bits gleich lang sein müssen.
Beim Stoppbit wird hier bewusst länger gewartet, aber das Startbit ist
irgendwarum länger. Bei meiner Frequenz ist das Startbit 100ns, die
Datenbits 80ns. Warum dieser Unterschied bei gleicher Bitrate?
Ziel ist es alles gleich lang zu machen.
Mit der oben genannten MUX-Version ist das kein Problem, aber bei der
verwendeten schon.
> Warum dieser Unterschied bei gleicher Bitrate?
Mein Glückwunsch, du hast einen Takt Latency entdeckt.
Das ursprüngliche Konzept dieser UART setzt eine Baudrate voraus, die
wesentlich geringer als die FPGA-Taktfrequenz ist. Da kann man 20ns
Verzögerung schon mal tolerieren ;-)
Du solltest bei derart knappen Timing keinesfalls irgendwelche Werte
herrechnen. Hier muss jeder Takt ausgezählt werden.
Du solltest bei derart knappen Timing keinesfalls irgendwelche Werte
herrechnen. Denn so schön diese Formel aussieht:
1
iftxcnt<((Quarz_Taktfrequenz/Baudrate)-1)then
So falsch ist das Ergebnis:
50000000/12000000 = 4,16666666
> Bei meiner Frequenz ist das Startbit 100ns, die Datenbits 80ns.
80ns sind damit genauso falsch wie 100ns. Richtig wären 83,3333ns. Die
wirst du aber mit einem 20ns Takt niemals erreichen...
> Ziel ist es alles gleich lang zu machen.
Dann starte den Zähler bei 1:
1
if(tx_start='1'andtx_busy='0')then-- dauernd senden, solange tx_start aktiv
>> Ziel ist es alles gleich lang zu machen.>Dann starte den Zähler bei 1:>if (tx_start = '1' and tx_busy = '0') >then> txcnt <= 1;
Was wäre zu ändern um für das Stoppbit die gleiche anforderung zu
stellen? Müsste der Zähler dann einfach nur bis neun gehen? Mir scheint
wenn ich den zähler bis neun gehen lasse, dann iwrd das Stoppbit zu
kurz. (txbitcnt geht nur bis 2)
> Was wäre zu ändern ...
Du hast eine ganz andere Aufgabenstellung, warum fängst du mit einer SIO
an, machst die dann rasend schnell, und hängst anschliessend noch einen
Manchesterdecoder dazu?
Das wäre wie wenn du sagst:
Ich brauche ein Fortbewegungsmittel, also nehme ich mir ein Moped
(RS232-SIO). Dann bastle ich solang dran herum, dass ich damit damit 300
fahren kann (12Mbit/sec). Und zum Schluss mache ich Flügel dran
(Mnachester), dann bin ich fertig.
Richtig wäre gleich zu sagen: ich brauche ein Flugzeug.
> Was wäre zu ändern ...
Ich klinke mich hier aus, denn du schießt dir gerade mit dem tx_busy ins
Knie. An dem haben wir ganz zu Anfang (weißt du das noch?) herumgemacht.
Wie gesagt: du brauchst (selber) erst mal eine genaue Definition der
Zielaufgabe. Welche Daten mit welcher Geschwindigkeit mit welcher
Codierung. Wozu willst du das überhaupt verwenden? Wäre ein anderes
Protokoll nicht geeigneter?
Womit wir wieder am Anfang wären...
Lother Miller schrieb:
> 12MBit/s sind zu schnell für eine RS232> Schnitte. Hier solltest du dir ein sinnvolles Interface aussuchen. Z.B.> ein synchrones Interface wie SPI. Wenns unbedingt asynchron sein soll,> dann mit Manchester-Codierung, damit pro Bit wieder aufsynchronisiert> werden kann.
Moment, seit wann ist RS232 Manchestercodiert? Das widerspricht deinem
letzten Posting...
Ist es wirklich Bestandteil deiner Aufgabe eine RS232-ähnliche
Übertragung mit Manchestercode zu "pimpen" und anschließend das ganze
noch schnell zu "pfuschen"?
Kann es vielleicht sein, dass du eine asynchrone Übertragung mit Hilfe
der Manchestercodierung auf die Beine stellen und hierbei den Takt mit
Hilfe der Codierung zurückgewinnen sollst?
Das würde nämlich technisch durchaus Sinn machen.
Sprich mal mit deinem Prof. und erzähl ihm deine Erkenntnisse, die du
hoffentlich aus diesem Thread hier gelernt hast. So macht das doch sonst
keinen Sinn.
Achja, wenn er wirklich darauf besteht, dann erzeug dir einen höheren
Systemtakt (DCM/PLL), wie schon gesagt muss die Abtastrate wesentlich
höher als die Baudrate sein.
PS: Halt uns bitte auf dem Laufenden :)