RS-485 Portumschaltung nicht wasserdicht

  • 1
  • 2
  • Page 1 of 2
Thomas.AC
Benutzer
Avatar
Gender: n/a
Age: 43
Posts: 308
Registered: 07 / 2013
Subject:

RS-485 Portumschaltung nicht wasserdicht

 · 
Posted: 21.12.2016 - 14:14  ·  #1
Hallo,

Ich habe ein Problem mit der Portumschaltung.
Die Portumschaltung schaltet den RS485 Senders zu früh ab, wenn der Tx-Puffer zwischenzeitlich geleer wurde, bevor der Tx-Puffer das letzte Byte aufgenommen hat.
Der Portpin für die Portumschaltung wird beim Aufruf von Ser_Enable(false) unmittelbar zurückgesetzt, obwohl die Übertragung des letzten Bytes noch nicht abgeschlossen ist.

Siehe Bild im Anhang: Man erkennt anhand lila Kurve, dass während der Übertragung des zweiten Bytes die Portumschaltung den RS485-Sender deaktiviert. Man beachte die programmierte Verzögerung um 100us.

Workaround: alle interrupts sperren, deren Ausführungszeiten länger als die Übertragung eines UART bytes dauern könnten. Im Fall Multithreading zusätzlich 'lock' verwenden.

Vielleicht kann man den Mechanismus mit der Portumschaltung noch verbessern?

Code

   loop
      mDelay(10);
      Ser_Enable2(true);
      SerOut2($01);
      mDelay(1); // (Stellvertretend für eine Unterbrechung durch Multithreading / interrupt)
      SerOut2($02);
      uDelay(10); //
      Ser_Enable2(false);
   endloop;
Attachments
portumschaltung
Filename: portumschaltung2.PNG
Filesize: 28.86 KB
Title: portumschaltung
Download counter: 149
rh
Administrator
Avatar
Gender:
Location: Germany
Age: 24
Homepage: e-lab.de
Posts: 5558
Registered: 03 / 2002
Subject:

Re: RS-485 Portumschaltung nicht wasserdicht

 · 
Posted: 21.12.2016 - 14:37  ·  #2
Hallo Thomas,

ich bin mir der Problematik bewusst. Das Senden erfolgt ja asynchron zum
Programm Fluss. Das Ser_Enable(false) wird u.U. schon ausgeführt während
das letzte Byte noch nicht verarbeitet ist. Der Treiber prüft die zugehörigen
Status Bits im UART und schaltet u.U. zu früh ab, wenn die Bedingungen
zutreffen.

Ein kleines Testprogramm was das Problem reproduzierbar aufzeigt wäre da
sehr hilfreich.

rolf
Thomas.AC
Benutzer
Avatar
Gender: n/a
Age: 43
Posts: 308
Registered: 07 / 2013
Subject:

Re: RS-485 Portumschaltung nicht wasserdicht

 · 
Posted: 21.12.2016 - 15:33  ·  #3
Hallo Rolf,

vielen Danke für die schnelle Antwort.
Ich würde mich freuen, wenn du die Portumschaltung verbessern könntest (bitte auch an den callback 'onSerTxComplete' denken).


Also, hier das vollständiges Testprogramm.

Code

program TEST;

Device = mega2560, VCC = 5;

import SysTick, watchdog, SerPort2;

define
  ProcClock      = 8000000;
  SysTick        = 10;
  WatchDog       = msec2000;
  StackSize      = $0080, iData;
  FrameSize      = $0080, iData;
  SerPort2       = 38400, Stop1;
  RxBuffer2      = 64, iData;
  TxBuffer2      = 32, iData;
  SerCtrl2       = PortD, 4, positive; // RS-485 ctrl line

implementation
{$IDATA}

begin
  incl(DDRD, 4);  // RS-485 ctrl line port pin to output
  EnableInts;
  loop
    WatchDogTrig;
    mDelay(10);
    Ser_Enable2(true);
    SerOut2($01);
    mDelay(1);
    SerOut2($02);
    uDelay(10); // optional
    Ser_Enable2(false);
  endloop;
end TEST.
rh
Administrator
Avatar
Gender:
Location: Germany
Age: 24
Homepage: e-lab.de
Posts: 5558
Registered: 03 / 2002
Subject:

Re: RS-485 Portumschaltung nicht wasserdicht

 · 
Posted: 22.12.2016 - 14:51  ·  #4
Hallo Thomas,

