Forum: Mikrocontroller und Digitale Elektronik serial-port: feststellen, ob write fertig ist


von lutz (Gast)


Lesenswert?

Hallo zusammen.
Ich möchte auf einem Raspberry Daten über die serielle Schnittstelle 
ausgeben. Bedingung dabei: Die write-Funktion sollte genau dann zum 
normalen programm-Ablauf zurückkehren, wenn alle Daten gesendet wurden.
Grund: An der Schnittstelle hängt ein RS485-Konverter, dessen Sendeteil 
ich nach der Übertragung ausschalten muss.
Mit einigen Delay-Anweisungen schaffe ich zwar, dass die Kommunikation 
mit einem Frequenzumrichter (MODBUS) meistens klappt, nur erscheint mir 
diese Lösung alles andere als sauber.
tcdrain klappt nicht.
Hat jemand eine einfache Lösung?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

lutz schrieb:
> Hat jemand eine einfache Lösung?

Nimm eine UART mit entsprechender Hardwareunterstützung, dann musst Du 
Dich nicht darum kümmern. Am einfachsten geht das mit einer USB-UART wie 
dem FT232R, der bietet eine für die Software transparente 
Hardwareunterstützung für RS485-Betrieb.

Andernfalls müsstest Du die UART im SOC des Raspberry Pi genauer 
untersuchen; bietet sie eine Möglichkeit, den Zustand 
"Sendeschieberegister leer" abzufragen? Kann sie gar bei diesem Zustand 
einen Interrupt auslösen?

Die "bessere" UART im Raspberry Pi ist eine PL011, das ist eine an die 
16C650 angelehnte Variante:

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0183g/index.html

.. und die hat keine Hardwareunterstützung für den RS485-Betrieb.

Du müsstest eine Kombination der Flags TXFE (Sendefifo leer) und BUSY 
(Uart sendet) verwenden, um das Ende des Sendens zu erkennen.

Der Sende-Interrupt wird bereits generiert, wenn der Füllstand des 
Sendefifos einen eingestellten Pegel unterschreitet. Einen "ich bin 
jetzt wirklich fertig"-Interrupt gibt es nicht.

Also müsstest Du im Handler für den Sendeinterrupt, wenn Du erkennst, 
daß Du nichts mehr zu senden hast, einen Timer aufziehen und bei dessen 
Ablauf o.g. Flags pollen, um dann Deine RS485-Sende/Empfangs-Umschaltung 
vorzunehmen ...

Das sollte natürlich im Treiber der UART geschehen, nicht in Deiner 
Anwendung (oder programmierst Du "bare bone", d.h. ohne 
Betriebssystem?).

Ist viel Gefrickel, da bist Du mit der USB-UART-Variante deutlich 
einfacher am Ziel.

von Hmmm (Gast)


Lesenswert?

Am Konverter einstellen, dass Du ein Echo der gesendeten Daten bekommst, 
und nach dem Empfang aller gesendeten Zeichen umschalten.

von minifloat (Gast)


Lesenswert?

TCSADRAIN ist nur zum Übernehmen der Einstellung nachdem der Tx-Puffer 
leer ist. Siehe https://www.cmrr.umn.edu/~strupp/serial.html#3_1 
"Setting the Baudrate"

Probier mal (void)ioctl(port, TCFLSH); wie hier beschrieben:
https://www.cmrr.umn.edu/~strupp/serial.html#5_1
mfg mf

von Jim M. (turboj)


Lesenswert?

lutz schrieb:
> Hat jemand eine einfache Lösung?

Man könnte einen für RS485 geeigneten USB2UART Chip nehmen, IIRC kennen 
bestimmte FTDI Chips sowas.

In seltenen Fällen könnnen MCUs die Rx/Tx Umschaltung in Hardware 
erzeugen und an einem GPIO ausgeben, ich kenne sowas z.B. von NXP 
LPC17xx oder Silabs EFM32. Beim RPi müsste man mal ins Hardware Handbuch 
schauen.

Eine Hardwarelösung wäre ein retriggerbarer Monoflop, der den Umschalter 
mit dem Low auf der Tx Leitung verknüpft - und bei high ungefähr nach 
einer Bitzeit den Tx wieder losslässt. Die Baudrate muss dafür aber 
konstant sein.

von Falk B. (falk)


Lesenswert?

@ lutz (Gast)

>Hat jemand eine einfache Lösung?

