 Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Ich benötige einen zusätzlichen Ausgang der vor dem Senden gesetzt wird,
und wollte dazu den RTS Pin benutzen, den ja die meisten USB zu TTL
Adapter haben. Jetzt habe ich festgestellt, dass das RTS Signal immer
mindestens 1ms auf dem selben Pegel bleibt. Ich kann also maximal 500Hz
erzeugen.
Das habe ich mit einem CH340 Klon und einem FTDI FT232BL probiert, und
beide machen diese 1ms.
Deshalb ist meine Vermutung, dass das irgendwo im Treiber eingestellt
ist. Ich benutzte Ubuntu 22.04.2 LTS. Das Programm, das ich zum testen
verwende, ist in Python (3.10.6) geschrieben und benutzt pyserial in der
Version 3.5:
1 | import serial
| 2 |
| 3 | port = serial.Serial("/dev/ttyUSB1", 40000, stopbits=serial.STOPBITS_ONE, timeout=0)
| 4 |
| 5 | print(serial.VERSION)
| 6 |
| 7 | while True:
| 8 | port.rts = True
| 9 | port.rts = False
|
Kann man dieses Timing irgendwo einstellen?
Dass Python so langsam ist, glaube ich nicht, das Programm läuft auf
einem Ryzen 5 5625U mit bis zu 4.3GHz.
Vielleicht kann mir hier ja jemand weiterhelfen.
Linux und erst recht USB sind von Hause aus nicht echtzeitfähig.
Du hast da einfach gewisse Latenzen, bevor so ein einzelnes USB-Paket
überhaupt abgesendet wird. 1ms ist schon eher bestcase und du musst
damit rechnen das da auch mal sporadisch bis zu 100ms Pause oder so drin
sind. Für irgendwas mit einem definierten Timing ist USB einfach nicht
vorgesehen und daher ungeeignet.
- Beitrag "USB Latenz im Millisekundenbereich?"
- https://wiki.archlinux.org/title/mouse_polling_rate
(mouse/hid ist zwar andere Richtung, dass grundlegende Verhalten ist
aber ähnlich)
Wenn du was genaues brauchst, nehme einen µC und verwenden den in dem du
dann z.B. per USB sagst "mach 100 Impulse von 0,5ms im Abstand von 1
ms". Dann kannst du dich da auch drauf verlassen (aber nicht darauf wann
die 100 Impulse wirklich anfangen).
Georg P. schrieb:
> Jetzt habe ich festgestellt, dass das RTS Signal immer
> mindestens 1ms auf dem selben Pegel bleibt.
[...]
> Kann man dieses Timing irgendwo einstellen?
Einstellen kannst du das garnicht. Du könntest höchstens einen anderen
USB-Serial-Adapter verwenden, nämlich einen, der mittels HighSpeed
kommunizieren kann (selten und teuer). Damit hast du dann eine Latenz
von 250µs, also ein Viertel von dem der üblichen FullSpeed-Adapter.
So weit die Theorie. In der Praxis ist es aber oft so, dass
minderweitertige Treiber, Firmwares und teildefekte oder ungeeignete
Hardware dafür sorgen, dass sich so ein Buszyklus (der eigentlich dafür
da ist, zumindest die genannten Latenzen zu garantieren) auch mal
verschluckt. Am wahrscheinlichsten bei der Anmeldung neuer Geräte am
Bus.
Das sollte zwar nicht so sein, passiert aber in der Praxis doch recht
häufig. Man ist also gut beraten, nicht darauf zu setzen, dass die
Zykluszeit (und damit die Latenzen) wirklich konstant und
unerschütterlich stabil ist.
Zusammenfassend: dein Ansatz ist eine ganz schlechte Idee. Dafür ist USB
schlicht nicht gedacht. Das ist auf hohen Durchsatz optimiert, nicht auf
geringe Latenzen.
Danke, ich dachte mir schon, dass es am USB liegt.
Eigentlich wollte ich ja einen Break senden, aber das dauert ja noch
länger. Unter Linux wohl mindestens 0,25s. Das Protokoll das ich habe
startet immer mit einem Break und hat 8N1. Die Pakete sind meist nur 4
Bytes lang. Das sind dann gerade Mal 4 Pakete pro Sekunde.
Ich habe auch schon probiert die Baudrate zu ändern, aber das ist auch
sehr langsam.
Ein Portpin war noch frei, also dachte ich, vielleicht ist es damit
besser. Ist es auch, aber ich dachte es wäre noch schneller.
Ich dachte auch daran ein Paritybit für den Break anzuhängen, aber da
dazu auch die Konfiguration der Schnittstelle geändert werden muss, ist
es wohl dasselbe wie beim Ändern der Baudrate.
Eine Möglichkeit wäre jetzt noch den Break in einem zusätzlichen
Datenbit zu senden, also 9N1 statt 8N1. Gibt es USB-Adapter die so etwas
können? Bis jetzt habe ich nichts gefunden.
Vermutlich bleibe ich dann bei der Lösung mit dem RTS. Ist bis jetzt das
schnellste und benötigt keine Sonderlösung.
VG
Georg P. schrieb:
> Eigentlich wollte ich ja einen Break senden, aber das dauert ja noch
> länger. Unter Linux wohl mindestens 0,25s. Das Protokoll das ich habe
> startet immer mit einem Break und hat 8N1.
Hört sich irgendwie stark nach DMX an...
Und natürlich ist ein Break nicht zwingend mindestens 250ms lang. Wie
lang der ist, hängt von der Baudrate ab, auf die die Schnittstelle
konfiguriert ist.
Baudrate und Status Leitungen werden über USB via Control Requests
eingestellt, das wird bei Fullspeed nicht wesentlich schneller, da für
Controll Requests nur 10% der gesammten Bandbreite vorgesehen ist. Das
passt schon ganz gut zu 1 Request pro ms.
C-hater schrieb:
> Und natürlich ist ein Break nicht zwingend mindestens 250ms lang. Wie
> lang der ist, hängt von der Baudrate ab, auf die die Schnittstelle
> konfiguriert ist.
Ich weiß manche Controller machen einfach ein paar Bits länger.
Aber in meinem Fall macht pyserial das so. Hängt wohl mit termios
zusammen. Soweit ich gelesen habe ruft pyserial tcsendbreak() aus
termios auf. Und das macht irgendwas zwischen 0.25 und 0.5s. Wenn man
eine Zeit übergibt, dann steht in der Beschreibung: If duration is not
zero, it sends zero-valued bits for some implementation-defined length
of time.
Also nichts genaues weiß man nicht.
Leider bezieht sich alles was ich im Netz gefunden habe auf
tcsendbreak().
Und ich möchte dafür auch nicht selbst irgendwas machen, es sollte schon
mit Standardhardware funktionieren.
Bei mir war der Break jedenfalls immer ziemlich lang. Aber auch das muss
ja über USB und wird dann wohl nicht schneller sein als der RTS.
P.S. Ist kein DMX, ist was in Anlehnung an LIN selbst gemachtes.
Da kann man noch was anpassen. Ich hatte auch Mal die Idee ein Byte auf
zwei 6Bit Werte aufzuteilen, dann muss aber die Baudrate hoch und mehr
als die eingestellten 40kBaud sollen es nicht werden, sonst wird wohl
der Empfänger (AVR) überlastet.
Danke nochmals,
VG
Georg P. schrieb:
> Ich benötige einen zusätzlichen Ausgang der vor dem Senden gesetzt wird,
> und wollte dazu den RTS Pin benutzen, den ja die meisten USB zu TTL
> Adapter haben.
Und was genau soll dieser Ausgang machen? Etwa einen RS485-Treiber
ansteuern? Dafür haben die meisten USB-Seriell-Bridges dedizierte
Steuerausgänge, die sie vollautomatisch in Hardware ansteuern, sobald
sie senden. Per Software an irgendwelchen Leitungen rumwackeln muss man
da gar nicht.
Und wenn Du einen längeren Impuls brauchst, häng' da halt ein Monoflop
dran.
Der Impuls soll den Anfang eines Datenpakets markieren.
Das mache ich normalerweise mit einem Break-Signal.
Ich habe einen Bus, wo das so passiert, und diesen will ich jetzt
mit dem PC verbinden. Dazu würde ich gerne dasselbe Protokoll benutzen,
und nicht wieder irgendwas neues machen. Da das mit dem Break vom PC aus
noch viiieeel langsamer ist, suche ich nach einer anderen Möglichkeit
dafür.
Die Ziele sind, dass es mit Standard USB-UART-Wandlern funktioniert,
dass es hinreichend schnell ist (also die 40kBaud gut ausnutzt), und
dass die Änderungen am Protokoll möglichst klein sind.
Da noch ein Portpin frei ist, schien mir das mit dem RTS-Ausgang eine
gute Lösung zu sein. Den haben die meisten Adapter.
Da, wie man auf dem angehängten Screenshot sieht, die Daten schon kurz
nach dem Setzen des RTS gesendet werden, sich Daten und Steuersignale
wohl überlappen, kann man damit immerhin 500 Datenpakete pro Sekunde
schicken.
Das ist schon Mal deutlich mehr als bei Benutzung des Breaks.
Die eigentliche Frage war jetzt, ob man das noch ein bisschen
beschleunigen kann. Sieht aber wohl nicht so aus.
VG
Georg P. schrieb:
> Der Impuls soll den Anfang eines Datenpakets markieren.
Und der "Impuls" soll während des Datenpaketes dann irgendwann aufhören?
Wie lange vor dem Beginn des Datenpaketes soll denn Dein "Impuls"
beginnen?
Mit der von mir vorgeschlagenen Kombination aus der
RS485-Treibersteuerung und gegebenenfalls einem Monoflop (retriggerbar)
bekommst Du ein Signal, das während des gesamten Datenpakets aktiv ist,
und das sehr knapp vor dem Beginn des Datenpakets aktiv wird.
Das Monoflop ist nur dazu da, um etwaige kurze Pausen zwischen den
einzelnen gesendeten Bytes zu überbrücken.
Du kannst ja, falls das Oszillogramm da oben mit einem FT232 o.ä.
erstellt wurde, zusätzlich noch das Signal TXDEN einblenden. Das ist
beim FT232RL üblicherweise auf CBUS2.
Andere USB-UARTs haben auch derartige Signale.
Was ist das für ein Protokoll? 40 kBaud ist eine sehr ungewöhnliche
Baudrate; ist das was selbstgebratenes?
Harald K. schrieb:
> Und der "Impuls" soll während des Datenpaketes dann irgendwann aufhören?
>
> Wie lange vor dem Beginn des Datenpaketes soll denn Dein "Impuls"
> beginnen?
>
Es reicht eine Flanke um zu erkennen, dass jetzt ein neues Datenpaket
kommt. Die soll natürlich möglichst lang genug vor den Daten kommen,
damit der Portinterrupt immer vor dem seriellen Receiverinterrupt kommt.
Zurückgesetzt kann er dann irgendwann werden. Laut Messung scheint das
zu passen, ich habe es aber noch nicht probiert.
> Mit der von mir vorgeschlagenen Kombination aus der
> RS485-Treibersteuerung und gegebenenfalls einem Monoflop (retriggerbar)
> bekommst Du ein Signal, das während des gesamten Datenpakets aktiv ist,
> und das sehr knapp vor dem Beginn des Datenpakets aktiv wird.
>
> Das Monoflop ist nur dazu da, um etwaige kurze Pausen zwischen den
> einzelnen gesendeten Bytes zu überbrücken.
>
> Du kannst ja, falls das Oszillogramm da oben mit einem FT232 o.ä.
> erstellt wurde, zusätzlich noch das Signal TXDEN einblenden. Das ist
> beim FT232RL üblicherweise auf CBUS2.
>
> Andere USB-UARTs haben auch derartige Signale.
>
Ja, das wäre auch eine Lösung, nur von den beiden Adaptern die ich hier
habe hat keiner dieses Signal herausgeführt, RTS aber schon. Falls ich
einen eigenen USB-Seriell-Wandler machen muss, wäre das wohl die beste
Lösung (wenn es nicht zu knapp vor den Daten kommt, siehe oben). Aber
wie gesagt, ich wollte was von der Stange nehmen.
> Was ist das für ein Protokoll? 40 kBaud ist eine sehr ungewöhnliche
> Baudrate; ist das was selbstgebratenes?
>
Ja, es ist was selbstgebratenes.
Georg P. schrieb:
> Es reicht eine Flanke um zu erkennen, dass jetzt ein neues Datenpaket
> kommt. Die soll natürlich möglichst lang genug vor den Daten kommen,
> damit der Portinterrupt immer vor dem seriellen Receiverinterrupt kommt.
Wenn Du das von mir vorgeschlagene Steuersignal verwendest, hast Du bei
Deinen 40 kBaud etwa 250 µsec Zeit, nämlich die Dauer für das Senden
eines Bytes. Das belegt auf der Leitung zehn Bitzeiten (bei 8n1, nämlich
ein Start-, ein Stop- und acht Datenbits).
Deine empfangende UART löst ihren Rx-Interrupt natürlich erst dann aus,
wenn sie das Zeichen auch empfangen hat. Das Steuersignal aber wird vor
dem Beginn der Übertragung des Startbits gesetzt.
Warum muss ein Datenpaket bei Deinem Protokoll angekündigt werden? Was
ist der tiefere Sinn davon?
Wenn ich ein spezielles Timing, zB fuer kurze Reaktionszeit bei hohem
Durchsatz will, lagere ich diese Funktionalitaet auf einen AVR aus,
welcher dann per USB am PC angeschlossen ist. Der USB bringt die hohen
Blocklaengen bei hoher Geschwindigkeit, der AVR macht das Timing. Muss
halt etwas buffern.
zB einen schnellen ADC an einem schnellen Bus per kurzen Packeten
angeschlossen, auf einen PC bringen. Die kurzen Packete werden einzeln
quitiert.
Harald K. schrieb:
> Warum muss ein Datenpaket bei Deinem Protokoll angekündigt werden? Was
> ist der tiefere Sinn davon?
Zum synchronisieren, z.B. wenn der Empfänger abgeschaltet war.
Der Busmaster fragt zyklisch Adressen ab, aber nicht alle Empfänger
sind aktiv, sie können zwischendurch schlafen gehen, wenn nichts zu tun
ist. Nach dem Aufwachen müssen sie erkennen können, wann ein Telegramm
beginnt. Für den Anschluss zum PC soll dasselbe Protokoll verwendet
werden (evtl. mit kleinen Änderungen). In diesem Fall ist der PC der
Busmaster und der Empfänger hat eine vom PC unabhängige Versorgung, so
dass auch hier eine Synchronisation notwendig sein kann.
VG
Purzel H. schrieb:
> Wenn ich ein spezielles Timing, zB fuer kurze Reaktionszeit bei hohem
> Durchsatz will, lagere ich diese Funktionalitaet auf einen AVR aus,
Wie ich schon geschrieben habe würde ich gerne "normale" USB zu UART ICs
verwenden und mir nicht noch eine Baustelle aufmachen. Sollte es gar
nicht funktionieren kann ich das ja immer noch.
VG
Georg P. schrieb:
> Zum synchronisieren, z.B. wenn der Empfänger abgeschaltet war.
Das macht man üblicherweise mit einem sinnvoll aufgebauten Protokoll -
erst wenn ein Paket mit funktionierender Prüfsumme empfangen wird, wird
es akzeptiert. Pakete werden durch Pausen separiert.
Sieh Dir Modbus/RTU an, da wird so ein Verfahren verwendet.
Was passiert bei Deinem "Protokoll", wenn ein Empfänger während des
Sendend eingeschaltet wird? Er erkennt (fälschlich) das
Paketbeginnsignal und decodiert falsche Daten.
Wie auch immer:
Das Steuersignal der USB-Seriell-Bridge ist für Deinen Zweck ausreichend
lange vor Beginn des Pakets aktiv, allerdings wird es erst nach
vollständigem Senden des Paketes wieder inaktiv. Wenn Deine Empfänger
nur auf eine Flanke des Signales reagieren, ist das aber kein Problem.
Schau dir den FT232R genauer an, insbesondere den Pin CBUS2. Eventuell
tut es die Hardware von selber was du brauchst.
Michael X. schrieb:
> Schau dir den FT232R genauer an, insbesondere den Pin CBUS2.
Davon rede ich hier die ganze Zeit.
Harald K. schrieb:
> Das macht man üblicherweise mit einem sinnvoll aufgebauten Protokoll -
> erst wenn ein Paket mit funktionierender Prüfsumme empfangen wird, wird
> es akzeptiert. Pakete werden durch Pausen separiert.
>
Bei dem Protokoll das ich habe wird der Paketanfang durch einen Break
signalisiert. Da ich das Protokoll auch für den PC-Anschluss verwenden
will muss ich das also irgendwie anders kenntlich machen. Zusätzliche
Pausen möchte ich eigentlich aus Durchsatzgründen nicht haben.
> Was passiert bei Deinem "Protokoll", wenn ein Empfänger während des
> Sendend eingeschaltet wird? Er erkennt (fälschlich) das
> Paketbeginnsignal und decodiert falsche Daten.
Dann wartet der Empfänger bis er einen Break erkennt. Erst danach werden
Daten akzepiert. Prüfsumme gibt es natürlich zuätzlich.
Wie ich schon Mal geschrieben habe, ist das Protokoll an das
LIN-Bus-Protokoll angelehnt. Da wird es so gemacht. Da das im Fahrzeug
schon lange verwendet wird, sollte es wohl funktionieren. Die
Spezifikation dafür kann man sich bei https://www.lin-cia.org/standards/
runterladen.
Wie ich schon geschrieben habe, haben die Adapter die ich hier habe das
RS485 Signal (TXDEN) nicht.
Ich habe einen mit dem FT232BL, der Chip hat das Signal, aber es ist
nicht herausgeführt.
Die anderen sind irgendwelche CH340 Kopien, da habe ich kein Datenblatt
davon, sie sind zwar im selben Gehäuse wie der CH340, haben aber eine
komplett andere Pinbelegung.
Außerdem habe ich schon genug Baustellen, da muss ich nicht noch einen
USB zu seriell Adapter selber machen. Nur wenn es gar nicht anders geht.
Aber das mit dem RTS sieht ja ganz gut aus. Ich bin gerade am Testen.
Danke für die vielen Vorschläge.
VG
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
|