Digi-Dot-Booster am esp8266 esp-12e

esp-12eVor Kurzem habe ich einige esp8266 Module bestellt, um damit bei einer Uhr die Zeit über einen NTP Server zu synchronisieren. Wegen der vielen IO Pins, kompakter Bauform und günstigen Preises habe ich mich für die esp-12e Version entschieden (Inzwischen sollte man zu esp-12f greifen, bei dem die Antenne verbessert wurde). Da ich bis jetzt keine Erfahrung mit diesen Modulen hatte, wollte ich zur Einarbeitung erst mal ein kleines Projekt damit umsetzen. Die Wahl fiel dann aus mehreren Gründen auf den Digi-Dot-Booster.

Zum Einen ist die Ansteuerung sehr einfach über SPI, zum Anderen liefert der Digi-Dot-Booster 3,3V für das esp8266 Modul gleich mit. Zwar kann die Leitung max. ca. 130 mA für die Schaltung liefern, das scheint aber für das WLAN Modul noch ausreichend zu sein.

Das esp8266 Module war mit der AT-Firmware programmiert – eine die mit AT-Kommandos über die serielle Schnittstelle angesteuert wird. Diese ist in ihrem Funktionsumfang sehr eingeschränkt, vor allem dann wenn mehr Logik auf dem Modul selbst ausgelagert werden soll. Als Alternativen sind Arduino und NodeMCU zu erwähnen. Erste erlaubt die Entwicklung gewohnt aus der Arduino IDE heraus, die zweite bringt Support für LUA auf das Modul. Ich habe mich für NodeMCU entschieden, hauptsächlich weil bei der Entwicklung nicht die ganze Firmware gebaut und geflasht werden muss, sondern nur der eigene LUA Script übertragen und ausgeführt wird. Wenn alles stimmt, kann man diesen Script dann endgültig im Flash ablegen. NodeMCU ist „Interaktiv“ und erlaubt schnelles Testen durch die Eingabe der Befehle direkt über die serielle Konsole.

Die Installation von NodeMCU sowie die Kommunikation mit dem Modul erfolgt über die serielle Schnittstelle mit TTL Pegeln (3,3V). Ich habe ein FT232RL basiertes Modul verwendet – unbedingt dabei beachten, dass es auch auf 3,3V Pegel eingestellt wird. Die ersten Tests wollte ich nur mit diesem Board machen und habe die 3,3V vom 3V3OUT Pin abgegriffen, dieser liefert jedoch max. nur 50mA, was zu ständigen Reboots vom esp8266 Modul geführt hat. Zum Betrieb vom esp-12e Modul werden noch die Pins GPIO15 an GND und EN an VCC angelegt. Zum Programmieren des Moduls mit der NodeMCU Firmware wird der Pin GPIO0 an GND gelegt, der Rest wird mit den Tools wie in der Anleitung erledigt.

Beim Anschluss des DD-Booster bin ich auf die nahe liegende Idee gekommen, die beschrifteten Pins des SPI Ports auf der Unterseite zu nehmen. Als es nicht funktioniert hat und ich mich auf die Suche nach dem Grund machte, hat sich herausgestellt, dass an dem Port intern der Flash-Speicher des Moduls hängt. Diese Pins können von extern dafür verwendet werden, direkten mit dem Speicher Chip zu arbeiten. Der zweite SPI Port ist an den Pins GPIO12 – MISO, GPIO13 – MOSI, GPIO14 – CLK, GPIO15 – CS, wobei GPIO15 beim Start des Moduls zur Bestimmung des Boot Modus verwendet wird und normalerweise auf GND liegt. Als Chip Select sollte daher ein anderer freier Pin verwendet werden, bei mir ist es GPIO16 geworden. Nachdem alles neu verdrahtet wurde, hat dann auch alles ohne große Probleme funktioniert.

esp8266-ddbooster

Zum Entwickeln verwende ich ESPlorer. Es ist recht komfortabel und läuft auch auf dem Mac. Alternativen dazu gib es ebenfalls auf der Projektseite von NodeMCU.

Der Regenbogen aus dem LUA Beitrag kann teilweise wieder verwendet werden. Die API zur Ansteuerung von SPI ist etwas anders und der Chip Select Pin muss ebenfalls manuell getriggert werden.

DELAY = 40
LED_COUNT = 24
cs = 0
spiport = 1

function initSPI()
    gpio.mode(cs, gpio.OUTPUT)
    gpio.write(cs, gpio.HIGH)
    spi.setup(spiport, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, spi.DATABITS_8, 60, spi.HALFDUPLEX)
end

function initLEDs()
    gpio.write(cs, gpio.LOW)
    spi.send(spiport, 0xB1, LED_COUNT, 24)
    gpio.write(cs, gpio.HIGH)
    tmr.delay(DELAY * 1000)
end

function clear()
    gpio.write(cs, gpio.LOW)
    spi.send(spiport, 0xA1, 0, 0, 0, 0xA5, 0xB2)
    gpio.write(cs, gpio.HIGH)
end

initSPI()
initLEDs()

i = 0
runs = 100
tmr.alarm(0, DELAY, tmr.ALARM_AUTO, function()
    if runs == 0 then
        tmr.unregister(0)
        clear()
    else
        i = i + 5
        i = i % 360
        gpio.write(cs, gpio.LOW)
        spi.send(spiport, 0xA7, i % 0x100, math.floor(i / 0x100), 255, 50, 0, LED_COUNT - 1, 10, 0xB2)
        gpio.write(cs, gpio.HIGH)
        runs = runs - 1
    end
end)

Im Beispiel sieht man, wie die für den DD-Booster nötigen Pausen zwischen den SPI Transfers umgesetzt wurden. Der Aufruf von `tmr.delay(DELAY * 1000)` bewirkt eine 40ms lange blockierende Pause. Das ist an der Stelle nicht kritisch, da sie ein Mal beim Initialisieren der LEDs verwendet wird. Jedoch eine Schleife mit diesem Aufruf, wie im LUA Beispiel für den Raspberry Pi,  würde die gesamte CPU Zeit für sich beanspruchen, ohne dass anderer Code (Netzwerk IO z.B.) je ausgeführt werden kann (das führt auch zu Timeouts in ESPlorer, der während der Ausführung der Schleife keine Antwort vom Modul bekommt). Daher wurde die Schleife durch einen Timer Aufruf ersetzt, der die Callback Funktion mit der Ansteuerung des DD-Boosters alle 40ms aufruft. In den 40ms Pause könnte die CPU andere aufgaben erledigen. Das bedeutet aber auch, dass es nicht garantiert werden kann, dass der DD-Booster exakt in vorgegebenen Intervallen gesteuert wird. Wird in der Pause anderer Code länger brauchen, wird sich auch das nächste Kommando an den DD-Booster verzögern. NodeMCU ist eben kein Echtzeitbetriebssystem… Wer sich wundert, warum GPIO16 im Code mit pin 0 adressiert wird, sollte sich das Mapping der Pins in NodeMCU anschauen.

Das es8266 ist eigentlich für die Kommunikation im WLAN bestimmt, daher wäre der nächste logische Schritt, einen Steuerung des DD-Boosters über WLAN zu realisieren. Mit Hilfe einer simple HTML Seite und einem HTTP Server auf dem esp8266 zum Beispiel. Mit NodeMCU ist es auch recht einfach umsetzbar. Evtl. mach ich das etwas später – momentan konzentriere ich mich auf die Anbindung des Moduls zwecks Zeitsynchronisation…

Schreibe einen Kommentar