Discussion:
Problem mit 8253/8254 und PC-Timer
(zu alt für eine Antwort)
Freiberg Martin
2007-04-21 19:52:43 UTC
Permalink
Hi,

Sorry für das Crossposting, aber ich hoffe das ich so diejenigen finde
dir mir die Ursache für mein Problem erklären können.
F-Up ist hoffendlich passend gesetzt, sonst bitte anpassen.

Ich habe ein Problem mit dem realisieren einer Drehzahlmessung über
einen PC und hoffe nun hier die Lösung zu finden.

Ich möchte nur eine Drehzahlmessung realisieren die von 1 bis 2500 oder
wenigstens von 60 bis 2200 U/Min geht. Eigendlich ein einfaches Vorhaben
könnte man meinen, doch der Teufel steckt im Detail. Über einen Sensor
bekomme ich pro Umdrehung einen Impuls. Die Messung erledige ich über
den Timerbaustein im PC.
Da der Timerbaustein im PC fest mit 1193182 Hz getaktet wird, reicht der
Zählbereich nicht aus und muss ihn über den Timerinterrupt erweitern.

Wenn der Messimpuls kommt läuft folgendes ab:
1.Wert im Timerbaustein festhalten (OUT 0x043,04)
2.Wert aus Timerbaustein auslesen (2x IN 0x040)
3.Softwaretimer auslesen (Word aus Adresse 0x0040:0x006C)
3.Die zuvor gespeicherten Werte hohlen
4.Die aktuellen Timerwerte zwischenspeichern
5.Die Differenz aus alten und aktuellen Werten berechnen
6.Aus der Differenz die Drehzahl errechnen (Drehzahl=71590920/Diff).

Dummerweise habe ich aber bei den Werten große Sprünge drin. Um dem
Problem auf die Spur zu kommen habe ich nun 100 Werte jeweils vom
Timerbaustein (Spalte B) und vom Softwaretimer (Spalte A) bei der
Messung abgespeichert.

Hier ein Auszug davon:

A B C D E F G H
Timer Differenz Gesamtwert Diverenz Drehzahl
Soft Hard Div A Div B A*65536+B Div E U/Min

27346 41897 1792189353
27347 49405 1 7508 1792262397 73044 980 516
27349 56965 2 7560 1792401029 138632 516 979
27350 64531 1 7566 1792474131 73102 979 516
27352 6619 2 -57912 1792547291 73160 978 516
27354 14255 2 7636 1792685999 138708 516 978
27355 21893 1 7638 1792759173 73174 978 516
27357 29513 2 7620 1792897865 138692 516 978
27358 37155 1 7642 1792971043 73178 978 516
27360 44807 2 7652 1793109767 138724
27361 52461 1 7654 1793182957 73190
27363 60127 2 7666 1793321695 138738
27365 2257 2 -57870 1793394897 73202
27366 9885 1 7628 1793468061 73164
27368 17513 2 7628 1793606761 138700
27369 25099 1 7586 1793679883 73122
27371 32663 2 7564 1793818519 138636


Das Verrückte dabei ist nun, warum zählt der Softwaretimer
des PC konstant im Wechsel mal um 1 und mal um 2 weiter wie
es Spalte C aufzeigt? So fehlt mir jeweils ein Interrupt aus
dem Timerbaustein. Wenn ich jeweils zum Gesamtwert passend
65536 dazuzähle bzw. abziehe, dann habe ich schöne konstante
Werte.
Die Uhr des PC, die ebenfalls aus dem Softwaretimer errechnet
wird geht hingegen auch nach Stunden korrekt. Wenn ich im
Interruptkontroller die anstehenden Interrupts überprüfe, so
kann ich keinen ausstehenden zum Auslesezeitpunkt feststellen.

Die Interrupts müssen demnach korrekt erfolgen, und trotzdem
bekomme ich Werte aus Soft- und Hardwaretimer die nicht
zueinander passen.

Warum? Was passiert da?

Auch schlugen alle Versuche fehl aus den Werten und auch wenn
sie zweimal gelesen werden, irgend wie an zueinander passenden
Werten zu kommen.

