como-servir-contenido-desde-memoria-flash-en-el-esp8266

How to serve content from Flash memory on ESP8266 or ESP32

  • 5 min

In this post from the section on ESP8266 and ESP32 we are going to see how to serve content from Flash memory, to avoid unnecessary RAM consumption.

We will refer to the ESP8266, but the same code is compatible with the ESP32, adjusting the library names. At the end you have the code for both ESP8266 and ESP32.

In previous posts we have seen how to make a simple server, how to distinguish between requests and read parameters, and how to serve dynamic content by generating a String in the request.

We already said that one of the problems with generating content dynamically is that it puts a load on the processor (compared to generating a static file) and that, if the response is long, it takes up a lot of memory in the variable space.

One way to avoid the latter is to store the static parts of the response in Flash memory and combine them with those that are actually going to change. This partially alleviates the memory usage problem.

It should be emphasized that this should only be used for dynamic content, i.e., content that will change between requests. For serving static content we have better alternatives like SPIFFS, which we will see in the next post.

Serve Content from Flash

Serving content from Flash memory is really simple.

Our Sketch is practically the same, we have only included a new file ‘index.h’ which will contain the String to be served.

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>

bool ledStatus = false;  // Example variable

#include "config.h"  // Replace with your network data
#include "index.h"
#include "ESP8266_Utils.hpp"
#include "Server.hpp"

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

   ConnectWiFi_STA();
   
   InitServer();
}
 
void loop()
{
   server.handleClient();
}
Copied!

Finally, our ‘Server.hpp’ file looks like this.

ESP8266WebServer server(80);

void handleRoot() {
   String response = MAIN_page;
   server.send(200, "text/html", response);
}

void handleNotFound() {
   server.send(404, "text/plain", "Not found");
}

void InitServer()
{
   server.on("/", handleRoot);
   server.onNotFound(handleNotFound);
   server.begin();
   Serial.println("HTTP server started");
}
Copied!

On the other hand, we create the ‘index.h’ file, where we have simply created a Char array containing the “Hello world” web page we want to serve.

To save it in flash memory we have used ‘PROGMEN’, so that this constant is not stored in the memory dedicated to variables.

const char MAIN_page[] PROGMEM = R"=====(
<!DOCTYPE html>
<html>
<body>

<div>
   <h1>Hello world!</h1>
</div>

</body>
</html>
)=====";
Copied!

In this simple example, we have only routed the root URL to the previous MAIN_page variable. The served content is a constant and does not vary (it is static). Next, we will see a slightly more realistic example.

Remember that we have better methods for serving static content, and we will see them in the following posts.

Serve Dynamic Content from Flash

So, in what circumstances can this be useful? For serving ‘pseudo-dynamic’ content, i.e., to host the parts of a dynamic response that do not vary, reducing the variable memory used.

For example, suppose that, continuing with the example from the previous post, we want to serve a Web page that shows the status of any variable. In this example the variable will be ‘ledStatus’.

In the previous post we returned a brief String informing about the variable’s status. But if we want to serve a Web page, there is a lot of content that is similar, and only a part of the served Web page changes.

In this case, it may make sense to store the ‘static’ parts of the response in PROGMEM variables.

We modify the ‘Server.hpp’ file to serve ‘HTML_PART_1’, then our dynamic content, and finish with ‘HTML_PART_2’.

ESP8266WebServer server(80);

void handleRoot() {
   String response = ledStatus ? "ON" : "OFF";

   server.setContentLength(sizeof(HTML_PART_1) + sizeof(response) + sizeof(HTML_PART_2));
   server.send(200, "text/html", HTML_PART_1);
   server.sendContent(response);
   server.sendContent(HTML_PART_2);
}

void handleNotFound() {
   server.send(404, "text/plain", "Not found");
}

void InitServer()
{
   server.on("/", handleRoot);
   server.onNotFound(handleNotFound);
   server.begin();
   Serial.println("HTTP server started");
}
Copied!

We modify ‘index.h’ to contain

const char HTML_PART_1[] PROGMEM = R"=====(
<!DOCTYPE html>
<html>
<body>

<div>
   <h1>Hello world!</h1>
   <p>LED: 
)=====";

const char HTML_PART_2[] PROGMEM = R"=====(
   </p>
</div>

</body>
</html>
)=====";
Copied!

And if we now access with the browser we will see that, instead of a simple “LED: OFF” we have served a complete Web page in which we only modify the content we want.

esp8266-server-from-flash

Of course, we have other ways to implement an application of this type. Normally we would serve a static Web page, and the frontend would make a query to an Endpoint to obtain the variable’s content.

However, although in upcoming posts we will see how to achieve a result similar to the example in a more conventional way, the important thing is to illustrate that it is possible to use Flash memory to serve content and lighten RAM consumption.

We will see all this soon. In the next post we will learn to use the SPIFFS file system to serve static content. See you soon!

Download the Code

All the code from this post is available for download on Github.

github-full

Version for ESP8266: https://github.com/luisllamasbinaburo/ESP8266-Examples

Version for ESP32: https://github.com/luisllamasbinaburo/ESP32-Examples