Forum: PC-Programmierung SerialPort Rx Puffer Überlauf mit Vista aber nicht bei XP


von Markus (Gast)


Lesenswert?

Hallo Leute,


habe folgendes Problem :

Ich habe mit VisualBasic.net eine Bedienoberfläche programmiert, mit der 
ich Daten von meiner Microcontrollerplatine über die RS232 empfange. Die 
Oberfläche zeichnet die Daten wie bei einem Oszilloskop über die Zeit 
auf.

Um dem PC genügend Zeit zu geben, die Daten einzulesen und auszuwerten, 
habe ich nach jeder kompletten "Frame" die vom µC gesendet wird, eine 
Pause in dessen Programm angehängt. Die Pausenzeit bis zur nächsten 
Controller Frame wurde so gewählt, das der Empfangspuffer des PC´s 
konstant bleibt und nicht überläuft. Ansonsten werden falsche Daten 
empfangen was man im Diagramm als Linienabrisse sofort erkennen kann.
Das alles wurde auf meinem Desktoprechner mit Windows-XP und einer 
On-Board Rs232 Schnittstelle programmiert. Prozessor ist ein Athlon64 
3000+ mit 2GB Ram

Wenn ich jetzt das Programm auf meinem Laptop laufen lasse (Intel Core 2 
Duo 3GB Ram mit dem Serial RS-232 Expresscard Adapter EX-1370 und 
Windows Vista Home Premium), läuft mir mit den selben Einstellungen der 
Empfangspuffer in windeseile voll.
Was mir dabei aber aufiel, ist das es scheinbar zu keinem Datenverlust 
führt wenn der Puffer überläuft, jedoch ist das Zeichnen alles andere 
als flüssig, vielmehr werden die Daten "Etappenweise" in der Picturebox 
gezeichnet, und irgendwann hängt sich das ganze dann komplett auf. Die 
Prozessorauslastung beider Kerne ist gerad einmal 20%.Auf Handshake 
Verfahren will ich aufgrund fehlender Pinbelegung am Controller 
verzichten , da es ja auch auf meinem Desktop-PC ohne klappt.

Wo könnte hier das Problem liegen ? An Leistungsdefiziten des Laptops 
kann es ja nicht liegen. Evtl. aber an der Seriellen Schnittstelle über 
die Expresscard ??


Danke fürs lesen
gruss Maggus ;)

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Das kann sehr wohl an der Schnittstelle in der ExpressCard liegen. Die 
wird nämlich mit recht hoher Wahrscheinlichkeit als USB-Seriell-Adapter 
implementiert sein - ja, das sieht die ExpressCard-Spezifikation vor.

Das kannst Du selbst herausfinden, indem Du mal im Gerätemanager 
nachsiehst, a) was für ein Devicetreiber verwendet wird und b) Dir mal 
die Eigenschaften des Gerätes ansiehst. Üblicherweise wird dort ein 
"Ort" genannt, und bei USB-Geräten steht dort korrekt "USB" ...

von Ralf (Gast)


Lesenswert?

Du kannst ja auch ohne zusätzliche Pins Handshake implementieren, und 
zwar auf Protokoll-Ebene. Du definierst also um die eigentlichen 
Nutzdaten noch einen Header am Anfang, bzw. eine Checksumme und ein 
spezielles Zeichen am Ende als Endeerkennung und zur Synchronisierung. 
Der Controller sendet dieses Paket zum Rechner. Wenn der PC das Päckchen 
ordnungsgemäß empfangen und geprüft hat (Längenangabe aus Header und 
Checksumme okay), gibt er dem Controller ein ACK, und der µC sendet das 
nächste Paket, andernfalls gibts ein NACK, und der µC sendet das gleiche 
Paket nochmal. Da brauchst du dann kein Timeout etc.