Gruß
Martin
Norbert Juffa
2007-06-09 09:41:24 UTC
Permalink
Post by Freiberg Martin
Hi,
Sorry für das Crossposting, aber ich hoffe das ich so diejenigen finde
dir mir die Ursache für mein Problem erklären können.
F-Up ist hoffendlich passend gesetzt, sonst bitte anpassen.
Ich habe ein Problem mit dem realisieren einer Drehzahlmessung über
einen PC und hoffe nun hier die Lösung zu finden.
Ich möchte nur eine Drehzahlmessung realisieren die von 1 bis 2500 oder wenigstens von 60 bis 2200 U/Min geht. Eigendlich ein
einfaches Vorhaben
könnte man meinen, doch der Teufel steckt im Detail. Über einen Sensor
bekomme ich pro Umdrehung einen Impuls. Die Messung erledige ich über
den Timerbaustein im PC.
Da der Timerbaustein im PC fest mit 1193182 Hz getaktet wird, reicht der
Zählbereich nicht aus und muss ihn über den Timerinterrupt erweitern.
1.Wert im Timerbaustein festhalten (OUT 0x043,04)
2.Wert aus Timerbaustein auslesen (2x IN 0x040)
3.Softwaretimer auslesen (Word aus Adresse 0x0040:0x006C)
3.Die zuvor gespeicherten Werte hohlen
4.Die aktuellen Timerwerte zwischenspeichern
5.Die Differenz aus alten und aktuellen Werten berechnen
6.Aus der Differenz die Drehzahl errechnen (Drehzahl=71590920/Diff).
Dummerweise habe ich aber bei den Werten große Sprünge drin. Um dem Problem auf die Spur zu kommen habe ich nun 100 Werte jeweils
vom
Timerbaustein (Spalte B) und vom Softwaretimer (Spalte A) bei der
Messung abgespeichert.
Zwei moegliche Probleme:

(1) Der Timer laeuft im "falschen Modus". Um SW- und HW-Timer zu
kombinieren muss der Timer als "rate generator" (zahelt in
Einerschritten herrunter) programmiert werden, nicht als
"square wave" (zaehlt in Zweierschritten herunter). Einige BIOSe
nutzen jedoch letztere Einstellung. Den "rate generator" Modus
setzt man so:

OUT 0x43, 0x34
OUT 0x40, 0x00
OUT 0x40, 0x00

(2) Das Auslesen und Kombinieren von SW und HW-Timer ist nicht richtig
verschachtelt. Auch zu beachten: Der HW-Timer zaehlt runter, der
SW-Tickzaehler zaehlt hoch. Hier ist ein alter, robuster 16-bit Code
fuer diese Aufgabe:

PUSH DS ; save caller's data segment
MOV DS, Seg40h ; access ticker counter
MOV BX, 6Ch ; offset of ticker counter in segm.
MOV DX, 43h ; timer chip control port
MOV AL, 4 ; freeze timer 0
PUSHF ; save caller's int flag setting
CLI ; make reading counter an atomic operation
MOV DI, DS:[BX] ; read BIOS ticker counter
MOV CX, DS:[BX+2]
STI ; enable update of ticker counter
OUT DX, AL ; latch timer 0
CLI ; make reading counter an atomic operation
MOV SI, DS:[BX] ; read BIOS ticker counter
MOV BX, DS:[BX+2]
IN AL, 40h ; read latched timer 0 lo-byte
MOV AH, AL ; save lo-byte
IN AL, 40h ; read latched timer 0 hi-byte
POPF ; restore caller's int flag
XCHG AL, AH ; correct order of hi and lo
CMP DI, SI ; ticker counter updated ?
JE @no_update ; no
OR AX, AX ; update before timer freeze ?
JNS @no_update ; no
MOV DI, SI ; use second
MOV CX, BX ; ticker counter
@no_update:
NOT AX ; counter counts down

; hier: Zaehler in DI:CX:AX

POP DS ; restore caller's data segment

Loading...