UART empfangen auf FPGA

#1460088
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?
Angehängte Dateien:
Moderator (Firma: Titel) Persönliche Seite #1460166
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... :-/
Moderator (Firma: Titel) Persönliche Seite #1460266
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');
#1460881
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ß
Angehängte Dateien:
Moderator (Firma: Titel) Persönliche Seite #1460900
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?
#1460933
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?
Angehängte Dateien:
Moderator (Firma: Titel) Persönliche Seite #1460960
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.
Gast #1460993
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;
Moderator (Firma: Titel) Persönliche Seite #1461037
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
#1461058
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!???????
#1461675
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
Angehängte Dateien:
Moderator (Firma: Titel) Persönliche Seite #1461709
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.
#1462236
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.
Angehängte Dateien:
Moderator (Firma: Titel) Persönliche Seite #1462978
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 ;-)
#1463650
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.
Angehängte Dateien:
Moderator (Firma: Titel) Persönliche Seite #1463688
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
#1463721
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)
Moderator (Firma: Titel) Persönliche Seite #1463743
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?
Gast #1463925
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.
Gast #1464059
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 :)

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