mikrocontroller.net

Forum: PC-Programmierung Timingverhalten in Windows-Treiber


Autor: Hardi S. (hardi13)
Datum:

Bewertung
0 lesenswert
nicht 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:
  unsigned int i, j;                         // counters
  unsigned int tickendwait, tickdiff;        // all in ticks256th
  unsigned int tickstep=22;                  // this is 2,5 micro secs
  unsigned int maxnumber=800000;             // 800000*2,5 => 2sec

  tickendwait=tick256th()+tickstep;          // when reached tickendwait, a new action is required
  asm ("cli");                               // disable interrupts, no system reaction for a specific time
  for(j=0; j<maxnumber; j++) {               // main loop to collect data
    for (i=0;;i++) {                         // wait for next action
      tickdiff=tick256th()-tickendwait;      // if tickdiff is negative: continue waiting
                                             // if tickdiff is zero: reached end time exactly now 
      if (tickdiff<0x80000000) {             // if tickdiff is positive: end time is in the past, break, action now
        tickendwait+=tickstep;               // calculate next tickendwait
        break;
      }
    }
    /* ACTION */
//    pio_field->i_port[j]=(InPort(0x379)&0xF8)^0x80;  // read port and fill in (bit7-3 without inversion)
    pio_field->i_port[j]=i;
    pio_field->tickoffset[j]=tickdiff+tickstep;        // fill in tickoffset in tick/256
  }
  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

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Hardi S. (hardi13)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Tim (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Hardi S. (hardi13)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Tim (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich Tippe auf den SMI. Der läst sich auch nicht blockieren:
http://cvs.gna.org/cvsweb/magma/base/arch/i386/cal...

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

Autor: Hardi S. (hardi13)
Datum:

Bewertung
0 lesenswert
nicht 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?

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.