Hallo Andreas,
ich fasse mal zusammen.
Deine Lösung beinhaltet zwei grundlegende Ideen.
1. Per "nop"-Zählung (ich behalte mal den Terminus Deiner Zählschleife so bei) stellst Du Deine Zeitrechnung auf dem CPU-Takt ab - also unabhängig von irgendwechen anderen Systemtimern, welche ggf. schon "nur" mit 1MHz (->1µs) laufen. D.h. Deine Auflösung wird bestimmt vom CPU-Takt und der Anzahl der Takte, die zur Ausführung der Schleife benötigt werden. Damit bist Du auch unabhängig vom Laufzeitverhalten eines clock_gettime oder anderer Kernelobjekte. Die Messung selbst hat den Vorteil, vollständig im Userspace laufen zu können.
2. Du kalibrierst Dein Zeitmodell über das "Zeitempfinden" Deiner Peripherie. D.h. laufen die Uhren in Raspi und Peripherie unterschiedlich schnell, dann paßt sich Dein Raspi-Zeitmodell (mittels Messung zweier bekannter Pulsweiten der Peripherie) an das Deiner zu steuernden HW an. Das hat Vorteile (Kompensation konstanter Gangabweichungen), kann aber auch Nachteile (bei veränderlichen Gangabweichungen) mit sich bringen.
Folgende Problemstellungen sehe ich jedoch unbehandelt.
1. Das Problem langer Einzelimpulse
2. Das Problem einer kontinuierlichen Übertragung von Impulsen
Beides geht zurück auf das Kernproblem, daß Deine Schleife...
procedure wait_falling(pin, korr, timeout)
loop := 0
start := &time
while GPIO(pin) = 1 do
{ loop +:= 1
if \timeout then if &time – start > timeout then break
}
if /korr then return loop else return loop * korr
end
letztendlich nicht ununterbrechbar ist, da sie vom Scheduler preempted werden kann. Da kannst Du im Prinzip auch nichts dagegen tun, außer auf Applikationsebene das Problem zu erkennen und zu behandeln. Für den Fall 1.) kann man allerdings etwas Zusatzcode in die Schleife einbauen, der durchaus hilfreich sein kann. Willst Du sehr lange Zeiten (also Zeiten größer den Latenzzeiten des Kernels) überbrücken, so könntest Du dich für den Restbetrag (jitternd) schlafen legen (z.B. nanosleep) und die Restzeit per nop-Schleife "verheizen". Das Problem ist hierbei lediglich, daß Du in jedem Fall die Zeit Deines Schlafes messen müßstest und damit aus Deinem (genaueren) Zeitmodell herausfallen würdest. Im Falle des Raspi würde sich dazu ggf. der mit 1MHz laufende System Takt anbieten, womit man zumindest im µs Bereich operiert. Nachdem Du dadurch allerdings Zeitauflösung verlierst, kann man in diesem Fall auch gleich von Anfang an auf dem System Timer aufbauen.
Vermutlich würde eine generische Methode der Zeitmessung auf mehreren Konzepten abstellen, je nachdem, wie lang die zu messenden Zeiten ausfallen und wie genau man sie benötigt.
So, und nachdem Du meine graue "CPU" wieder mal gequält hast (und das am Wochenende!!!), geb' ich Dir jetzt auch mal was zum tüfteln, so Du magst.
Gesucht ist ein Algorithmus, der in O(1) einen Wert, welcher die Registergröße der CPU überschreitet, um n Stellen shiftet.
Beispiel: Ein 32 Bitwert z.B. dx:ax (bleiben wir mal bei Intel) soll um n Bits nach links geschoben werden. O(1) - also ohne Schleife mit Carrybit! Und komm' mir jetzt nicht mit eax
Hinweis: Du mußt in Assembler denken. Hochsprachen fehlen die hierzu notwendigen Operatoren.
Schöne Grüße
schnasseldag