home
erste Version am 22.01.2017
letzte Änderung am 24.01.2017

Merkzettel zum ESP8266-12

Im folgenden sammle ich meine ersten Erfahrungen mit dem ESP8266-12.

Inhalt

Vorüberlegungen
die ersten ESP-12E-Module wurden geliefert
Pin-Mapping
Pin-Mapping - Realitätsabgleich
drei unterschiedliche Varianten
den nackigen ESP-12E auf Lochrastermaß bringen
Programmier-Board
Vortest des Programmier-Boards
Programmier-Board löten
ein paar Messungen zum Stromverbrauch
das RTC+EEPROM-Modul abfragen
DS18B20 und LDR abfragen
Tests zur Genauigkeit der Uhr im ESP-12E


Vorüberlegungen

Noch wurde keins der 12'er-Module geliefert. Meine Arduino IDE kennt den ESP8266 schon lange.
Aber bisher ist mir nicht ganz klar, wie ich mit diesem Keyword NodeMCU im Namen der Module umgehen muss.
Was ich bisher dazu gelesen habe, verstehe ich so, dass das eine Art Befehls-Interpreter ist. Etwa hier steht es so. Ebenfalls steht unter der URL, dass ich genauso gut eine "custom firmware" über die Arduino IDE draufspielen kann. Und das ist es ja, was ich tun will.
Hier steht allerdings, dass ich einigen Heckmeck mit Reset und GPIO0 anstellen müsste, um das Modul dafür in den "bootload mode" zu zwingen. Andererseits geht es da ja um ein Modul ohne USB-Port....

Zunächst sammle ich erst mal die URLs von ein paar nützlich aussehenden Seiten:
- Firmware Options
- ein Video zum Thema "programming via Arduino IDE", das erst ab Minute 7:30 interessant wird
- und noch ein Video, diesmal zum Thema "power saving"
- ein Wiki zum ESP8266
- die Reference zum "ESP8266 Arduino Core"

Hier steht, dass der ESP-12E im deep sleep mode ca. 15µA zieht - aber auch, dass er ca. 300ms zum aufwachen braucht.
Das würde ihn dann ja wohl als neue Plattform für meinen Temperatur- und Helligkeits-Logger disqualifizieren. Wenn der alle fünf Sekunden aufwachen soll, damit aber jedes mal 300ms Wach-Phase (mit ca. 15mA) hat, dann ergäbe das pro Minute eine Wach-Zeit von 12*0,3=3,6 Sekunden. Pro Stunde schon 216 Sekunden und pro Tag 5.184 Sekunden bzw. 86 Minuten. Also würden pro Tag über eine Stunde lang 15mA verbraten werden. Das kann meine Schaltung mit ATmega und ESP-01 deutlich besser.
Mal gucken, welche anderen sleep-Modi es noch so gibt - in denen der ESP-12E dann zwar vielleicht mehr als 15µA vernascht, aber der ansonsten besser zu meiner fünf-Sekunden-Aufwach-Frequenz passt.

In diesem PDF von Espressif steht schon mal, dass es neben deep-sleep (~20µA) auch einen light-sleep (0,4mA) und einen modem-sleep (15mA) gibt. Aus dem Modus light-sleep dauert das Aufwachen weniger als 3ms. Ganz am Ende des Dokuments wird empfohlen, bei Schlafzeiten über zwei Sekunden deep-sleep zu verwenden.


die ersten ESP-12E-Module wurden geliefert

Bereits heute wurden die drei bestellten Billig-Module geliefert (11,70€ für alle drei zusammen!).
Deren Lieferdatum war zwischen dem 19.01. und dem 06.02. angekündigt.
Deshalb habe ich ein paar Tage später noch ein ähnliches Modul zum Stückpreis von 12,99€ bestellt.
Das wird wohl morgen kommen.... 12,99€ für die Katz.... Naja, dafür hat das wohl immerhin einen leistungsfähigeren 3,3V-Regler drauf.

Das USB-Interface des (zuerst getesteten) Billig-Moduls meldet sich als "QinHeng Electronics USB2.0-Serial".
In der Arduino IDE habe ich eingestellt:
- Board: "NodeMCU 1.0 (ESP-12E Module)"
- CPU Frequency: "80 MHz"
- Flash Size: "4M (3M SPIFFS)"
- Upload Speed: "115200"
- Port: "/dev/ttyUSB0"

