Forum: FPGA, VHDL & Co. [Verilog] Warum ist hier die Ausgabe bitte 1,3,5,7.und nicht 1,2,3,4,5


von otto (Gast)


Lesenswert?

Hallo, guten Tag.
Warum ist die serielle Ausgabe bitte 1,3,5,7....und nicht 1,2,3,4,5...

Danke.
Gruss
1
module rs232tx(input clk, output UART_TX);
2
  reg [9:0] sendbuf = 9'b000000001;
3
  reg [7:0] data = 0;
4
  reg send = 0;
5
  reg sending  = 0;
6
 
7
  reg [13:0] timeout;
8
  assign UART_TX = sendbuf[0];
9
 
10
  always @(posedge clk) begin
11
    if (send && !sending) begin
12
      sendbuf <= {1'b1, data, 1'b0};
13
      sending <= 1;
14
      timeout <= 1406 - 1; 
15
    end else begin
16
      timeout <= timeout - 1;
17
    end
18
    
19
    if (sending && timeout == 0) begin
20
      timeout <= 1406 - 1; 
21
      if (sendbuf[8:0] == 9'b000000001) begin
22
        sending <= 0;
23
      end else
24
        sendbuf <= {1'b0, sendbuf[9:1]};
25
    end 
26
  end
27
  
28
  always @(posedge clk) begin
29
    if (data < 100 && sending == 0) begin
30
     data <= data+1;
31
     send <= 1;
32
    end else begin
33
      send <=0;
34
   end
35
  end
36
endmodule

: Bearbeitet durch Admin
von Stefan F. (Gast)


Lesenswert?

Diese Programmiersprache habe ich noch nie gesehen. Ich rate mal:

Es scheint hier zwei konkurrierende Threads zu geben:

1) Der obere Thread sende Daten.
2) Der untere Thread erzeugt die Daten.

Beabsichtigt war wohl dass der untere Thread die Variable "data" immer 
dann um 1 erhöht (und das Senden startet), wenn der Sender nicht aktiv 
ist.

Dazu setzt der Sender wiederum seinen Status in der Variable "sending".

Der Fehler besteht in der fehlenden Synchronisation dieser Prozesse. 
Wenn die Threads durch einen aktiven Task-Scheduler ausgeführt werden 
(also immer ein bisschen von jedem Thread), könnte sich folgender Ablauf 
ergeben:
1
Thread 2:
2
if (data < 100 && sending == 0) begin
3
     data <= data+1; // Data wird von 0 nach 1 erhöht
4
     send <= 1;
5
6
Thread 1:
7
if (send && !sending) begin
8
      sendbuf <= {1'b1, data, 1'b0};
9
10
Thread 2:
11
// Achtung: sending ist immer noch 0!
12
if (data < 100 && sending == 0) begin
13
     data <= data+1; // Data wird von 1 nach 2 erhöht
14
     send <= 1;
15
16
Thread 1:
17
      sending <= 1;
18
      timeout <= 1406 - 1;

Ebenso kann der selbe Fehler auftreten, wenn das Programm auf mehreren 
CPU's oder CPU Kernen ausgeführt wird.

Du brauchst einen zuverlässigen Mechanismus, um die Prozesse zu 
synchronisieren. Zum Beispiel, indem du irgendwie verhinderst, dass die 
folgenden Zeilen von Thread1 für andere Threads unterbrochen werden:
1
// Andere Threads pausieren
2
if (send && !sending) begin
3
      sendbuf <= {1'b1, data, 1'b0};
4
      sending <= 1;
5
// Andere Threads fortfahren

Manche CPU's haben dazu einen speziellen Befehl, der eine Variable 
testet und zugleich setzte. In Pseudo-Code nach diesem Prinzip:
1
if (ändere sending von 0 nach 1 und wenn das geklappt hat, dann)
2
  // sende daten
3
end

Hier findet die Änderung und der Test in einer einzigen nicht 
unterbrechbaren Operation statt. Andere Threads sehen daher niemals 
einen falschen Zwischenstatus.

Auf Mikrocontrollern sieht man als einfach Lösung oft, dass kurzzeitig 
alle Interrupts deaktiviert werden. Dadurch wird der aktuelle Thread 
garantiert nicht unterbrochen.

Auf PC stellen Linux und Windows dafür spezielle Funktionen bereit, die 
in der Regel vom Framework der Anwendung gekapselt und benutzt werden.

Die richtigen Suchwörter zu dem Thema sind: Synchronisierung, Threads, 
Concurreny, Mutex, Atomare Zugriffe

von Peter II (Gast)


Lesenswert?

Stefan U. schrieb:
> Diese Programmiersprache habe ich noch nie gesehen. Ich rate mal:

falsch geraten:

schau mal wo der Thread ist:

FPGA, VHDL & Co.


Das ist gar keine Programmiersprache

von Stefan F. (Gast)


Lesenswert?

Nachtrag zum möglichen Ablauf:

Die Variable data wurde nun schon zweimal erhöht, bevor sie gesendet 
wurde. Die Schrittweite 2, die du beobachtest hast ist mehr oder weniger 
ein Zufallsprodukt. Die Schrittweite könnte auch viel größer sein oder 
unregelmäßig.