ich vermute dass der noch nicht leere TxBuffer zum Zeitpunkt von Ser_Enable(false)
das Problem ist. Das nächste/letzte Zeichen wird via Interrupt aus dem Buffer geholt.
Die Funktion Ser_Enable gibt jetzt den Interrupt frei, der den Enable Pin schaltet.
Durch irgendwelche Verzögerungen kommt der Sende Interrupt nach dem Empty
Interrupt. so dass das letzte Zeichen nicht vollständig geschickt wird.

Fazit:
Es muss sichergestellt werden dass der TxBuffer komplett leer ist bevor Ser_Enable den
Treiber umschalten lässt. Das ist nicht trivial, denn wenn als letztes ein langer String
in den TxBuffer gestellt wurde, wird das eine relativ lange Wartezeit bis alle chars
aus dem Buffer raus sind. Ich möchte dieses Warten nicht in den Treiber einbauen,
da diese Wartezeit ja nicht immer notwendig ist. Ich empfehle daher notfalls vor dem
Ser_Enable den TxBuffer zu prüfen:

Code
    repeat
    until _TXCOUNT2 = 0;
    Ser_Enable2(false);

rolf
Thomas.AC
Benutzer
Avatar
Gender: n/a
Age: 43
Posts: 308
Registered: 07 / 2013
Subject:

Re: RS-485 Portumschaltung nicht wasserdicht

 · 
Posted: 22.12.2016 - 17:36  ·  #5
Hallo.
Habe heute keine Zeit für Feedback. Auf die schnelle kann ich einwenden, dass der txBuffer zum Zeitpunkt von setSerEnable(false) bereits leer ist, da das zweite Byte schon von der uart Hardware übertragen wird. Daher denke ich, dass der workaround nicht hilft. Ich melde mich wieder...
Gruß,
Thomas
Thomas.AC
Benutzer
Avatar
Gender: n/a
Age: 43
Posts: 308
Registered: 07 / 2013
Subject:

Re: RS-485 Portumschaltung nicht wasserdicht

 · 
Posted: 22.12.2016 - 23:47  ·  #6
Hallo Rolf,

Vorab lediglich eine Gedankenzusammenfassung darüber, wie ich den Vorgang betrachte.
Ich bin noch nicht dazu gekommen, die Implementierung der Portumschaltung im Assemblercode
nachzuvollziehen.

--------------------------------------------------------------------------------
Kleiner Exkurs zur UART Hardware:

Es existieren ein TX-Data-Register und ein Shift-register
Die CPU schreibt jeweils ein Datenbyte in das TX-Data-Register, das von der
UART Hardware automatisch in das Shift Register übertragen wird, sobald dieses frei ist.
Das Shift register wird dann mit dem Takt der eingestellten Baudrate bitweise geleert.

Bildlich: Tx Data Register -> Shiftregister -> gpio pin (+ Start und Stopbit Generierung)

Zitat datasheet atmega128: "The USART Transmitter has two flags that indicate its state: USART Data Register Empty
(UDRE) and Transmit Complete (TXC). Both flags can be used for generating interrupts."

Es existieren also zwei Interrupt Flags
1.) USART Data Register Empty (UDRE) = TX Daten Register ist leer, welches automatisch gelöscht wird, wenn ein neues byte in das data register geschrieben wird.
2.) Transmit Complete (TXC) = TX Shift Register ist leer, wird automatisch durch den Interrupt gelöscht

Es existieren zwei Interrupts:
1.) USARTx_DRE: TX Daten Register wurde geleert.
2.) USARTx_TXC: shift register wurde geleert und es ist kein weiteres byte im TX-Data Register vorhanden.

--------------------------------------------------------------------------------

Meine Interpretation zum Testcode:

Ausgangsbedingung: alle Register sind leer und keine Interrupts hängen (no pending Interrupts).

[EDIT:] Tatsächlich funktioniert der Treiber etwas anders als hier beschrieben. Mittlerweile kenne ich den Assembler Code.

SetSerEnable(true):
Der Treiber schaltet den Pin für die Portumschaltung ein.

Serout(byte0) + mDelay(1):
1.) Der AVRcco-Treiber schreibt das byte0 sofort in das UART-Daten Register, um das Senden in Gang zu setzen. Der TX-Buffer ist anschließend wieder leer (oder wurde nie gefüllt). Die UART Hardware füllt das shift register sofort mit byte0 (shift register war leer). Die UART Hardware beginnt mit der Übertragung der Bitpulse am TX-GPIO-Pin.
2.) Das Leeren des UART-Daten-Register führt zu einem TXE-Interrupt.
3.) Wenn die UART Hardware das Shift Register komplett geleert hat, kommt es zum TXC Interrupt.
4.) Alle Interrupts wurden bedient (TXE und TXC). Die Bedingung für eine RS485-Abschalung wurde auf 'true' gesetzt, da keine weiteren Daten zum Senden vorhanden sind.