Eine andere Möglichkeit wäre, den Rx-Buffer einfach höher zu setzen. Du 
gehst davon aus, dass die Abläufe unter Vista die gleichen sind wie bei 
XP. Ist definitiv nicht so. Erstens hast du eine andere "Schnittstelle" 
vom PC-Prozessor bis zu deinen RS232-Pins (einmal fest aufm Board und 
einmal über Karte) und somit ein anderes Verhalten (Timing, Ansteuerung, 
etc.). Zweitens wird denke ich der Ablauf mit .NET unter Vista anders 
sein als bei XP.
Die Ruckler können z.B. auch auftreten, wenn du erstens die 
Datenverarbeitung nicht sauber von der Ausgabe getrennt hast, also die 
Ausgabe besser in einem eigenen Thread laufen lassen (z.B. mit der 
BackGroundWorker-Klasse in .NET). Zweitens wird Vista halt viel mehr 
Krimskrams im Hintergrund laufen haben als XP, da könnt ich mir 
vorstellen, das wegen Klickibunti die wichtigen Sachen wie 
Schnittstellen weniger Priorität bekommen haben.

Und dann kommts noch drauf an, wie du den Buffer ausliest (Ereignis oder 
Polling) und wie du bei Ereignissteuerung triggerst (jedes Byte oder 
nach einer bestimmten Anzahl Bytes das Ereignis auslösen).

Ralf

von Markus (Gast)


Lesenswert?

>Zitat von  Rufus

>Das kannst Du selbst herausfinden, indem Du mal im Gerätemanager
>nachsiehst, a) was für ein Devicetreiber verwendet wird und b) Dir mal
>die Eigenschaften des Gerätes ansiehst. Üblicherweise wird dort ein
>"Ort" genannt, und bei USB-Geräten steht dort korrekt "USB" ...

Devicetreiber :    OXCB950 Cardbus UART
Gerätetyp     :    Multifunktionsadapter
Hersteller    :    Enhanced Ports
Gerät         :    PCI Bus 13, Gerät 4


>Zitat von Ralf

>Wenn der PC das Päckchen
>ordnungsgemäß empfangen und geprüft hat (Längenangabe aus Header und
>Checksumme okay), gibt er dem Controller ein ACK, und der µC sendet das
>nächste Paket

Der Controller darf möglichst keine Unterbrechnungen bei seinem 
Programmablauf haben. Zweck der Oberfläche ist das darstellen von 
Reglergrössen. Der Controller wird später mal als Regelung für eine Art 
aktives Pendel verwendet. Mit der Oberfläche soll es möglich sein, die 
internen Abläufe Grafisch darzustellen. Und damit das µC Programm 
möglichst unterbrechnungsfrei laufen soll, hab ich die Sache mit der 
Kurzen Pause am Ende einer gesendeten Frame geschrieben. Dann kann man 
wenigstens mit festen Pausen Rechnen. Die Darstellung darf hierbei nicht 
den Controller behindern. Deshalb wäre dabei ein Pufferüberlauf evtl. 
sogar verschmerzbar , aber nicht wüschenswert.


Zum Quellcode :
1
If cp.ReadChar = 2 Then
2
            Try
3
                strString = ""
4
                Dim i As Integer = 0
5
                Do
6
                    intChar(i) = cp.ReadByte
7
                    i += 1
8
                    
9
                Loop While intChar(i - 1) <> 3
10
                Dim temp(3) As Byte
11
                newFrame.bytFC = intChar(0)
12
                temp(0) = intChar(4)
13
                temp(1) = intChar(3)
14
                temp(2) = intChar(2)
15
                temp(3) = intChar(1)
16
                newFrame.sngValue = System.BitConverter.ToSingle(temp, 0)
17
18
                strString += "FC:(" & Hex(intChar(0)) & ")" & "Value : (" & CStr(newFrame.sngValue) & ")" & vbCrLf
19
20
                ' Schreibt anhand des erhaltenen Funktionscodes an die entsprechende Eigenschaft den Übergebenen Wert
21
                setValues(intChar(0), newFrame.sngValue)
22
                
23
24
                Me.Invoke(Aktualisieren)

Ich reagiere auf jedes Empfangene Byte durch das Empfangen Ereignis der 
SerialPort Klasse. Nur Wenn das erste empfangene Zeichen (cp.ReadChar = 
2) ist, wird die Frame aufgenommen.
In Einer Schleife frage ich jedes folgende Byte ab, bis das Endzeichen 
erhalten wird (Loop While intChar(i - 1) <> 3).
So hab ich alle Bytes der Frame dann in dem Array ( intChar() ), das ich 
dann weiter verarbeite.

Das der Code nichts professionelles darstellt ist kein Geheimnis, aber 
er sollte funktionieren.Was er ja auch tut unter XP.Zumindest sollte er 
nicht das bewirken was es unter Vista bewirkt.

Ich bleib auf jedenfall dran, werde es mal an meinen alten XP Rechner 
ausprobieren. Sollte Vista das Problem sein, muss man mit den 
Konsequenzen eben klarkommen.

von Peter (Gast)


Lesenswert?

Hallo,
ich vermute mal das Problem wird sein das du beim empfangen gleich die 
Daten anzeigst. Soetwas sollte man vermeiden!. In PC mit mehr als 1GHz 
langweilt sich wenn du daten von einem µC mit ein paar Mhz kommen. 
Versuche mal das lesen ser Seriellen schnittstelle und das Anzeigen zu 
trennen.
Sobalt man etwas aus einem Programm anzeigt ist man von Windows 
abhängig, das vernichtet jedes Timing.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Markus wrote:
>>Zitat von  Rufus
>
>>Das kannst Du selbst herausfinden, indem Du mal im Gerätemanager
>>nachsiehst, a) was für ein Devicetreiber verwendet wird und b) Dir mal
>>die Eigenschaften des Gerätes ansiehst. Üblicherweise wird dort ein
>>"Ort" genannt, und bei USB-Geräten steht dort korrekt "USB" ...
>
> Devicetreiber :    OXCB950 Cardbus UART
> Gerätetyp     :    Multifunktionsadapter
> Hersteller    :    Enhanced Ports
> Gerät         :    PCI Bus 13, Gerät 4

OK, dann hast Du eine ausreichend hochwertige Karte gekauft. Dennoch 
gibt es einen Hardwareunterschied zwischen den Onboard-UARTs und der in 
dieser Karte verbauten - nämlich die Fifo-Größe. Die beträgt bei den 
Onboard-UARTs im PC 16 Byte (das ist der Standard-16550 von NSC), aber 
bei den UARTs von Oxford Semiconductor ganz erheblich mehr.

Der Empfangs-Fifo der UART wirkt sich auf zwei Arten auf den Empfang von 
Daten aus. Der Empfangs-Interrupt wird ausgelöst, wenn der Fifo voll 
ist, aber auch, wenn der Fifo nicht voll ist, und eine gewisse Wartezeit 
vergangen ist. Diese kann für das von Dir geschilderte Phänomen 
zuständig sein.

Abhilfe: Im Gerätemanager die Interruptschwelle für den Empfangs-Fifo 
der Oxford-UART auf den gleichen Wert stellen, wie auf dem PC mit 
Standard-UARTs, das dürfte 14 sein.

von Markus (Gast)


Lesenswert?

Ok, eben klappts. Ich schreibs mal ausführlich für alle die den Post 
evtl. verfolgen :


Im "Gerätemanager/Anschlüsse(COM1)" unter dem Reiter FIFO´s gibts zwei 
Gruppen, nämlich

       FIFO Interrupt Trigger Levels und
       Receive FIFO Flow Control Thresholds

Wenn ich bei Interrupt Trigger Level den Schwellwert für Receiver auf 1 
setzte, läuft mein Programm so wie es soll. Vorher war hier der Wert 100 
eingetragen.

