Wir haben einen ARM9, der den Kernel 3.2 verwendet - alles scheint gut zu funktionieren. Kürzlich wurde ich gebeten, Code hinzuzufügen, um bei einigen GPIO-Leitungen beim Start einen 50-ms-Impuls hinzuzufügen. Der Pulscode ist in Ordnung; Ich kann sehen, dass die Linien wie erwartet nach unten und oben gehen. Was nicht wie erwartet funktioniert, ist die Funktion udelay()
. Das Lesen der Dokumente lässt mich glauben, dass die Einheiten in Mikrosekunden sind, aber wie im Logikanalysator gemessen, war es viel zu kurz. Also habe ich diesen Code hinzugefügt, um 50ms zu bekommen.
Ich mag es nicht, aber es funktioniert gut. Es gibt einige ungerade Konstanten und Anweisungen im Code udelay
. Kann mir jemand aufklären, wie das funktionieren soll? Dieser Code wird aufgerufen, nachdem alle Uhren initialisiert wurden, also scheint alles andere in Ordnung zu sein.
Laut Linus in diesem Thread :
Wenn es etwa 1% weniger ist, ist alles in Ordnung. Wenn jemand einen Verzögerungswert gewählt hat das ist so empfindlich auf kleine Fehler in der Verzögerung, die sie bemerken das - oder sogar etwas wie 5% bemerken - dann haben sie auch gepflückt kurz vor einer Verzögerung.
udelay () war nie wirklich eine Art von Präzision Instrument. Vor allem, wenn CPUs mit unterschiedlichen Frequenzen laufen, Wir hatten in der Vergangenheit einige ziemlich wilde Schwankungen. Das traditionelle Die busy loop wird nicht nur von Interrupts, sondern auch von Dinge wie Cache-Ausrichtung (wir haben es inline) und dann später die TSC basierte natürlich davon, dass TSC stabil war (was sie waren für eine Weile nicht).
In der Vergangenheit haben wir udelay () also wirklich ausgemacht (dh 50% Rabatt) usw.), ich würde mich nicht um Dinge in der 1% -Bereich kümmern.
Linus
Es wird also nicht perfekt sein. Es wird weg sein. Um wieviel hängt von vielen Faktoren ab. Verwenden Sie statt einer for
-Schleife stattdessen mdelay
. Es könnte ein bisschen genauer sein. Aus dem O'Reilly Linux Device Drivers Buch:
Der udelay Aufruf sollte nur für kurze Zeitspannen aufgerufen werden, weil Die Genauigkeit von
loops_per_second
ist nur acht Bits und bemerkbar Fehler häufen sich bei der Berechnung langer Verzögerungen. Obwohl die Die maximal zulässige Verzögerung beträgt fast eine Sekunde (seit Berechnungen Überlauf für längere Verzögerungen), der vorgeschlagene Maximalwert für udelay ist 1000 Mikrosekunden (eine Millisekunde). Die Funktion mdelay hilft dabei Fälle, in denen die Verzögerung länger als eine Millisekunde sein muss.Es ist auch wichtig daran zu denken, dass udelay eine "busy-wait" -Funktion ist (und so auch mdelay ); Andere Aufgaben können während der Zeit nicht ausgeführt werden Ablauf. Sie müssen daher sehr vorsichtig sein, insbesondere mit mdelay und vermeide es, es zu benutzen, es sei denn, es gibt keinen anderen Weg, dein Ziel zu erreichen.
Gegenwärtig werden Verzögerungen von mehr als einigen Mikrosekunden unterstützt kürzer als ein Timer Tick ist sehr ineffizient. Dies ist normalerweise nicht ein Problem, weil Verzögerungen nur lang genug sein müssen, um von bemerkt zu werden Menschen oder durch die Hardware. Eine Hundertstel Sekunde ist geeignet Präzision für mensch-bezogene Zeitintervalle, während eine Millisekunde eine ist lange genug Verzögerung für Hardware-Aktivitäten.
Speziell die Zeile " der vorgeschlagene Maximalwert für udelay ist 1000 Mikrosekunden (eine Millisekunde) " bei mir, da Sie angeben, dass 2000 der max. Von dieses Dokument zum Einfügen von Verzögerungen:
mdelay ist Makro Wrapper um udelay, um für möglich zu berücksichtigen Überlauf beim Übergeben großer Argumente an udelay
Es ist also möglich, dass Sie in einen Überlauffehler geraten. Obwohl ich 2000 normalerweise nicht für ein "großes Argument" halte.
Aber wenn Sie echte Genauigkeit in Ihrem Timing benötigen, müssen Sie sich mit dem Offset wie Sie beschäftigen, rollen Sie Ihre eigenen oder verwenden Sie einen anderen Kernel. Informationen dazu, wie Sie Ihre eigene Verzögerungsfunktion mit Assembler oder mit harten Echtzeitkerneln steuern können, finden Sie in diesem Artikel auf Hoch -Lösung Timing .
Siehe auch: Linux-Kernel: udelay () kehrt zu früh zurück?
Tags und Links linux embedded linux-kernel