Phänomen: Störungen bei Aufruf von OLED in Callback Function (ESP32)

Ich beschäftige mich gerade mit ESP-NOW in Verbindung mit zwei ESP32 mit OLED - mein neues Spielzeug :slight_smile: .
ESP-NOW funktioniert wie erwartet (=gut), allerdings ist mir ein "interessantes" Pänomen aufgefallen:
Wenn das Update des OLED in der Callback-Function für die ESP-NOW-Nachricht aufgerufen wird, kommt es zu eigenartigen Störungen auf dem OLED (zu sehen ist die Zahl 18):

oled_mit_stoerungen1.png

oled_mit_stoerungen2.png

Hier der Sketch (eigentlich nur ein einfacher Beispiel-Sketch):

// Hier gibt es Störungen

#include <esp_now.h>
#include <WiFi.h>

//OLED:
#include <U8g2lib.h>
U8G2_SSD1306_128X64_NONAME_F_HW_I2C  u8g2(U8G2_R0, 16, 15, 4);   // resetPin, sclPin, sdaPin

// Structure example to receive data. Must match the sender structure.
typedef struct struct_message {
  char a[32];
  int b;
  float c;
  String d;
  bool e;
} struct_message;

struct_message myData;

bool newData = false;

// callback function that will be executed when data is received
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
  memcpy(&myData, incomingData, sizeof(myData));
  Serial.print("Bytes received: ");
  Serial.println(len);
  Serial.print("Int: ");
  Serial.println(myData.b);
  newData = true;
  ausgabeOled();    // <<<------ hier gibt es "Störungen" am OLED
}

void ausgabeOled() {
  u8g2.clearBuffer();
  char myBuffer[5];
  sprintf(myBuffer, "%2d", myData.b);   // 2stellig
  u8g2.drawStr(10, 10, myBuffer );
  u8g2.sendBuffer();
  newData = false;
}

void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);    // Set device as a Wi-Fi Station
  if (esp_now_init() != ESP_OK) {    // Init ESP-NOW
    Serial.println("Error initializing ESP-NOW");
  }
  esp_now_register_recv_cb(OnDataRecv);    // Register for recv CB to get recv packet info

  // OLED:
  u8g2.begin();
  u8g2.setFont(u8g2_font_fub49_tn);
  u8g2.setFontRefHeightExtendedText();
  u8g2.setDrawColor(1);
  u8g2.setFontPosTop();
  u8g2.setFontDirection(0);
}

void loop() {
  if (newData) {
  //    ausgabeOled();   // <<<------ hier gibt es keine Störungen am OLED
  }
}

Wenn ich hingegen das OLED-Update in Loop aufrufe gibt es diese Störungen nicht und die Darstellung am OLED ist sauber:

oled_ohne_stoerungen.png

Hier der Sketch. Er unterscheidet sich von dem oben nur nur durch die beiden mit <<<------ gekennzeichneten Zeilen, die mal auskommentiert sind und mal nicht:

// Hier gibt es keine Störungen

#include <esp_now.h>
#include <WiFi.h>

//OLED:
#include <U8g2lib.h>
U8G2_SSD1306_128X64_NONAME_F_HW_I2C  u8g2(U8G2_R0, 16, 15, 4);   // resetPin, sclPin, sdaPin

// Structure example to receive data. Must match the sender structure.
typedef struct struct_message {
  char a[32];
  int b;
  float c;
  String d;
  bool e;
} struct_message;

struct_message myData;

bool newData = false;

// callback function that will be executed when data is received
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
  memcpy(&myData, incomingData, sizeof(myData));
  Serial.print("Bytes received: ");
  Serial.println(len);
  Serial.print("Int: ");
  Serial.println(myData.b);
  newData = true;
  // ausgabeOled();    // <<<------ hier gibt es "Störungen" am OLED
}

void ausgabeOled() {
  u8g2.clearBuffer();
  char myBuffer[5];
  sprintf(myBuffer, "%2d", myData.b);   // 2stellig
  u8g2.drawStr(10, 10, myBuffer );
  u8g2.sendBuffer();
  newData = false;
}

void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);    // Set device as a Wi-Fi Station
  if (esp_now_init() != ESP_OK) {    // Init ESP-NOW
    Serial.println("Error initializing ESP-NOW");
  }
  esp_now_register_recv_cb(OnDataRecv);    // Register for recv CB to get recv packet info

  // OLED:
  u8g2.begin();
  u8g2.setFont(u8g2_font_fub49_tn);
  u8g2.setFontRefHeightExtendedText();
  u8g2.setDrawColor(1);
  u8g2.setFontPosTop();
  u8g2.setFontDirection(0);
}

void loop() {
  if (newData) {
    ausgabeOled();   // <<<------ hier gibt es keine Störungen am OLED
  }
}

Diese Störungen sind nicht wirklich ein großes Problem, weil ich ja eine Lösung gefunden habe, aber interessieren würde mich schon, wieso es zu diesen Störungen kommt.
Hat jemand eine Idee?

Edit:
Bei dem ESP32-Board handelt es sich übrigens um ein "Heltec WiFi Kit 32", hier ein paar Links:

https://github.com/HelTecAutomation/HeltecDocs/tree/master/en/source/esp32%2Barduino
https://heltec-automation-docs.readthedocs.io/en/latest/esp32+arduino/index.html

Ich glaube aber eher weniger, dass das Phänomen speziell mit diesem Board zu tun hat.
Ich habe es auch mit einem anderen ESP-32 Board mit OLED ausprobiert (WEMOS LOLIN32) - da hängt das Display aber an anderen Pins - mit dem selben Resultat.