Bemerkung: Zu diesem Zeitpunkt sollte ein 'SetSerEnable(false)' den Pin sofort zurücksetzen können, daher ist die Bedingung 'true' für eine RS485-Abschalung wichtig. In diesem Fall werden wird aber ein weiteres Byte an den Treiber übergeben.

Serout(byte1):
5.) Der AVRcco-Treiber schreibt das byte1 sofort in das TX-Daten Register, um das Senden wieder in Gang zu setzen.
Der TX-Buffer ist anschließend wieder leer (oder wurde nie gefüllt).
Die UART Hardware füllt das shift register sofort mit dem byte1 (shift register war frei).
UART Hardware beginnt mit der Übertragung der Bitpulse am TX-GPIO-Pin
6.) Das Leeren des TX-Daten-Register führt zu einem TXE-Interrupt.

uDelay(10): (das ist eine optionale Verzögerung, damit am Oszilloskop das Senden von byte 1 am RS485 Bus zu sehen ist)
7.) Der Pin für die Portumschaltung bleit noch für weitere 100 us eingeschaltet.

SetSerEnable(false):
8.) Der Treiber Schaltet den Pin für Portumschaltung sofort aus, da im Punkt 4.) die Bedingung für ein Abschalten bereits erreicht wurde.
8.) Das TXC Flag wurde zwischenzeitlich gesetzt. Der Aufruf von Ser_Enable(false) aktiviert jetzt den TXC Complete Interrupt ohne das Flag zu löschen. Der TXC-Interrupt wird sofort ausgeführt und dort wird der Pin zurückgesetzt.

Meiner Meinung nach, fehlt zwischen Punkt 4 und 5 das Rücksetzten der Bedingung für das Ausschalten des Pins für die Portumschaltung.

Kannst du meine Gedankengänge nachvollziehen?

Ich bleibe dabei, eine Treiber-Optimierung an dieser Stelle ist meiner Meinung nach wertvoll.
Ob dies möglich ist, kann ich zur Zeit nicht behaupten. Aber mein Gefühl sagt, dass es gehen müsste.

Gruß,
Thomas
Harald_K
 
Avatar
 
Subject:

Re: RS-485 Portumschaltung nicht wasserdicht

 · 
Posted: 23.12.2016 - 01:12  ·  #7
tschuldige mal, aber da gibts nen Denkfehler:

du mußt jedesmal, wenn du ein Byte in den Sendepuffer schiebst, das RS-485-Abschalt-enable-bit auf false setzen - dann klappt es auch mit dem Senden im Punkt 5, weil das Abschalten ja wieder disabled wird bis zum zugehörigen TxE-Int

Letztlich mußt du sowieso überlegen, wie du erkennen willst, wann die Übertragung fertig ist - kein RS-485-System läßt es zu, daß du deine zu einem Datenblock gehörenden Bytes sozusagen einzeln versendest, weil das auf unbestimmte Zeit den Bus blockiert.
Thomas.AC
Benutzer
Avatar
Gender: n/a
Age: 43
Posts: 308
Registered: 07 / 2013
Subject:

Re: RS-485 Portumschaltung nicht wasserdicht

 · 
Posted: 23.12.2016 - 10:29  ·  #8
Danke Harald.

Das Testprogramm ist eine Simulation für eine Unterbrechung von SeroutBlock durch einen Threadwechsel oder Auftreten eines Interrupts.
Die Unterbrechung wird mit mDelay(1) simuliert.

Ich würde doch niemals in Senderoutinen mDelay verwenden, was denkst du von mir? :-)

Hinweis: Habe Punkt 8 korrigiert

Gruß
Thomas
  • 1
  • 2
  • Page 1 of 2
Selected quotes for multi-quoting:   0

Registered users in this topic

Currently no registered users in this section

The statistic shows who was online during the last 5 minutes. Updated every 90 seconds.
MySQL Queries: 16 · Cache Hits: 15   141   156 · Page-Gen-Time: 0.038958s · Memory Usage: 2 MB · GZIP: on · Viewport: SMXL-HiDPI