Sub-Milisekunden-Timer für ESP8266 in Lua

9

Ich versuche, auf dem ESP8266 einen ferngesteuerten Servomotor-Controller zu erstellen, der von einem Server gesteuert wird. Das Problem, mit dem ich konfrontiert bin, ist, wie man einen asynchronen Timer erstellt tmr.alarm(), aber in Mikrosekunden. tmr.delay()funktioniert nicht so gut, weil es alles andere stoppt und nicht so genau ist. Sie können dies auf Arduino zum Laufen bringen, aber wie kann man dies in Lua implementieren?

Raitis Bērziņš
quelle

Antworten:

7

Ich denke, Sie könnten Schwierigkeiten haben, eine Mikrosekundenverzögerung zu erzielen, die mit dem ESP8266 sowohl genau als auch nicht blockierend ist .

Gemäß der NodeMCU-Dokumentation :

Wenn Sie sich den app/modules/tmr.cCode für diese Funktion ansehen, werden Sie feststellen, dass er eine niedrige Ebene ets_delay_us (Verzögerung) ausführt. Diese Funktion ist nicht Teil des NodeMCU-Codes oder des SDK. Es ist tatsächlich Teil des xtensa-lx106Boot-ROM und eine einfache Zeitschleife, die den internen CPU-Takt abfragt. Dies geschieht bei deaktivierten Interrupts. Wenn diese aktiviert sind, kann nicht garantiert werden, dass die Verzögerung den Anforderungen entspricht.

tmr.delay()ist wirklich für den Einsatz gedacht, wenn Sie eine genauere Zeitsteuerung für eine externe Hardware-E / A benötigen (z. B. Anheben eines GPIO-Pins für 20 μSec). Es wird in so gut wie jedem anderen Anwendungsfall keinen funktionalen Zweck erfüllen, da jede andere systemcodebasierte Aktivität für die Ausführung blockiert wird. Im schlimmsten Fall wird Ihre Anwendung beschädigt und es kommt zu schwer zu diagnostizierenden Timeout-Fehlern.

Es scheint, dass Interrupts in diesem Fall einfach deaktiviert werden müssen, weil der Interrupt-Handler viel mehr Zeit in Anspruch nehmen würde, als die gesamte Verzögerung angenommen hätte, wenn ein Interrupt mitten in der Verzögerung mit einem kurzen Intervall (in der Größenordnung von einigen Mikrosekunden) aufgetreten wäre sein.

Angenommen, Sie wollten einen Timer für 20 Mikrosekunden, und bei etwa 10 μs trat ein Interrupt auf. Wenn der Handler mehr als 10 μs benötigt, haben Sie die von Ihnen beabsichtigte Verzögerung von 20 μs bereits überschritten.

Wir können also ausschließen, tmr.delay()ob Interrupts erforderlich sind.

Ich habe ein bisschen mehr gegraben, und anscheinend unterstützt der ESP8266 Mikrosekunden-Timer, bei ets_timer_arm_new()denen der letzte Parameter Null ist. NodeMCU setzt diesen Wert jedoch auf 1, wobei die Millisekundengenauigkeit verwendet wird . Dieser Beitrag scheint diese Idee zu unterstützen:

Wenn Sie das Intervall zwischen zwei gpio-Interrupts abrufen müssen, verwenden Sie die System-API system_get_time (), um die relative Zeit zu berechnen. (Us) Wenn Sie eine os_timer-API verwenden möchten, um ein us-Timer-Ereignis zu arrangieren, verwenden Sie system_timer_reinit am Anfang von user_init und rufen Sie os_timer_arm_us auf.

Wenn Sie versuchen möchten, die Firmware zu bearbeiten und neu zu erstellen, ist dies möglicherweise einen Versuch wert. Es gab jedoch eine Funktionsanforderung dafür , die wie folgt abgelehnt wurde:

Also habe ich Nanosekunden-Timer getestet und kann keine Intervalle von weniger als 1000us festlegen (mit kompiliertem und entferntem Code und im 160-MHz-CPU-Modus habe ich so etwas wie 800us). Ist dies ein Fall, um neue (meist unbrauchbare) Funktionen bereitzustellen?
- Djphoenix

Nicht machbarer Geldautomat -> Schließen.
- marcelstoer

Aurora0001
quelle
5

Ich habe es geschafft, die NodeMCU-Firmware mit aktiviertem Timer neu zu kompilieren:

füge hier die Zeile hinzu: system_timer_reinit();

  1. ./sdk-overrides/osapi.h über der Linie hinzufügen #include_next "osapi.h": #define USE_US_TIMER

  2. ./app/modules/tmr.c-> static int tmr_start(lua_State* L){ ändern: os_timer_arm->os_timer_arm_us

  3. ./app/modules/tmr.c-> static int tmr_interval(lua_State* L){ ändern: os_timer_arm->os_timer_arm_us

  4. ./app/modules/tmr.c:verlassen os_timer_armin int luaopen_tmr( lua_State *L ){wie es ist, sonst werden Sie ein Watchdog - Reset beim Start-up erhalten

    • Kompilieren Sie die Firmware neu und flashen Sie Ihren ESP8266

Bei einer CPU mit 160 MHz habe ich es geschafft, ADC mit 8,3 kHz (Timer-Verzögerung von 125 us) abzutasten. Wenn ich schneller gehe, tritt der Wachhund ein.

Code:

    local mytimer2 = tmr.create()
    local count = 0
    local count2 = 0
    local adc_read = adc.read
    mytimer2:register(125, 1, function (t2) 
        count = count + 1; count2 = count2 + 1
        local adc_v = adc_read(0) 
        if (count2 == 500) then 
            count2 = 0
        end
        if count == 100000 then
            mytimer2:stop()
            print("Time at end: "..tmr.time())
            print("Counter: "..count)
        end
    end)
    print("Time at start: "..tmr.time())
    mytimer2:start()

Ausgabe:

Startzeit: 1

Zeit am Ende: 13

Zähler: 100000

100.000 Lesevorgänge in 12 Sekunden.

kadzsol
quelle