-->
Page 1 of 1

RAM limit?

PostPosted: Sat Jul 16, 2016 9:30 am
by Claudio Hutte
Hello everybody, I'm new to this environment and I found a problem that makes me puzzled.
Basically the problem is the inability to write into a char buffer. I call a function which parses a source buffer and put the results into a destination buffer. While the source buffer is fine, the destination buffer appears not writable apart the first 225 bytes, and some garbage characters are left into it. In addition when the function exits the process stops and a Watchdog reset happen.

This is the part of the code where the problem has been triggered:
Code: Select allsize_t parseDoc( char* buf, size_t len, char* dest, size_t lendest, AsyncWebServerRequest *request ) {
   ...(omissis)...

  strncat(dest, &buf[lastchunk], i-lastchunk);  // copy in output the previous chunk
  // code added to debug:
  z = strlen(dest);
  dest[z] = 'X';  // X not won't be set, actual length is less than the amount of appended bytes

  Serial.printf("\nstrlen:%d, free heap:%d, dest*:%x - 1: \n", z, ESP.getFreeHeap(), &dest); 
  Serial.print(dest);

   ...(omissis)...
}


The problem seems to be this: the pointer of dest is 3fffdba0h, which apparently put it out of RAM space. Accordingly to what I found here: https://github.com/esp8266/esp8266-wiki/wiki/Memory-Map
user data RAM for applications spans from 3FFE8000h to 3FFFC000h (RAM size 81920 bytes), placing the pointer 3FFFDBA0h clearly out of space.

However the getFreeHeap returns 32928.

The compiler (I use Arduino IDE) says:
Code: Select allSketch uses 309,578 bytes (29%) of program storage space. Maximum is 1,044,464 bytes.
Global variables use 41,124 bytes (50%) of dynamic memory, leaving 40,796 bytes for local variables. Maximum is 81,920 bytes.


so the free heap is apparently roughly at the expected value.

I am stuck, any hint that could help me in pointing out what is going on is really appreciated.

Hardware: NodeMCU 0.9 (ESP12 Module)
Libraries included: ESPAsyncTCP, ESPAsyncWebServer, ESP8266WiFi, ESPDNSserver, ESP8266mDNS

Re: RAM limit?

PostPosted: Sun Jul 17, 2016 6:33 pm
by Claudio Hutte
SOLVED
I declared both buffers within the scope of an other function that in turn calls parseDoc, so these variables should be allocated in some stack space rather the heap, space that seems to be quite limited.
I moved the two buffers in the global scope with fixed dimensions and the problem appears solved.

WDT

PostPosted: Thu Jul 21, 2016 9:15 am
by mrburnette
In addition when the function exits the process stops and a Watchdog reset happen.


So, the ESP8266 RF code and protocol stack(s) all run before the Arduino sketch (user code) is initialized. The process is somewhat akin to a proto-thread where the Arduino gets approximately 50mS (max) to run and then the user code must return control to the native ESP8266 functions. The implementation of void loop{} causes a return upon every full loop and these commands do also: delay(0) and yield() as well as just the standard use of delay(n). You can also force 'pat the dog' to reset the WDT (but this does not keep the RF section from going stale and should be done only if the RF is off.)

The following Prime Numbers example is from the Arduino UNO world and has been rewritten for the ESP8266 and shows the use of delay(0):
Code: Select all/*
  PrimeNos: by Nick Gammon
  ESP8266 Arduino port m. ray burnette
  OS version Linux Mint 17.3 32-bit tested on 20160422
  IDE settings: NodeMCU 1.0 (ESP-12E Module). 80 MHz, 115200, 4M (1MSPIFFS)
  Compiled under Arduino 1.6.8
    Sketch uses 223,060 bytes (21%) of program storage space. Maximum is 1,044,464 bytes.
    Global variables use 31,663 bytes (38%) of dynamic memory, leaving 50,257 bytes for local variables. Maximum is 81,920 bytes.
  PUBLIC DOMAIN EXAMPLE
  RF sleep reference: https://github.com/esp8266/Arduino/issues/460#issuecomment-168970936
*/

extern "C" {
#include "user_interface.h"
}

#define BOARD_LED_PIN  2
#define FREQUENCY     80                                    // valid 80, 160

#include <ESP8266WiFi.h>                                    // for the low power function only
#include <Streaming.h>                                        // http://arduiniana.org/libraries/streaming/

// just add more primes to the prime table for larger search
// byte data type to save memory - use a larger datatype with prime table entries above 255 :)
byte primes[]= {
    2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101,
    102, 107, 109, 113, 127, 131,  137 , 139, 149, 151, 157, 163, 167, 173,  179, 181, 191, 193, 197,
    199, 211, 223, 227, 229, 233, 239, 241, 251 };

// if you change the datatype of primes array to int, change next line to
// "const int TopPrimeIndex = (sizeof(primes)/2) - 1;"

const unsigned int  TopPrimeIndex = sizeof(primes) - 1;     
const unsigned long TopPrimeSquared = (long)primes[TopPrimeIndex] * (long)primes[TopPrimeIndex];
int primeFlag;
unsigned long t = 0;


void setup()                   
{
   
  WiFi.forceSleepBegin();                                   // turn off ESP8266 RF
  delay(1);                                                 // give RF section time to shutdown
  // yield();                                               // generally same as delay(1) but inconsistent
  system_update_cpu_freq(FREQUENCY);

  pinMode(BOARD_LED_PIN, OUTPUT);
  Serial.begin(115200);
  delay(1);

  Serial << "\n\n\n\r\r\r" ;
  Serial << "Prime Number Generator by Nick Gammon\r\n";
  Serial << "ESP8266 port by Ray Burnette\r\n\r\n";
  Serial << "Number of primes in prime table = ";
  Serial << TopPrimeIndex << endl << endl;
  Serial << "Last prime in table =  ";
  Serial << (unsigned int)primes[TopPrimeIndex] << endl;
  Serial << "Calculating primes through ";
  Serial << TopPrimeSquared << endl << endl;
  Serial << "Starting uS timer now... ";
  t = micros();
}


void loop()
{
 for (long x = 1; x < TopPrimeSquared; x+=2)             // skips even numbers, including 2, which is prime, but it makes algorithm tad faster
      {
            for (long j=0; j < TopPrimeIndex; j++){
            primeFlag = true;

            if (x == primes[j]) break;

            if (x % primes[j] == 0){                        // if the test number modolo (next number from prime table) == 0
                primeFlag = false;                          //  then test number is not prime, bailout and check the next number
                break;
            }
            delay(0);
        }
        if (primeFlag == true)                              // found a prime
        {
            digitalWrite(BOARD_LED_PIN,!digitalRead(BOARD_LED_PIN));
            yield();
            // Serial.println(x);
        }
      }
    Serial << "uS = " << micros()-t << endl;
    Serial << "Sketch terminating.  Press Reset to rerun." << endl;
    for(;;) yield() ;                                       // infinite loop with yield to prevent WDT
}



Ray