Memory and limits
A board has much less memory than a PC, and some things work differently from Windows. Here are the figures the VM and the IDE give, and what changes in your program.
Internal RAM and PSRAM
A board has two memories for your program:
- The internal RAM, the one the chip carries.
- The PSRAM, a separate, larger memory chip. Not every board has it, and the profile doesn't say.
The ESP32 and ESP32-S3 VMs work with PSRAM and without it. The ESP32-P4 and ESP32-S31 VMs need it: it is where they keep the screen frames.
| What | Where it goes |
|---|---|
| What your program creates: strings, lists, maps, objects… | The system decides by its size: small blocks to the internal RAM, and large ones to the PSRAM if there is one. The boundary is 4 KB on the ESP32 and the ESP32-S3, and 16 KB on the ESP32-P4 and the ESP32-S31. |
| Images: bitmaps, sprites and backgrounds | To the PSRAM if there is one; if not, to the internal RAM. Each pixel takes 2 bytes: a 320 × 240 image takes 153,600 bytes. |
| The screen's double buffer, on the ESP32 and the ESP32-S3 | To the internal RAM, and if it doesn't fit, to the PSRAM. One byte per pixel of the view: 76,800 bytes for 320 × 240. |
| The screen frames, on the ESP32-P4 and the ESP32-S31 | Two, the size of the panel, in the PSRAM. Two bytes per pixel: 1,036,800 bytes each on a 720 × 720 panel. |
| Samples and music of 4 KB or more | To the PSRAM if there is one; if not, to the internal RAM. |
To see how much memory you use, use memUse() and memFree(), from the standard library:
| Windows | ESP32 / ESP32-S3 | ESP32-P4 | ESP32-S31 | |
|---|---|---|---|---|
memUse() | What the VM has allocated for your program | Same | Same | Same |
memFree() | Always 0 | The free internal RAM, without the PSRAM | All the free memory, PSRAM included | All the free memory, PSRAM included |
On the board, the garbage collector kicks in more often than on Windows: its growth factor is 1.2, and on Windows, 1.7 (see GC).
If memory runs out, the VM collects the garbage and tries again, three times. If that fails, it writes "Fallo en ReallocAlloc Null" on the serial monitor, with the bytes it was asking for, and closes.
Program and file size
The board's flash is split by a partition table that the IDE makes every time it writes to the board. The VM goes in a fixed place, and the file memory (LittleFS), where the program and its resources go, takes from the end of the VM to the end of the flash. The IDE reads the flash size from the board (see Flash the firmware and run).
| Board flash | Files on the ESP32 and the ESP32-S3 | Files on the ESP32-P4 and the ESP32-S31 |
|---|---|---|
| 4 MB | 2,624 KB | 960 KB |
| 8 MB | 6,720 KB | 5,056 KB |
| 16 MB | 14,912 KB | 13,248 KB |
| 32 MB | 31,296 KB | 29,632 KB |
The VM's space is 1,408 KB on the ESP32 and the ESP32-S3, and 3,072 KB on the ESP32-P4 and the ESP32-S31; before it, in the first 64 KB of the flash, go the bootloader, the partition table and two small system partitions (nvs and phy_init). The figures come from JARU IDE's partition templates, in Compiler\ESP32\<chip>\partitions_template.csv.
The file memory holds everything in the project's Build/flash folder: the compiled program, the boot.cfg and the resources (see The file memory).
Check Storage, on the Storage page of ESP32 Tools (LittleFS Storage Check group), tells you whether it fits. It reads the flash size from the board, adds up what is in Build/flash, counting each file in whole 4 KB blocks, and shows it in a bar:
| Message | What it means |
|---|---|
| "OK. Used Space: … KB / Total: … KB (…%)" | It fits. |
| "WARNING: Low storage space…" | It fits, but takes up more than 90%. |
| "ERROR: Capacity exceeded…", with how much is over | It doesn't fit. |
It is an estimate: it doesn't write anything. If the files really don't fit, Run stops at step 1, before writing anything: the Output says "File system is full." and "DEPLOYMENT FAILED: Error during LittleFS build.".
Check Storage reads the board through its port, and doesn't move the serial monitor aside: if it is open on that port, it can't read the board. Close it first with Close Serial.
File paths
On the board, paths are written as in the file memory, not as on Windows:
- With
/, never with\. On Windows both work; on the board, a path likeImages\background.bmpdoesn't find the file. - With the upper and lower case of its name. Windows doesn't tell them apart, and the board's file memory does: if the file is called
Images/Background.bmp,"images/background.bmp"works on Windows and not on the board.
The flash: and sd: units and the open modes, which also change on the board, are in File.
What the board does not have
readLine(). On the board it waits for a line from the serial port, and in 0.9.7 nothing reaches it: the IDE's serial monitor doesn't send what you type. The program keeps waiting forever. It happens to the examples that ask for input, such as CheckPrime, Factorial_ForLoop, FibonacciGenerator and Palindromes. On Windows it works.- Keys. On the board,
Input.maponly accepts GPIO, except on the ESP32-S31, which reads a USB keyboard (see Buttons, pins and gamepad). There is no key to quit: a program with an endless loop never ends. - The window. Window Scale and closing the window to end the program are Windows things.
MQTT.intStatsandMQTT.resetIntStats. They only exist on Windows.- The debugger. Debug always runs on the Windows VM, and Stop doesn't stop a program on the board (see Run on the board).
What only works on the board
These modules talk to the board's hardware. On Windows you can use them, but they don't do the same:
| Module | On Windows |
|---|---|
| GPIO | The pins are those of the GPIO simulator. |
| LED | The strip shows on the WS2812 Strip card of the GPIO simulator. |
| I2C | Writing succeeds, and reading gives 0. |
| Power | Power.sleep() waits the time of Power.wakeOnTimer the first time it sleeps after that call, and 100 ms otherwise; Power.wakeReason() always returns Power.WAKE_TIMER. |
Display.backlight | Does nothing. |
Power.sleep() on the Waveshare 2.8 and the JaruCadeAfter the first Power.sleep(), these boards lose their USB: the serial monitor gets nothing more, and the IDE can't write to them until you start them in download mode (see Supported boards).
All the known issues of JARU, together, are in Known issues.
What looks different from Windows
Colors
| Windows | ESP32 / ESP32-S3 | ESP32-P4 | ESP32-S31 | |
|---|---|---|---|---|
With double buffer (Display.mode(2), the default) | 16.7 million colors (24 bits) | 256 colors (8 bits) | 65,536 colors (16 bits) | 65,536 colors (16 bits) |
On the ESP32 and the ESP32-S3, the double buffer stores each pixel in one byte: 3 bits of red, 3 of green and 2 of blue. There are 8 shades of red, 8 of green and 4 of blue, so:
- two similar colors look the same;
- a gradient looks stepped;
draw.getPixelreturns the color as it ended up in the frame, not the one you asked for.
Images and sprites are loaded with 65,536 colors, but when drawn into the double buffer they also go down to 256. With direct mode, Display.mode(1), drawing uses 65,536 colors, but you see each thing being drawn (see Display). For a game, pick colors that stay distinct with 256.
Text
draw.text doesn't use the same lettering on Windows as on the board:
- On Windows, text always comes out in the same lettering, 13 pixels high, whatever
draw.fontsays. - On the board,
draw.fontpicks one of the screen's fonts:
draw.font | Font on the board |
|---|---|
0, 1 (the default), 3 and 5 | The small one, 6 × 8 pixels |
2 | 16 pixels high |
4 | 26 pixels |
6 | 48 pixels, for clocks |
7 | 48 pixels, seven-segment |
8 | 75 pixels |
With the default one, text on the board is a little over half its size on Windows. If your game places text by eye on Windows, check on the board that it doesn't overlap or spill out: the width of each letter changes too.