Man nehme ein Monoflop ala 74HC123 und schalte den Eingang an die 
Sendedaten des UART, den Ausgang an den _RE/DE Pin des MAX485. Die 
Pulszeit stellt man auf ca. 15 Bitlängen ein. Wenn nun die fallende 
Flanke des Startbits kommt, schaltet das MONOFLOP auf HIGH und aktiviert 
damit den Treiber. Jede weitere, fallende Signalflanke macht einen Reset 
der Monoflopzeit (74HC123 ist ein retriggerbares Monoflop). Erst wenn 
keine Daten mehr kommen und das UART-TX Signal dauerhaft HIGH bleibt, 
schaltet das Monoflop wieder auf LOW und damit den Sender ab. Das dauert 
im Extremfall 1,5 Bytezeiten nach der letzten fallenden Flanke im 
Datenstrom.

von Jim M. (turboj)


Lesenswert?

Bei dem voll ausgestattetem UART auf dem RPi könnte man ausprobieren ob 
man das DTR Signal als Richtungsumschalter benutzen kann. Dessen Logik 
ist mir leider nicht klar aus der Doku ersichtlich.

Der mini UART kennt diese Funktion nicht.

von minifloat (Gast)


Lesenswert?

lutz schrieb:
> Hat jemand eine einfache Lösung?

Kann man Hardware-Flow-Control aktivieren, RTS mit CTS verbinden und das 
als Steuersignal für -RE/DE benutzen? mfg mf

von W.S. (Gast)


Lesenswert?

lutz schrieb:
> Ich möchte auf einem Raspberry Daten über die serielle Schnittstelle
> ausgeben. Bedingung dabei: Die write-Funktion sollte genau dann zum
> normalen programm-Ablauf zurückkehren, wenn alle Daten gesendet wurden.

Bedenke mal, daß du zwischen deinem Programm und der HW noch das 
Betriebssystem dazwischen hast, was selbstverständlich die Daten 
zwischenpuffert und für dich unvorhersagbare Zeitabläufe mit sich 
bringt.

Wann also dein Programm überhaupt Rechenzeit kriegt und ob das genau 
dann der Fall ist, wenn tatsächlich alle Daten gesendet wurden, ist sehr 
fraglich.

Also sehe ich als einfache Lösung nur, daß dein Programm anhand der 
Baudrate und der Anzahl gesendeter Zeichen sich ausrechnet, wann die 
Übertragung fertig sein sollte. Dann noch etwas Zeit draufschlagen und 
dann den Sender ausschalten. Aber (s.o.) das kann eben auch mal ne ganze 
Weile später der Fall sein, eben wegen der Zuteilung der Rechenzeit.

W.S.

von lutz (Gast)


Lesenswert?

Vielen Dank.
An das Betriebssystem hab ich gar nicht gedacht. Bleibt wohl nur ein 
Hardwarelösung über Monoflops oder DTR (gibt ja auch die fertigen 
RS485-Converter wo bereits alles eingebaut ist, die ich aber vermeiden 
wollte).

von Hmmm (Gast)


Lesenswert?

lutz schrieb:
> Bleibt wohl nur ein
> Hardwarelösung über Monoflops oder DTR

Was spricht gegen den von mir genannten Ansatz? Kann der Konverter das 
nicht?

von lutz (Gast)


Lesenswert?

Hmmm schrieb:
> Was spricht gegen den von mir genannten Ansatz? Kann der Konverter das
> nicht?

Jetzt kapiere ich erst, was du meinst. Probiere ich gleich mal aus. 
Dagegen könnte aber sprechen, dass meinem Programm nicht die gesamte 
Rechenzeit zur Verfügung steht. Ich weiß nicht genau, nach welcher Zeit 
mein MODBUS-Gegenpart zu reden anfängt. Hab mal was von 50ms gelesen, 
das sollte also leicht reichen.

Vielen Dank, obs erfolgreich war melde ich, sobald ich es weiß.

von lutz (Gast)


Lesenswert?

lutz schrieb:
> obs erfolgreich war melde ich, sobald ich es weiß.

Geht offenbar. Super Idee.

von georg (Gast)


Lesenswert?

lutz schrieb:
> Geht offenbar. Super Idee.

Das mit dem Monoflop funktioniert perfekt, wenn man immer die gleiche 
Baudrate hat, dann kann man die Zeit darauf einstellen. In der Praxis 
ist das fast immer der Fall, nur muss man sich anpassen wenn ein anderes 
System eine andere Geschwindigkeit fährt.

Es ist aber typisch für dieses Forum, dass eine gute Lösung erst einmal 
ignoriert oder abgelehnt wird. Hätte hmmm nicht nachgefasst hätte lutz 
das nie probiert.

Georg

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.