von Stefan F. (Gast)


Lesenswert?

> Das ist gar keine Programmiersprache

Oh mein Fehler. Mit FPGA's kenne ich mich gar nicht aus. Aber ich 
glaube, die führen viele Aktionen zeitgleich aus - insofern passt meine 
Überlegung trotzdem Auch wenn es gar keine CPU's sind.

von Achim S. (Gast)


Lesenswert?

hast du einen Simulator zur Hand?

Dann nutz den mal, und schau dir an, wann send aktiv wird, wann sending 
aktiv wird und in welchen Taktzyklen data hochgezählt wird.

Stefan U. schrieb:
> ie Schrittweite könnte auch viel größer sein oder
> unregelmäßig.

Nein: die Schrittweite wird immer genau 2 sein.

von FRANK (Gast)


Lesenswert?

Peter II schrieb:

> Das ist gar keine Programmiersprache

Auch eine Hardware-Beschreibungssprache ist eine Programmiersprache.

von Peter II (Gast)


Lesenswert?

FRANK schrieb:
> Auch eine Hardware-Beschreibungssprache ist eine Programmiersprache.

hast du dafür einen beleg?

Unter Programmiersprachen finde ich nicht VHDL, und unter VHDL finde ich 
nicht das es eine Programmiersprache ist.

von Markus F. (mfro)


Lesenswert?

Peter II schrieb:
> Unter Programmiersprachen finde ich nicht VHDL, und unter VHDL finde ich
> nicht das es eine Programmiersprache ist.

... seit Peter Otto heißt, nutzt er Verilog. Und wahrscheinlich tut's 
deswegen nicht ;)

von Andi (Gast)


Lesenswert?

Markus F. schrieb:
> ... seit Peter Otto heißt, nutzt er Verilog. Und wahrscheinlich tut's
> deswegen nicht ;)

Wenn sich sein Benehmen so bessert wie die Wahl der Beschreibungsprache 
gibts ja noch Hoffnung ;-)

Um Achim S. Hinweise etwas zu verdeutlichen:
Wenn 'sending' = 0 wird zählst du hoch.
Wenn du hochzählst setzt du im gleichen Takt 'send'.
Wenn 'send' gesetzt ist wird im nächsten Takt 'sending' gesetzt.
Wieviele Takte lang ist dann 'if (data < 100 && sending == 0)' wahr?

Du musst also in der if Bedingung noch etwas verwenden das sich schon im 
nächsten Takt geändert hat. 'send' würde sich da anbieten...

Andi

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


Lesenswert?

FRANK schrieb:
> Auch eine Hardware-Beschreibungssprache ist eine Programmiersprache.
So wie ein Traktor und ein LKW natürlich auch ein Automobil ist, weil 
sie sich selbständig bewegen...

otto schrieb:
> Warum ist die serielle Ausgabe bitte 1,3,5,7
Die Ursache ist Latency. Im Simulator siehst du, dass sending 2 Takte 
lang 0 ist...

Schreib da unten mal sowas:
1
  always @(posedge clk) begin
2
    if (data < 100 && sending == 0 && send == 0) begin
3
     data <= data+1;
4
     send <= 1;
5
    end else begin
6
      send <=0;
7
   end
8
  end

Stefan U. schrieb:
> Die Schrittweite ... ein Zufallsprodukt. Die Schrittweite könnte auch
> viel größer sein oder unregelmäßig.
Sie ist in dem Fall hier vollkommen deterministisch und immer '2'. Das 
ist das Schöne an der Hardware... ;-)

: Bearbeitet durch Moderator
von Stefan F. (Gast)


Lesenswert?

>> Die Schrittweite ... ein Zufallsprodukt. Die Schrittweite könnte auch
>> viel größer sein oder unregelmäßig.

> Sie ist in dem Fall hier vollkommen deterministisch und immer

Ich war ja auch fälschlicherweise von einem Mikroprozessor mit einem 
Multitaksing OS ausgegangen.

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


Lesenswert?

Stefan U. schrieb:
> Ich war ja auch fälschlicherweise von einem Mikroprozessor mit einem
> Multitaksing OS ausgegangen.
Ja, da ist das Ganze eher zufällig und nicht so einfach nachvollziehbar. 
Deshalb mag ich Hardware... ;-)

von otto (Gast)


Lesenswert?

Ja jetzt funktioniert es.

Danke.
Gruss

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


Lesenswert?

Lothar M. schrieb:
> Schreib da unten mal sowas:  ...
Besser wäre sogar sowas:
1
  always @(posedge clk) begin
2
    if (data < 100 && sending == 0 && send == 0) begin
3
     data <= data+1;
4
     send <= 1;
5
    end
6
    if (sending == 1) begin
7
      send <=0;
8
    end
9
  end
Denn dann würde das Flag send erst quittiert, wenn tatsächlich mit dem 
Senden begonnen worden wäre und dies über das Flag sending angezeigt 
wird...

: Bearbeitet durch Moderator
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.