oled_mit_stoerungen1.png

oled_mit_stoerungen2.png

oled_ohne_stoerungen.png

uxomm:
Ich beschäftige mich gerade mit ESP-NOW in Verbindung mit zwei ESP32 mit OLED - mein neues Spielzeug :slight_smile: .

Ich habe nur einen normalen ESP32, ob ich Deine Situation dennoch nachstellen kann? Der Kompiler ist glücklich, allerdings wird nichts angezeigt, da ja keine Nachrichten reinkommen.

Ich habe auch einen zweiten ESP32 ;D

So richtig auskennen tue ich mich da nicht. Ich habe eine Vermutung dazu und wüsste gerne ob das in etwa hinkommt:

Eine Callback-Funktion wird ja aufgerufen wenn durch den Empfang von Daten ein Interrupt ausgelöst wurde. Wenn jetzt die Datenübertragung zum OLED für (microcontroller-Verhältnisse) relativ lange dauert funken da irgendwelche anderen Interrupts dazwischen und das bringt das Timing der Datenübertragung zum Display durcheinander.

Könnte das der Grund sein?

vgs

Wenn Datenübertragung zum OLED überhaupt ein Timing braucht, hat es in einer Interrupt-Routine eigentlich gar nichts zu suchen.
Da es dafür aber doch relativ gut geht, vermute ich, dass die callback-Funktion nicht wirklich in einer Interrupt-Routine abläuft, sondern etwas ESP-spezifisches ist.
(Wäre dann hier bei Arduinos eigentlich OffTopic)

Dass es irgendwie ein Timing-Problem ist, ist schon klar.

Nunja....

Es sind natürlich nicht nur die Interrupts, welche sich ins Gehege kommen können.
Sondern auch die 2(+1) Kerne des ESP32.

Wenn bei einem preemptiven Multitasking System nicht die volle Aufmerksamkeit auf Verriegelungen/Semaphoren gerichtet wird, dann passiert sowas schon mal.
z.B. Stichwort Wiedereintrittsfähigkeit/Reentrance
Threadsicherheit

Im Grunde kann das verwendete FreeRTOS das alles. Man muss es nur richtig anwenden.

Wo genau hier der Fehler liegt, kann ich auch nicht sagen, denn dieses ESP Now ist mir völlig fremd.

Danke für die Antworten!

Wer das nachbauen möchte: Die Beispiel-Sketche (für "Sender" und "Empfänger") stammen von hier:

ergänzt von mir durch die Ausgabe von Daten auf einem OLED.
Es funktioniert natürlich auch mit "normalen" ESP32 und einem externen OLED. Das "Phänomen" ist auch genau gleich.

Ich weiß eh dass das alles nur sehr am Rande mit "Arduino" zu tun hat. Man kann die ESPs eben über die Arduino-IDE programmieren (wie viele andere Boards auch) und deshalb finden sich hier im Forum vermehrt Threads zu ESPs :slight_smile:

Ob die Callback-Funktion in einer Interrupt-Routine abläuft weiß ich nicht (ich glaube eher nicht). Und dass es in irgendeiner Form ein "Timing-Problem" zu sein scheint, legt die "verschobene" Darstellung am OLED nahe. Was da aber "genau" abläuft bleibt für mich im Dunklen - damit kann ich aber leben :slight_smile:

Danke auch für das Stichwort "Threadsicherheit", da gab es interessanten Lesestoff.

Das Bild, dass ein ESP viel mehr von einer "Blackbox" hat wie ein ATMega328P, hat dieses Beispiel für mich wieder sehr deutlich werden lassen. :slight_smile:
Um diese "Blackbox" besser zu durchschauen, wäre intensive Beschäftigung mit FreeRTOS, ESP32 etc. nötig.
Mal sehen ... :slight_smile:

Aber auch wenn ich nicht dazu komme, werde ich ESPs auch weiterhin verwenden.
Oft reicht ja eine (mehr oder weiniger vage) Idee um ein Problem zu lösen, auch wenn man nicht immer im Detail weiß wan man tut :slight_smile: :slight_smile:


Weil ich mich noch etwas mehr mit ESP-NOW beschäftigt habe und es zur Übertragung von kleinen Datenmengen sehr brauchbar finde, hier noch ein paar Infos zu ESP-NOW:

ESP-NOW ist eine Direktverbindung zwischen ESPs (ESP8266, ESP32) über WLAN.

Eckdaten:
– Kommunikation mit max. 20 Geräten (wenn nicht encrypted, falls encrypted max. 10, nur 6 als AP)
– Nachrichtenlänge max. 250 Bytes
– Keine direkte Internet-Verbindung möglich/nötig
– Kein externer Router, Accesspoint oder DHCP-Server nötig (aber möglich)
– Sehr wenig Overhead (verglichen mit z.B. TCP/IP)
– Addressierung erfolgt über die Mac-Adressen der ESPs

  • Der "Sender" kann erkennen ob die Nachricht beim "Empfänger" angekommen ist

Es gibt 3 "Rollen":
– Controller
– Slave
– Combo

ESPnow ermöglicht sehr kurze Sendezeiten (weil sehr wenig Overhead) und dadurch können sich sehr lange Laufzeiten bei Batteriebetrieb ergeben, wenn Sleep-Modus verwendet wird.

Ein paar Links:

Andreas Spiess zu ESP-NOW:

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.