Forum: PC-Programmierung Timingverhalten in Windows-Treiber


von Hardi S. (hardi13)


Lesenswert?

Hallo,

Ich habe ein Problem das Timingverhalten in einem selbstgeschriebenen 
Windows-Treiber zu verstehen.
Vielleicht kann mir jemand helfen ... oder sagen wonach ich suchen muss.

Unter MinGW habe ich auf einem XP-Rechner einen kleinen Treiber 
programmiert.
Später soll über eine Dauer von 2 sec alle 2,5 microsec der Parallelport 
ausgelesen werden (tickstep=22 entspricht 2,5 microsecs).
Da Windows so große Zeitscheiben nicht sicher zur Verfügung stellen 
kann, sperre ich alle Interrupts und akzeptiere für die Messzeit einen 
"eingefrorenen" Windows-Rechner.

Die Funktion tick256th() gibt das Ergebnis vom Assemblerbefehl "rdtsc" 
zurück. Allerdings werden von den ursprünglich 64 Bit nur Bit 39-8 
zurückgegeben, da es vollkommen ausreicht und ich auf long 
long-Berechnungen verzichten kann. Damit ist der zurückgegebene 
Prozessortakt durch 256 geteilt.
Die vorerst auskommentierte Funktion InPort() führt den Assemblerbefehl 
"inb" aus.

Hier eine kurze Sequenz aus dem Treiber:
1
  unsigned int i, j;                         // counters
2
  unsigned int tickendwait, tickdiff;        // all in ticks256th
3
  unsigned int tickstep=22;                  // this is 2,5 micro secs
4
  unsigned int maxnumber=800000;             // 800000*2,5 => 2sec
5
6
  tickendwait=tick256th()+tickstep;          // when reached tickendwait, a new action is required
7
  asm ("cli");                               // disable interrupts, no system reaction for a specific time
8
  for(j=0; j<maxnumber; j++) {               // main loop to collect data
9
    for (i=0;;i++) {                         // wait for next action
10
      tickdiff=tick256th()-tickendwait;      // if tickdiff is negative: continue waiting
11
                                             // if tickdiff is zero: reached end time exactly now 
12
      if (tickdiff<0x80000000) {             // if tickdiff is positive: end time is in the past, break, action now
13
        tickendwait+=tickstep;               // calculate next tickendwait
14
        break;
15
      }
16
    }
17
    /* ACTION */
18
//    pio_field->i_port[j]=(InPort(0x379)&0xF8)^0x80;  // read port and fill in (bit7-3 without inversion)
19
    pio_field->i_port[j]=i;
20
    pio_field->tickoffset[j]=tickdiff+tickstep;        // fill in tickoffset in tick/256
21
  }
22
  asm("sti");                                // enable interrupts

Grundsätzlich funktioniert das Programm, doch folgende Dinge fallen mir 
auf:
1.) Mit i kann man zählen, wie oft die Warteschleife durchlaufen wurde, 
bis die nächsten 2,5µm verstrichen sind. Es werden bei meinem Prozessor 
(2,3MHz) ca. 309-310 Durchläufe verbraucht (96%). Doch in 4% der Fälle 
zeigt der Schleifenzähler kleinere Werte (235-308)! WARUM? Wenn 
Interrupts gesperrt sind, wer kann denn noch Prozessorticks verbrauchen? 
Dieses Verhalten ist reprodizierbar.
2.) Wenn die Zeile zum Einlesen des Ports (mit InPort()) wieder 
einkommentiert wird, ist der Effekt noch viel größer. Erwartet hätte ich 
eine (konstante) Verringerung der Durchläufe, aber stattdessen kann in 
26 Fällen von 800000 nicht einmal das Timing von 2,5µm eingehalten 
werden! Der Durchlaufzähler bleibt bei 0(!!!) und tickdiff hat einen 
Wert von bis zu 15, was einer Verspätung  von 1,7µm entspricht!!!

Wer oder was klaut Prozessorticks? Kann/muss noch etwas abgeschaltet 
werden?

Vielen Dank schon im voraus für eine hilfreiche Antwort

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

I/O-Zugriffe auf den Parallelport sind sehr langsam, da hier noch 
Fragmente des alten ISA-Busses in der PC-Architektur fortleben.
Um das auszuprobieren, schreib' mal eine Variante, die nur einen Pin 
hin- und herschaltet und häng ein Oszilloskop daran. Mehr als ein paar 
MHz wirst Du nicht messen können, auch wenn Dein Rechner mit noch so 
vielen GHz Takt betrieben wird.

Nicht nur aus diesem Grund halte ich Dein Unterfangen für einen 
Designfehler.

von Hardi S. (hardi13)


Lesenswert?

Nachmessen ist natürlich das Einzig richtige, doch leider habe ich kein 
Oszilloskop zur Hand. Ich weiß aber, dass beispielsweise alte 
Flasherprogramme für Handys über meinen Parallelport vergleichbare 
Datenraten korrekt übertragen können. -> Tests werden es dann zeigen...

Die Hauptfrage für mich im Moment ist aber, warum das Zeitverhalten 
nicht streng wiederholbar ist, sondern sich offensichtlich trotz 
abgeschalteter Interrupts von Außen verändern lässt.
Wer stört da?

von Tim (Gast)


Lesenswert?

Vielleicht irgend eine Bios Funktion?
(Lüftersteuerung, Stromsparen, Temperatur überwachung...)
Hatte mit dem EMC auch schon solche Probleme.
Nur ein Mainboard wechsel hat geholfen.

von Hardi S. (hardi13)


Lesenswert?

Danke für den Hinweis.
Ein zweiter XP Rechner mit 2,9MHz zeigt ein vergleichbares Verhalten. 
Die Zeiten sind andere, aber die Effekte ähnlich.
Aber das ist natürlich kein Beweis...

Kann man etwas Konkretes noch abschalten?
Wie gesagt: Es läuft Software auf dem Rechner, der das Timing 
zuverlässig schafft.

von Tim (Gast)


Lesenswert?

Ich Tippe auf den SMI. Der läst sich auch nicht blockieren:
http://cvs.gna.org/cvsweb/magma/base/arch/i386/calibration/README.SMI?rev=1.4;content-type=text%2Fplain;cvsroot=rtai

Realtime Linux hat auch entsprechende Problem damit:
http://wiki.linuxcnc.org/cgi-bin/emcinfo.pl?Latency-Test

von Hardi S. (hardi13)


Lesenswert?

Das klingt SEHR interessant und ist neu für mich! Vielen Dank dafür. Es 
wird etwas dauern, bis ich das Thema durchgearbeitet habe...
Hat noch jemand Erfahrungen, Ergänzungen zum SMI oder kann kurz einen 
Überblick geben, um leichter in das Thema reinzukommen?

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.