Ich interpretiere das jetz mal einfach so, das das Abarbeiten der 
Empfangenen Zeichen vom Controller erst ausgelöst wurde, wenn er 100 
Bytes Empfangen hatte.Ich war aber auch der Meinung, das ich das selbst 
in meinem Code festlegen kann ab wieviel Byte das Empfangs Ereignis 
ausgelöst wird. Aber vermutlich vergleiche ich hier Äpfel mit Birnen, 
kann das sein ?

von Markus (Gast)


Lesenswert?

>Zitat von Peter
>
>Versuche mal das lesen ser Seriellen schnittstelle und das Anzeigen zu
>trennen.


Ich dachte hierfür sei der invoke Befehl (Me.Invoke(Aktualisieren)
). Dieser Startet nämlich das aktualisieren der Werte in der Form über 
einen eigenen Thread. VB.net lässt es auch garnicht zu, das ich die 
Daten direkt in die Form schreibe, sondern ich muss in diesem Fall den 
umweg über die Eigenschaften meiner Oszilloskopklasse gehen. Die Methode 
"Aktualisieren" die mit invoke ausgelöst wird, kümmert sich dann darum , 
das die vorhanden Daten (stecken jetzt ja in den Eigenschaften der 
Osziklasse ) in der Form gezeichnet werden.
Oder lieg ich hier evtl. auch falsch ?


Auf jedenfall funktioniert jetzt alles, vielen Dank nochmals ;)

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

> Wenn ich bei Interrupt Trigger Level den Schwellwert für Receiver auf 1
> setzte, läuft mein Programm so wie es soll.

Naja, das löst für jedes einzelne Zeichen einen Interrupt aus. Das 
entspricht dem Verhalten der Fifolosen uralt-UART 8250, wie man sie 
früher in PCs verwendet hatte. Bei hohen Datenraten ist das recht 
ineffizient, womit ich wörtlich Datenraten im Sinne von übertragene 
Bytes pro Sekunde meine, nicht die Baudrate an sich; man kann auch mit 
19200 Baud nur vier Zeichen pro Sekunde übertragen.

> Vorher war hier der Wert 100 eingetragen.

Naja, wie ich bereits riet, solltest Du mal nachsehen, mit welchem Wert 
der XP-Rechner arbeitet, dessen Onboard-Schnittstelle Du verwendest -ich 
tippe auf 14.

> Ich interpretiere das jetz mal einfach so, das das Abarbeiten der
> Empfangenen Zeichen vom Controller erst ausgelöst wurde, wenn er 100
> Bytes Empfangen hatte.

Wenn Du mit "Controller" den UART-Baustein in Deiner Karte meinst, ist 
das korrekt.

> Ich war aber auch der Meinung, das ich das selbst
> in meinem Code festlegen kann ab wieviel Byte das Empfangs Ereignis
> ausgelöst wird.

Nein, dazwischen sitzt noch ein Puffer, der von Windows verwaltet wird. 
Zugriff auf treiberspezifische Konfigurationsoptionen bietet die recht 
allgemein gehaltene API für serielle Schnittstellen nicht, das aber ist 
kein Fehler von Windows, sondern bei Betriebssystemen allgemein üblich.

> Aber vermutlich vergleiche ich hier Äpfel mit Birnen,
> kann das sein ?

Ach, das wird so oft gemacht ...

von Markus (Gast)


Lesenswert?

Ich habe den Wert von WindowsXP übernommen, der stand in der tat auf 14, 
aber leider hatte ich dabei immernoch einen Überlauf. Zwar wesentlich 
langsamer, aber er war eben noch da.

Denke aber das die Einstellungen in Ordnung , solange ich nicht wieder 
Schwierigkeiten bekomme. Ich bin ja schon voll zufrieden das es erstmal 
so funktioniert. Bin in Sachen Programmieren kein profi und was die 
Hardware angeht auch nicht :)

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.