ESP8266 Memory Frage

Moin,

ich bin gerade dabei mit meinem ESP8266 einen Leistungsmesschip (ADE8266) auszulesen.
Der ADE bietet die Möglichkeit Momentanwerte der Spannung und des Stomes zur Anzeige des Phasenverlaufes auszulesen.

Hierzu ist es notwendig in einer Schleife möglichst viele Samples möglichst schnell auszulesen.
Der I2C-Bus arbeitet mit bis zu 800MHz, um es nicht zu übertreiben nutze ich 400kHz.

Die Messwerte und den Zeitpunkt des Samples möchte ich in zwei Arrays zwischenspeichern.

  unsigned long t[samples];
  uint32_t values[samples];
  unsigned long t0 = micros(); 
  for (int i=0; i<samples; i++){
    t[i] = micros();
    values[i] = random(100);  //exemplarisch readRegister ADE 
  }

Wie kann ich jetzt berechnen wie viele Samples in meinen Speicher passen?

Momentan lese ich den heap zur Kontrolle aus.

ESP.getFreeHeap()

Sehe hier aber keinen Zusammenhang zwischen freiem heap und benötigter Größe der beiden Arrays.

Bei 200 Samples erhalte ich folgende Werte:

call TEST      = 46592  <- vor Aufruf der function
run TEST       = 46568  <- in der function
Samples        = 200
ArraySize      = 12800  // = 2 * 32 * 200
destruct TEST  = 46592  <- nach der function

Bei mehr als 270 Samples laufe ich in einen Reset:

call TEST      = 46592<\r><\n>
run TEST       = 46568<\r><\n>
Samples        = 280<\r><\n>
ArraySize      = 17920<\r><\n>
<\r><\n>
 ets Jan  8 2013,rst cause:4, boot mode:(1,6)<\r><\n>
<\r><\n>
wdt reset

Im heap sollten doch aber noch mehr als 17920 bytes zur Verfügung stehen.
Warum gibt es einen Absturz?
Kann mir hier jemand die Zusammenhänge ein wenig näher bringen?

Danke für euer Unterstützung

Gruß
Pf@nne

Was machst Du sonst noch in Deinem Sketch? Das kann auch Speicher brauchen.

Gruß Tommy

Das ist nur ein Testsketch der auf ein Minumum, soweit man beim ESP-Board von Minimum sprechen kann…

mqtt_esp8266.ino (4.47 KB)

Was sagt denn Deine Arduino-IDE vorm Hochladen über den Speicher? Sie braucht ja selbst auch einiges.
Edit: bei 280 Samples.

Gruß Tommy

Der Sketch verwendet 235757 Bytes (22%) des Programmspeicherplatzes. Das Maximum sind 1044464 Bytes.
Globale Variablen verwenden 33040 Bytes (40%) des dynamischen Speichers, 48880 Bytes für lokale Variablen verbleiben. Das Maximum sind 81920 Bytes.

Da sollte doch auch noch Luft sein.....

//===> Librarys <===============================================================
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <AktSen.h>


//===> GLOBAL <=================================================================

//===> constants <--------------------------------------------------------------
const char* ssid = "xxxxxxxx";
const char* password = "xxxxxxx";
const char* mqtt_server = "192.168.1.203";

//===> variables <--------------------------------------------------------------
WiFiClient espClient;
PubSubClient client(espClient);
IPAddress ip;



//===> SETUP <==================================================================

void setup() {
  //RS232
  Serial.begin(115200);
  
  //ESP8266
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
}

//===> WIFI SETUP <-------------------------------------------------------------
void setup_wifi() {

  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  ip = WiFi.localIP();
}

//===> SUB-Routines <===========================================================

//===> MQTT callback <------------------------------------------------------
void callback(char* topic, byte* payload, unsigned int length) {
  char value[500] = "";
  for (int i = 0; i < length; i++) {
    value[i] = payload[i];
  }
  
  //Serial.println(topic);
  
  if (strcmp(topic, "ESP8266_1032096/ADE7953/getValues/getWaves") == 0){    
    Serial.println("===============================");
    Serial.println("call TEST      = " + String(ESP.getFreeHeap()));
    //TEST(String(value).toInt());
    TEST(String(value).toInt());
    Serial.println("destruct TEST  = " + String(ESP.getFreeHeap()));
  }

}
//===> MQTT publishTEST <------------------------------------------------------
void TEST(int samples) {
  Serial.println("run TEST       = " + String(ESP.getFreeHeap()));
  Serial.println("Samples        = " + String(samples));
  Serial.println("ArraySize      = " + String(2 * 32 * samples));

  unsigned long t[samples];
  uint32_t values[samples];
  unsigned long t0 = micros(); 
  for (int i=0; i<samples; i++){
    t[i] = micros();
    values[i] = random(100);
  }
  
  String wave = "";
  for (int i=0; i<samples; i++){
    wave = String(0.001*(t[i]- t0), 5);
    wave += ",";
    wave += String(values[i], 2);
    client.publish("ESP8266_1032096/ADE7953/values/V_INST", wave.c_str());
    client.loop();
  }  
}

//===> MQTT reconnect if lost <--------------------------------------------------
void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect("ESP8266Client")) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      //client.publish("outTopic", "hello world");
      // ... and resubscribe
      client.subscribe("ESP8266_1032096/#");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}