Der Blink-Sketch aus den Beispielen für den ESP8266 hat augenscheinlich was verändert, aber erstmal hat da nix mehr geblinkt - mehr deswegen, weil ab Werk offenbar bereits ein Blink-Sketch eingespielt worden war.
Hier habe ich dann gefunden, dass die blaue onboard-LED auf GPIO2 liegen soll.
Und mit digitalWrite(2, LOW); blinkt es dann auch in der von mir eingestellten Frequenz.
Das Terminal funktioniert ebenfalls wie vom Arduino gewohnt. Also in setup() ein Serial.begin(115200); und in loop() ein Serial.println("blink"); bringt das erwartete Ergebnis.

Das war ja jetzt vollkommen schmerzfrei. Klappt quasi direkt.
Lediglich der Upload dauert deutlich länger als beim Arduino.
Ganz grob etwa 28 Sekunden für das Blink-Sketch.
Als Meldung kommt in der IDE das hier:
Warning: Board breadboard:avr:atmega328bb doesn't define a 'build.board' preference. Auto-set to: AVR_ATMEGA328BB

Der Sketch verwendet 224.153 Bytes (21%) des Programmspeicherplatzes. Das Maximum sind 1.044.464 Bytes.
Globale Variablen verwenden 31.656 Bytes (38%) des dynamischen Speichers, 50.264 Bytes für lokale Variablen verbleiben. Das Maximum sind 81.920 Bytes.
Uploading 228304 bytes from /tmp/arduino_build_508065/Blink.ino.bin to flash at 0x00000000
................................................................................ [ 35% ]
................................................................................ [ 71% ]
...............................................................                  [ 100% ]


Den nächsten Test habe ich mit dem NTPClient-Sketch aus den mitgelieferten Beispielen gemacht.
Schnell meine SSID eingetragen, Passwort auf Leerstring gesetzt, hochgeladen und ... klappt :-)
Auf dem DHCP-Server hat sich das Teil als ESP_951444 gemeldet.

Das Beispiel-Sketch TestEspApi meldet:
ESP starting.
system_get_time(): 18254785
system_get_rst_info() reset reason: REASON_EXT_SYS_RST
system_get_free_heap_size(): 45472
system_get_os_print(): 0
system_get_os_print(): 1
system_get_chip_id(): 0x951444
system_get_sdk_version(): 1.5.3(aec24ac9)
system_get_boot_version(): 31
system_get_userbin_addr(): 0x0
system_get_boot_mode(): SYS_BOOT_NORMAL_MODE
system_get_cpu_freq(): 160
system_get_flash_size_map(): FLASH_SIZE_32M_MAP_512_512
wifi_get_opmode(): 3 - STATIONAP_MODE
wifi_get_opmode_default(): 3 - STATIONAP_MODE
wifi_get_broadcast_if(): 2
 
SoftAP Configuration
--------------------
ssid:            TestAP
password:        testtesttest
ssid_len:        6
channel:         1
authmode:        AUTH_WPA2_PSK
ssid_hidden:     0
max_connection:  4
beacon_interval: 100ms
--------------------
 
wifi_get_channel(): 6
wifi_get_phy_mode(): PHY_MODE_11N
system_get_time(): 18322740
EVENT_STAMODE_CONNECTED ()
EVENT_STAMODE_GOT_IP ()

Daraufhin habe ich das Setting "CPU Frequency" in der IDE auf 160MHz geändert und das Sketch erneut kompiliert und hochgeladen.
Ergebis: klappt ebenfalls.

Nun noch ein GET_TIME bei meinem Rollotron-SocketServer:
/*
 *  GET_TIME @ ss
 */

#include <ESP8266WiFi.h>

void setup() {
  Serial.begin(115200);
  WiFi.begin("FreifunkWees01.2 (http://ffw)", "");
 
  while (WiFi.status() != WL_CONNECTED) {
    delay(100);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected"); 
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}


char *getChecksum(char *strg) {
  static char buf[5];
  int cs=0;
  for(char *ptr=strg; *ptr!='\0'; ptr++)  {
    cs+=*ptr;
  }
  snprintf(buf, 5, "%04x", cs);
  return(buf);
}


void loop() {
  WiFiClient client;
 
  if (!client.connect("192.168.42.80", 2626)) {
    Serial.println("connection failed");
    delay(1000);
    return;
  }

  client.write("GET_TIME,");
  client.write(getChecksum("GET_TIME"));
  while(client.available()==0) {
    delay(1);
  }
  while(client.available()>0) {
    Serial.print((char)client.read());
  }
  Serial.println("<EOT");

  client.stop();
  while(1) {delay(1000);}
}

Liefert im Terminal:
............................
WiFi connected
IP address: 
192.168.42.110
2017.01.23 19:49:22,03ba<EOT


Fazit: klappt alles.


Pin-Mapping

Als nächstes sollte ich vielleicht mal die IO-Ports durchtesten. An einigen Stellen hatte ich gelesen, das die Namen der Bezeichner aus der Library wohl nicht immer zur Realität bzw. dem konkreten Modul passen. Am Blink-Sketch durfte ich das ja schon selbst erfahren: der Bezeichner LED_BUILTIN war ganz offensichtlich nicht die fest verlötete LED.

Die Kontakte am Modul haben folgende Beschriftung:
Pin
Beschriftung

Pin
Beschriftung
1
5V

9
RST
2
G

10
A0
3
D4

11
D0
4
D3

12
D5
5
D2

13
D6
6
D1

14
D7
7
RX

15
D8
8
TX

16
3V3

Wegen der nicht unerheblichen Upload-Zeit macht es wohl Sinn, ein Sketch zu bauen, das jeden Pin einzeln für z.B. drei Sekunden auf LOW setzt, dies per Terminal meldet, danach wieder auf HIGH setzt und zum nächsten Pin wechselt. Mit einem Multimeter könnte man dann die Pins -einen nach dem anderen- messen und notieren, welcher Pin jeweils im Terminal zu dem Zeitpunkt gemeldet wurde, als sich die gemessene Spannung geändert hat.

Im Verzeichnis ~/.arduino15/packages/esp8266/hardware/esp8266/2.3.0/variants/nodemcu liegt eine Datei pins_arduino.h mit folgenden Zuweisungen:
static const uint8_t SDA = 4;
static const uint8_t SCL = 5;

static const uint8_t LED_BUILTIN = 16;
static const uint8_t BUILTIN_LED = 16;

static const uint8_t D0   = 16;
static const uint8_t D1   = 5;
static const uint8_t D2   = 4;
static const uint8_t D3   = 0;
static const uint8_t D4   = 2;
static const uint8_t D5   = 14;
static const uint8_t D6   = 12;
static const uint8_t D7   = 13;
static const uint8_t D8   = 15;
static const uint8_t D9   = 3;
static const uint8_t D10  = 1;

Weiterhin wird darin eine Datei ../generic/common.h geladen:
#define EXTERNAL_NUM_INTERRUPTS 16
#define NUM_DIGITAL_PINS        17
#define NUM_ANALOG_INPUTS       1

static const uint8_t SS    = 15;
static const uint8_t MOSI  = 13;
static const uint8_t MISO  = 12;
static const uint8_t SCK   = 14;

static const uint8_t A0 = 17;


Das wird ja spannend.... was für ein Kuddelmuddel.
Heute wird das nix mehr.


Pin-Mapping - Realitätsabgleich

Erstmal noch ein paar Informationsquellen:
- ein PDF zum ESP-12E WiFi Module
- Getting started with the esp8266 (ESP-12e)
- Comparison of ESP8266 NodeMCU development boards
- Espressif Documents
- WeMos D1 mini

Die letzte URL ist besonders interessant, weil es dort offenbar um ein Modul geht, welches meinem recht ähnlich ist.
Ein Schaltbild vom Modul gibt es außerdem. Allerdings fehlt darin mindestens schon mal die LED. Auch besteht die "USB to UART"-Einheit im Schaltbild aus zwei Chips, auf meinem Modul befindet sich aber nur ein Chip (zusätzlich zum ESP).

Erste Erkenntnis beim Pin-Zuordnungs-Sketch: der ESP-12E mag es gar nicht, wenn man einfach an die Pin-Nummer 0 bis 16 ein pinMode(p, OUTPUT) gefolgt von einem digitalWrite(p, HIGH) schickt. Das führt zum Absturz.
Daher nun also folgendes Sketch:
int pins[]={16, 5, 4, 0, 2, 14, 12, 13, 15};

void setup() {
  Serial.begin(115200);

  for(int p=0; p<9; p++) {
    pinMode(pins[p], OUTPUT);
    digitalWrite(pins[p], LOW);
  }
}

void loop() {
  for(int p=0; p<9; p++) {
    Serial.println(pins[p]);
    digitalWrite(pins[p], HIGH);
    delay(3000);
    digitalWrite(pins[p], LOW);
  }
}
Der Inhalt von pins[] stammt aus der Zuordnungs-Tabelle von WeMos D1 mini.
Und es stellt sich heraus, dass die dort angegebene Zuordnung auch für mein Modul zutrifft:
Beschriftung
Pin#

Beschriftung Pin#
5V


RST

G


A0

D4
2

D0
16
D3
0

D5
14
D2
4

D6
12
D1
5

D7
13
RX


D8
15
TX


3V3


Ebenfalls passt dazu die Zuordnung aus pins_arduino.h - abgesehen von LED_BUILTIN.
Somit könnte man auch die symbolischen Namen für die Pins benutzen.
Andererseits passt das dann zwar zu der Beschriftung auf dem Entwicklungs-Modul, aber nicht mehr zu der des eigentlichen ESP-12E-Moduls - welches schließlich die vorgesehene Ziel-Plattform ist.

Dabei muss dann wohl auch beachtet werden, dass das D1mini-Modul laut Schaltbild die Pins GPIO0 und GPIO2 per 10KΩ-Pullup auf HIGH und den Pin GPIO15 per 10KΩ-Pulldown auf LOW zieht. Gemäß der Doku zum ESP-12E-Modul wird damit der sog. "Flash Boot"-Modus eingestellt. Parallel dazu gäbe es den sog. UART-Modus, bei dem stattdessen GPIO0 auf LOW gezogen werden müsste.
Hier steht, dass "Flash Boot" den normalen Start des aktuell hochgeladenen Programms einleitet und mit UART-Modus der Hochlade-Modus gemeint ist - bei dem also ein neues Programm empfangen und geflashed wird.
Wahrscheinlich werden die drei Ports nach der Boot-Phase normal und frei nutzbar sein - aber die 10KΩ-Widerstände bleiben da und heizen ggf. die Umwelt....naja, 3,3V/10KΩ=0,33mA. Bei drei Widerständen aber schon 1mA, wenn vom Programm aus der jeweils andere Pegel angelegt wird. Und statt 10KΩ einfach 1MΩ zu nehmen, wird wohl auch nix werden, weil der dann nicht mehr den Chip-internen Widerstand überstimmen kann.

Drei Bit für zwei Boot-Modi sind ausgesprochen üppig. Es könnte acht davon geben. Hier stehen sie.


drei unterschiedliche Varianten

Heute wurden die anderen beiden bestellten ESP-12E-Module geliefert.
Damit sieht mein ESP-12E-Zoo jetzt folgendermaßen aus:
Foto der drei ESP-12E-Modelle

Von dem linken ELEGIANT NodeMcu Lua ESP8266 ESP-12E WIFI Development Board habe ich eins.
In der Mitte das Mirocle ESP8266 ESP-12 NodeMcu Lua WeMos D1 Mini WiFi Entwicklung Kit Development Board, von dem ich drei habe.
Ganz rechts 3/5 von JVJ 5X ESP8266 ESP-12E Wireless WiFi Module serielle Transceiver Plattenmodul.

Das Elegiant-Modul meldet sich mit dem selben Namen beim USB, wie das WeMos-D1mini-Modul. Allerdings passt hier LED_BUILTIN aus der pins_arduino.h zum Modul. Der ESP ist mit ESP-12F beschriftet. Laut dieser Tabelle hat der ESP-12F die gleichen Daten, wie der ESP-12E.
Beim TestEspApi kommt quasi der selbe Output wie beim WeMos-D1mini:
ESP starting.
system_get_time(): 17362548
system_get_rst_info() reset reason: REASON_EXT_SYS_RST
system_get_free_heap_size(): 46768
system_get_os_print(): 0
system_get_os_print(): 1
system_get_chip_id(): 0x23ED8B
system_get_sdk_version(): 1.5.3(aec24ac9)
system_get_boot_version(): 31
system_get_userbin_addr(): 0x0
system_get_boot_mode(): SYS_BOOT_NORMAL_MODE
system_get_cpu_freq(): 160
system_get_flash_size_map(): FLASH_SIZE_32M_MAP_512_512
wifi_get_opmode(): 2 - SOFTAP_MODE
wifi_get_opmode_default(): 2 - SOFTAP_MODE
wifi_get_broadcast_if(): 2
 
SoftAP Configuration
--------------------
ssid:            TestAP
password:        testtesttest
ssid_len:        6
channe
beacon_interval: 100ms
--------------------
 
wifi_get_channesystem_get_time(): 19392300


Wie ich die nackigen ESP-12Es an irgendwas anschließen soll, habe ich mir noch gar nicht überlegt. Dessen Kontakte halten nicht den Lochraster-Abstand von 1/10 inch bzw. 2.54mm ein. Wahrscheinlich wird es auf sowas hier hinauslaufen.
Das wäre jetzt mein erster nützlicher Einsatzzweck für einen 3D-Drucker.... wobei sich damit ja auch kein vollwertige Sockel produzieren ließe - also komplett mit (federnden) Kontakten.

Auf der nächsten Seite gehts weiter.