Forum: FPGA, VHDL & Co. UART empfangen auf FPGA


von Hans H. (hanshirsch)


Angehängte Dateien:

Lesenswert?

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?

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


Lesenswert?

Weil txd_tmp immer '1' ist.
1
TXD      <= txsr(txsr'left);
2
txd_tmp  <= txsr(0);
3
:
4
         txsr     <= txsr(txsr'left-1 downto 1) & '1';  
5
:
6
         rxd_sr <= rxd_sr(rxd_sr'left-1 downto 0) & txd_tmp;
Du taktest immer nur eine '1' in den Empfänger hinein...

von Hans H. (hanshirsch)


Angehängte Dateien:

Lesenswert?

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?

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


Lesenswert?

U.A. weil die erste fallende Flanke nicht erkannt werden kann:
1
:
2
    if (rxd_sr(3 downto 2) = "10") then                 -- fallende Flanke Startbit            
3
:
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... :-/

von Hans H. (hanshirsch)


Angehängte Dateien:

Lesenswert?

txbitctr fängt auch erst bei 3 an zu zählen...

von Hans H. (hanshirsch)


Angehängte Dateien:

Lesenswert?

habe die flankenerkennung auf "01" gesetzt, sieht jetzt etwas besser 
aus:

    if (rxd_sr(3 downto 2) = "01") then

Aber noch nicht 100%!?

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


Lesenswert?

> 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');

von Hans H. (hanshirsch)


Angehängte Dateien:

Lesenswert?

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ß

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


Lesenswert?

> 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
   signal rxd_sr    : std_logic_vector (1 downto 0) := "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?

von Hans H. (hanshirsch)


Angehängte Dateien:

Lesenswert?

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?

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


Lesenswert?

> 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.

von Hans H. (hanshirsch)


Lesenswert?

> 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.

von Johann (Gast)


Lesenswert?

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;

von Johann (Gast)


Lesenswert?

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.

von Hans H. (hanshirsch)


Lesenswert?

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.

von Hans H. (hanshirsch)


Lesenswert?

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.

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


Lesenswert?

> 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

von Hans H. (hanshirsch)


Lesenswert?

> 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!???????

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


Lesenswert?

"Mitdenken!" sagte der Meister zum Stift  :-/

Probier mal statt:
1
   rxd_sr <= rxd_sr(rxd_sr'left-1 downto 0) & txd_tmp;
das da:
1
    rxd_sr <= rxd_sr(0) & txd_tmp;

Und wenn das nichts hilft, hindert dich keiner, in der simulation mal 
das rxd_sr genauer anzuschauen...

von Duke Scarring (Gast)


Lesenswert?

Warum habe ich hier nur

>"Mitdenken!" sagte der Meister zum Shift

gelesen? ;-)

Duke

von Hans H. (hanshirsch)


Angehängte Dateien:

Lesenswert?

> 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...

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


Lesenswert?

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... :-/

von Hans H. (hanshirsch)


Angehängte Dateien:

Lesenswert?

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.

von Hans H. (hanshirsch)


Angehängte Dateien:

Lesenswert?

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

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


Lesenswert?

> 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.

von Hans H. (hanshirsch)


Lesenswert?

Funktioniert! Besten Dank!

von Hans H. (hanshirsch)


Angehängte Dateien:

Lesenswert?

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.

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


Lesenswert?

txsr     <= txsr(txsr'left-1 downto 1) & '1';

Mitdenken...  :-/

txsr     <= txsr(txsr'left-1 downto 0) & '1';

Da hätte der Simulator aber auch meckern müssen...

von Hans H. (hanshirsch)


Lesenswert?

Danke!

von Hans H. (hanshirsch)


Angehängte Dateien:

Lesenswert?

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ß

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


Lesenswert?

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-1 downto 1) & '1';       -- links schieben, mit MSB beginnen
2
3
   rxsr  <= rxd_sr(1) & rxsr(rxsr'left downto 1);   -- rechts schieben, weil LSB first

Mach das Empfangsregister doch so:
1
   rxsr  <= rxsr(rxsr'left downto 1) & rxd_sr(1);   -- links schieben, weil MSB first


PS: Phänomenal, dass du das nicht selber siehst ;-)

von berndl (Gast)


Lesenswert?

hab' das gerade auch von oben bis unten durchgelesen, bin erschuettert!

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


Lesenswert?

> hab' das gerade auch von oben bis unten durchgelesen
Donnerwetter, meine Hochachtung.
Ich musste es immer nur in kleinen Häppchen aufnehmen   ;-)

von Iulius (Gast)


Lesenswert?

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 :)

von Hans H. (hanshirsch)


Angehängte Dateien:

Lesenswert?

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.

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


Lesenswert?

> 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.
1
  Generic ( Quarz_Taktfrequenz : integer   := 50000000;  -- Hertz               
2
            Baudrate : integer :=  12000000              -- Bits/Sec             
3
        );
Du solltest bei derart knappen Timing keinesfalls irgendwelche Werte 
herrechnen. Denn so schön diese Formel aussieht:
1
      if txcnt < ((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' and tx_busy = '0') then   -- dauernd senden, solange tx_start aktiv
2
      txcnt    <= 1;                            -- Z�hler initialisieren

von Hans H. (hanshirsch)


Lesenswert?

>> 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)

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


Lesenswert?

>  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?

von Hans H. (hanshirsch)


Lesenswert?

Ziel:

ca.5Mbit Daten(muss nicht genau sein), die Manchestercodiert übertragen 
werden sollen.(also 10Mbit)
1. FPGA sendet -> kapazitive Übertragungsstrecke(deswegen 
Manchestercodiert für gleichspannungsfreiheit) -> 2.Fpga empfängt wertet 
aus.

von Gast (Gast)


Lesenswert?

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.

von Hans H. (hanshirsch)


Lesenswert?

Es soll nur eine RS232 simuliert werden, d.h. die Daten sollen die 
"Form" einer UART haben und werden per LVDS übertragen.
Ok, aber danke bis hierher!

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


Lesenswert?

> Ok, aber danke bis hierher!
De nada ;-)

von Gast (Gast)


Lesenswert?

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 :)

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.