//===> MAIN-LOOP <===========================================================

void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();
}

Du verwendest sehr häufig die Klasse String. Das könnte Deine Speicherprobleme erklären. String fragmentiert den Heap und irgendwann ist der zu Ende.
String wird angelegt, es wird etwas angehangen, Umwandlung in String = neuer String, angehängt wieder neuer String und keiner räumt auf. Es gibt keine Garbage Collection, wie in JAVA.
Das muss nicht zwingend, kann aber sehr wahrscheinlich die Ursache sein.

Mach das Ganze mal mit char-Arrays und schau ob das Problem noch besteht.

Gruß Tommy

Moin Tommy,

Tommy56:
Du verwendest sehr häufig die Klasse String. Das könnte Deine Speicherprobleme erklären. String fragmentiert den Heap und irgendwann ist der zu Ende.
String wird angelegt, es wird etwas angehangen, Umwandlung in String = neuer String, angehängt wieder neuer String und keiner räumt auf.

Das könnte natürlich sein, ich setze die Sample-Daten ja per String zusammen, das passiert auch ständig immer wieder…Ich werde die Schleife mal auf char-Array umstellen und berichten.

  String wave = "";
  for (int i=0; i<samples; i++){
    wave = String(0.001*(t[i]- t0), 5);
    wave += ",";
    wave += String(values[i], 2);
    client.publish("ESP8266_1032096/ADE7953/values/V_INST", wave.c_str());

Ich habe den Schleifenteil mal auf char umgeschrieben…

  for (int i=0; i<samples; i++){
    char cTime[30] {""};
    char cValue[15] {""};
    dtostrf(0.001*(t[i]- t0) , 1, 5, cTime);
    dtostrf(values[i], 1, 5, cValue);
    
    strcat(cTime, ",");
    strcat(cTime, cValue);
    
    client.publish("ESP8266_1032096/ADE7953/values/V_INST", cTime);
    client.loop();
  }

Leider ohne Erfolg, mehr als 280 Samples gehen trotzdem nicht obwohl
290 Samples * 2 * 32 = 18560 bei freiem heap von 46760 doch locker passen sollten.

===============================<\r><\n>
call TEST      = 46760<\r><\n>
run TEST       = 46736<\r><\n>
Samples        = 290<\r><\n>
ArraySize      = 18560<\r><\n>
destruct TEST  = 43560<\r><\n>
<\r><\n>
 ets Jan  8 2013,rst cause:4, boot mode:(3,7)<\r><\n>
<\r><\n>
wdt reset<\r><\n>
load 0x4010f000, len 1384, room 16 <\r><\n>
tail 8<\r><\n>
chksum 0x2d<\r><\n>
csum 0x2d<\r><\n>
v3de0c112

Hat hier jemand noch eine zündende Idee oder Erklärung für mich?
Ich würde das sonst mal als Issue auf GitHub beim ESP-Board posten

Gruß
Pf@nne

Ich weiß nicht, was die Funktion als Heapsize ausgibt.
Die Funktion für den Flashspeicher getFlashChipRealSize(); gibt Bit aus, nicht Byte.

Gruß Tommy

Hmmm....hab jetzt nicht rausfinden können was heapSize ausgibt, wenn es aber Bit wären,
dann wäre ja bei 46760 Bit / 8 = 5845 Byte schon Schluss.
Was dann ja 5845 / 2 / 32 = 91 Samples entsprechen würde.

Ich stehe da momentan auf dem Schlauch......

Ja, dann wäre schon eher Schluss.
Ich weiß im Moment auch nicht weiter. Was sagt denn die IDE nach dem Kompilieren über freien Speicher?

Gruß Tommy

Der Sketch verwendet 235641 Bytes (22%) des Programmspeicherplatzes. Das Maximum sind 1044464 Bytes.
Globale Variablen verwenden 33036 Bytes (40%) des dynamischen Speichers, 48884 Bytes für lokale
Variablen verbleiben. Das Maximum sind 81920 Bytes.

48884, das passt zum heap in Bytes......
Platz sollte hier also reichlich vorhanden sein......

Ja, das klingt in sich logisch, hilft Dir aber nicht weiter.
Ich habe keine Idee mehr.

Gruß Tommy

Moin Tommy,

erstmal vielen Dank.
Vielleicht hat ja jemand anderes noch eine unterstützende Idee.....

Gruß
Pf@ne

P.S. getFlashSize ist auch in Bytes....

============================================
Flash real id:   001640E0
Flash real size: 4194304
Flash ide  size: 4194304
Flash ide speed: 40000000
Flash ide mode:  DIO
Flash Chip configuration ok.
============================================

OK, die lokalen Arrays liegen auf dem Stack nicht auf dem Heap!!
Der Stack ist beim ArduinoESP default auf 4k begrenzt.

Die Arrays lokal zu deklarieren hilft!

Das verstehe ich jetzt nicht. Wenn Du mehr Heap als Stack hast, wieso bringt es dann einen Vorteil, die Arrays auf dem begrenzten Stack anzulegen (also lokal)?

Gruß Tommy

Blödsinn, es muss natürlich global heißen....lokal hatten wir ja schon....
:grin:

Ok, dann bin ich wieder bei Dir.

Gruß Tommy

OK, das ist gut ich bin so ungern alleine...... :slight_smile: