Hallo zusammen!
Anfängerproblem: Ich würde gerne über UART Kommandos und Daten an einen
FPGA schicken (zum Testen benutze ich das BASYS 3 Board von Digilent),
worauf dieser dann entsprechend reagieren soll. Leider funktioniert das
überhaupt nicht.
Ich benutze dazu eine FSM, die die ankommenden Bytes vom UART Receiver
per Handshake abholt, prüft ob diese mit definierten Bitmustern
(Kommandos) übereinstimmen und dann eine entsprechende Ausgabe über den
Transmitter macht. (Falls sie mit keinem Bitmuster übereinstimmen, soll
es sich um einfache Datenbytes handeln) Um das zu testen, lasse ich alle
"dekodierten" Eingaben so einfach auch wieder ausgeben. Die Simulation
mit einem Testbench funktioniert.
Hier mal eine verkürzte Version dieser FSM mit dem Process (auch genauso
getestet):
1
process(clk)
2
begin
3
ifrising_edge(clk)then
4
ifrst='1'then
5
-- Synchroner reset.
6
state<=s_Idle;
7
s_rx_ack<='0';-- Handshake für UART Receiver
8
s_tx_ack<='0';-- Startsignal für UART Transmitter
9
-- ...
10
endif;
11
else
12
casestateis
13
whens_Idle=>
14
ifs_rx_rdy='1'then-- neues Byte im Receiver verfügbar
15
s_buffer<=s_rx_data;-- Byte vom Receiver zwischenspeichern
16
s_rx_ack<='1';-- Handshake
17
state<=s_Decode;
18
endif;
19
20
whens_Decode=>
21
s_rx_ack<='0';-- Handshake zurücksetzen
22
23
ifs_buffer(7)='1'then-- 1XXXXXXX (Kommando)
24
-- Kommando
25
ifs_buffer(6)='1'then-- Zur Demonstration hier nur vereinfacht zwei Kommandos
26
s_output<="00000001";
27
else
28
s_output<="00000000";
29
endif;
30
else-- 0XXXXXXX (Daten)
31
-- Datenbyte
32
s_output<=s_buffer;-- Datenbyte wird unverändert übernommen
33
endif;
34
35
whens_Send=>
36
ifs_tx_rdy='1'then-- warten bis UART Tx bereit
37
s_tx_data<=s_output;-- zu sendendes Byte übergeben
38
s_tx_ack<='1';-- Startsignal geben
39
state<=s_CleanUp;
40
endif;
41
42
whens_CleanUp=>
43
s_tx_ack<='0';
44
state<=s_Idle;
45
endcase;
46
endif;
47
endprocess;
Es kommt mir so vor als würde der Schritt im s_Decode-Zustand ignoriert,
bzw. die Ausgaben passen überhaupt nicht zu etwas erwartbarem.
Ich würde fast ausschließen, dass der UART Receiver/Transmitter
fehlerbehaftet ist: Wenn ich den s_Decode-Zustand quasi weg lasse und
alles eingehende unverändert wieder rausschicke, funktioniert es
tadellos. Ich vermute daher stark, dass der Fehler hier im s_Decode
Bereich liegt. Vermutlich ein Fehler der vom Software-denken herrührt
und der mit VHDL gänzlich anders gelöst werden muss. Was ich bereits
erfolglos versucht habe, ist ein Auslagern in einen kombinatorischen
Prozess oder in eine Funktion, genauso wie ständiges Umbauen der FSM.
Ich bin über jeden Input/Tipp dankbar, weil mir mittlerweile echt die
Ideen ausgegangen sind.
Falls weiterer Code benötigt wird, hänge ich diesen gerne an, wollte es
nur beim wesentlichen erstmal belassen.
Vielen Dank!
Stefan L. schrieb:> Ich bin über jeden Input/Tipp dankbar, weil mir mittlerweile echt die> Ideen ausgegangen sind.
du wertest im Decode die Bits 7 und 6 von s_buffer aus. Kann es sein,
dass die Bitreihenfolge anders ist als erwartet (d.h. du wertest in
Wirklichkeit Bit 0 und 1 aus)?
Dein Board hat doch diverse LEDs. Lass zur Kontrolle einfach mal auf den
LEDs ausgeben, was du in s_buffer bekommst und was in s_output landet.
Und dann schicke einzelne Bytes und schau auf den LEDs an, was decodiert
wird.
Gute Idee! Leider liefert das auch sehr verwirrende Ergebnisse... Kann
man das generell schon so machen wie ich das angehe? Oder sollte man den
Code anders formulieren? Falls das okay ist, sollte ich den Fehler
vielleicht doch wo anders suchen, eventuell mal eine andere UART
Implementierung ausprobieren.
Stefan L. schrieb:> Oder sollte man den> Code anders formulieren?
Ups: jetzt sehe ich den Fehler. Du hast fast den gesamten Code im
else-Zweig von if rising_edge(clk) then
Du wolltest ihn eigentlich im else-Zweig von if reset='1' then...
Dein Simulator hat dir wohl Warnungen geben, dass die Sensitivity nicht
vollständig ist, oder?
Stefan L. schrieb:> Gut gesehen, aber das war leider ein blöder Fehler von mir, habe es> falsch eingegeben. :/ Hier die hoffentlich korrekte Version.
Hmmm
Kannst du nicht den tatsächlichen Code per Copy&Paste rüberziehen (ohne,
dass sich dabei weitere Fehler einschleichen)?
Dieser Code sieht jetzt imho grundsätzlich korrekt aus (den UART-Teil
mit seinem Handshake sehe ich im obigen Code-Schnippsel natürlich nicht.
Selbst die Einstellung der Baudrate kann ja z.B. völlig daneben sein).
Stefan L. schrieb:> Leider liefert das auch sehr verwirrende Ergebnisse...
Was sind denn die verwirrenden Ergebnisse? Schicke mal einzelne Bytes
mit charakteristischen Bitmustern. Notiere, was gesendet wurde und was
auf den LEDs angezeigt wird, und lade eine Liste von Werte hier hoch.
Vielleicht erkennt jemand ein Muster...
Stefan L. schrieb:> Wenn ich ... alles eingehende unverändert wieder rausschicke,> funktioniert es tadellos.
Was passiert denn, wenn du nicht das gerade empfangene Byte wieder
zurückschickst, sondern einfach ein U (=0x55)? Oder wenn du mit jedem
empfangenen Byte einen Zähler um 1 hochzählst und diesen Zählerstand
dann zurückschickst? Was kommt dann am Terminal an?
Stefan L. schrieb:> Die Simulation> mit einem Testbench funktioniert.
Kannst Du die funktionierende Simulation (VHDL + Testbench) evtl. hier
einstellen (als Anhang)?
Dann könnte ich mir das anschauen und testweise durch meinen Simulator
schicken.
Duke
Erstmal vielen Dank für die wertvolle Hilfe! Ich habe den Code mal mit
angehängt. Dieser folgt der Hierarchie:
1. Loopback.vhd
2. uart.vhd
3. uart_rx.vhd
4. uart_tx.vhd
(Auflistung wollte jetzt nicht so wie ich wollte, aber ich hoffe es ist
verständlich)
Testbench: Loopback_Tb.vhd
Vivado Constraints: Constraints.xdc (FYI)
Achim S. schrieb:> Was sind denn die verwirrenden Ergebnisse? Schicke mal einzelne Bytes> mit charakteristischen Bitmustern. Notiere, was gesendet wurde und was> auf den LEDs angezeigt wird, und lade eine Liste von Werte hier hoch.> Vielleicht erkennt jemand ein Muster...
Mache ich sofort im Anschluss.
Lothar M. schrieb:> Stefan L. schrieb:>> Wenn ich ... alles eingehende unverändert wieder rausschicke,>> funktioniert es tadellos.> Was passiert denn, wenn du nicht das gerade empfangene Byte wieder> zurückschickst, sondern einfach ein U (=0x55)? Oder wenn du mit jedem> empfangenen Byte einen Zähler um 1 hochzählst und diesen Zählerstand> dann zurückschickst? Was kommt dann am Terminal an?
Im Falle, dass ich ein konstantes Byte (0x55) bei jedem eintreffenden
Byte zurückschicke, passiert gar nichts (Loopback.vhd Zeile 113-116).
Also empfange am PC nichts (das entsprechende LED am Board leuchtet auch
nicht auf), es wird augenscheinlich nichts geschickt. Ist mir völlig
unverständlich vor allem weil der einfache Loopback funktioniert. Die
Sache mit dem Zähler versuche ich gleich mal noch einzubauen.
Duke Scarring schrieb:> Stefan L. schrieb:>> Die Simulation>> mit einem Testbench funktioniert.> Kannst Du die funktionierende Simulation (VHDL + Testbench) evtl. hier> einstellen (als Anhang)?> Dann könnte ich mir das anschauen und testweise durch meinen Simulator> schicken.>> Duke
Habe alles mal angehängt. Ich gebe zu, der Testbench ist dilettantisch.
Es werden zwei Bytes geschickt, eines das als Datenbyte interpretiert
werden soll und eines als Kommando.
Ich arbeite mal die Arbeitsaufträge weiter ab, falls noch weitere Daten
gewünscht werden, gerne.
Die Simulation läuft nach kleinen Anpassung (LED1, LED2) erstmal durch.
Ist das gewollt, das die Baudrate bei 1,15 MHz ist?
Außerdem würde ich zwischen den Übertragungen auch mal eine kleine Pause
lassen, damit sich das Auge synchronisieren kann :-)
Duke
Duke Scarring schrieb:> Die Simulation läuft nach kleinen Anpassung (LED1, LED2) erstmal> durch.> Ist das gewollt, das die Baudrate bei 1,15 MHz ist?> Außerdem würde ich zwischen den Übertragungen auch mal eine kleine Pause> lassen, damit sich das Auge synchronisieren kann :-)>> Duke
Diese Ungereimtheit mit der Baudrate hat mich etwas stutzig gemacht. Als
Baudrate soll 115200 und als Clock Takt 10 MHz verwendet werden. Ich
habe mal einen etwas "schöneren" Testbench geschrieben. Da scheint es
auch korrekt zu funktionieren, bis auf das erste Byte, das nicht richtig
erkannt wird, wird alles richtig ersetzt und interpretiert. Zumindest
sehe ich hier keinen Fehler.
- s_tx_data[7:0] - Byte das der UART Transmitter sendet
- s_rx_data[7:0] - Byte das der UART Receiver liefert
- s_rx_port - Serieller Eingang
- s_tx_port - Serieller Ausgang
- s_buffer[7:0] - Interner Eingangsbuffer
- s_output[7:0] - Interner Ausgangsbuffer (enthält Kommandos/Daten als
erstes)
- s_rx_rdy - Zeigt an wenn neues Byte im Receiver verfügbar ist
- s_rx_ack - Handshake wenn Byte abgeholt wird
- s_tx_ack - Sendebefehl für Transmitter
- s_tx_rdy - Zeigt an wenn Transmitter bereit ist
Habe das erste Byte markiert, dass vom Receiver empfangen wird und das
zweite Byte, welches der Transmitter verschickt.
Übersetzt werden soll so:
- 1XXXXXXX -> Kommando /
- 11XXXXXX -> Cmd1 -> 0x01
- 10XXXXXX -> Cmd2 -> 0x00
- 0XXXXXXX -> Daten -> unverändert wieder rausgehen
Laut constraints und laut Kommentaren im VHDL-Code erwartest du eine 10
MHz Clock direkt von Pin W5.
Laut Usermanual deines boards ist dort aber eine 100MHz Clock
angeschlossen.
https://digilent.com/reference/_media/basys3:basys3_rm.pdf
Wenn du die einfach so in deine UART einfütterst ist die Einstellung für
die Baudrate um eine Größenordnung zu hoch.
-> entweder das generic clk_cycles_per_bit entsprechend anpassen.
oder aus dem 100 MHz an W5 per DCM einen internen 10 MHz-Takt
generieren.
Achim S. schrieb:> Laut constraints und laut Kommentaren im VHDL-Code erwartest du> eine 10> MHz Clock direkt von Pin W5.>> Laut Usermanual deines boards ist dort aber eine 100MHz Clock> angeschlossen.> https://digilent.com/reference/_media/basys3:basys3_rm.pdf>> Wenn du die einfach so in deine UART einfütterst ist die Einstellung für> die Baudrate um eine Größenordnung zu hoch.>> -> entweder das generic clk_cycles_per_bit entsprechend anpassen.> oder aus dem 100 MHz an W5 per DCM einen internen 10 MHz-Takt> generieren.
Das würde tatsächlich auch diese wirren Ausgaben erklären oder? Linke
Spalte ist was ich reingeschickt habe, s_buffer ist der Eingangsbuffer
vom Uart, s_output der Ausgangsbuffer und Output zeigt, was bei mir am
Terminal ankam. (Bis einschl. 0x7F hätte alles unverändert wieder
rausgehen soll, ab dann entweder 0x00 oder 0x01)
Ich habe naiverweiße gedacht, man kann den Takt mittels der Constraints
festlegen.
Achim S. schrieb:> Laut constraints und laut Kommentaren im VHDL-Code erwartest du> eine 10> MHz Clock direkt von Pin W5.>> Laut Usermanual deines boards ist dort aber eine 100MHz Clock> angeschlossen.> https://digilent.com/reference/_media/basys3:basys3_rm.pdf>> Wenn du die einfach so in deine UART einfütterst ist die Einstellung für> die Baudrate um eine Größenordnung zu hoch.>> -> entweder das generic clk_cycles_per_bit entsprechend anpassen.> oder aus dem 100 MHz an W5 per DCM einen internen 10 MHz-Takt> generieren.
Das war es tatsächlich... Kurz im Code geändert, funktioniert wie es
soll. Sowas dummes...
Vielen Dank Achim und die anderen für die sehr große Hilfe!
Stefan L. schrieb:> Das würde tatsächlich auch diese wirren Ausgaben erklären oder?
Deine UART_RX.vhd überprüft den korrekten Wert des Stop-Bits nicht.
Deswegen werden die empfangenen Bytes nicht wegen ungültigen Wert des
Stop-Bits verworfen sondern als gültiges Byte gezählt. (Mit Kontrolle
des Stopbits wäre zumindest ein Teil der übetragenen Bytes verworfen
worden.)
Und bei den empfangenen Bytes (s_buffer LEDin) sind immer viele
benachbarte Bits auf dem identischen Wert, weil jedes einzelne Bit der
115kBaud Übertragung mehrfach abgetastet und an mehrere benachbarte
Stellen von s_buffer geschrieben wird.
Stefan L. schrieb:> Ich habe naiverweiße gedacht, man kann den Takt mittels der Constraints> festlegen.
das war falsch gedacht. Mit den clock period Constraint teilst du deinem
Synthesetool mit, wie schnell deine Logik laufen soll. Dann wird bei der
Implementierung darauf geachtet, dass sie diese Geschwindigkeit auch
schafft. (Falls nicht werden entsprechende Meldungen ausgegeben).
Stefan L. schrieb:> kurz im Code geändert, funktioniert wie es> soll.
gut, wieder was dazu gelernt ;-)