I’ve been working on embedding Micropython into the firmware for the new version of Marty the Robot V2 and, since the robot already has Bluetooth (BLE) and WiFi capabilities (or at least it will have WiFi soon), there is a bit of a cram going on getting everything working in a standard ESP32 WROOM chip.
WROOM editions and limitations
The basic WROOM comes in a number of flavours and the main differences are the amount of Flash onboard (4, 8 or 16MB) and whether the module has an external antenna.
The version we’re currently using at Robotical is the 4MB option and there isn’t really too much of a problem with Flash space at present – the layout we have includes a 1.7MB area for OTA (doubled up), around 500MB of file-system and a small amount of other non-volatile storage.
The problem is RAM.
What is a WROVER
The WROVER is essentially identical to a WROOM but with external memory called SPIRAM (because it is accessed over a high-speed serial bus called SPI). The amount of available SPIRAM is (directly) 4MB but there are some gotchas to be aware of:
- more cache RAM should be used so that external Flash and SPIRAM are not using the same cache
- there was a bug in some versions of WROVER which could be worked around but the work-around required IRAM (which is in short supply).\
ESP32 Memory Architecture
My initial thoughts about the memory availability on the ESP32 was that the advertised 520KB ought to be ample for many things. But the reality is that all of this space isn’t really available for program variables as you might expect. The ESP32’s Flash (and external SPIRAM) are not actually accessed directly but via a SPI (high-speed serial) bus and execution of code from Flash involves a cache which has to be in the RAM as well.
Furthermore, the cache mentioned above won’t necessarily have code in it that is required to service interrupts so another block of RAM is needed to contain that code.
In the current RIC firmware we don’t have WiFi or Micropython (only BLE using the NimBLE library – which is much more space efficient than the alternative) the available RAM looks a bit like this:
DRAM .data size: 15812 bytes DRAM .bss size: 29424 bytes Used static DRAM: 45236 bytes ( 79344 available, 36.3% used) Used static IRAM: 115585 bytes ( 15487 available, 88.2% used) Flash code: 784007 bytes Flash rodata: 169248 bytes Total image size:~1084652 bytes (.bin may be padded larger)
Initial reported heap size in this scenario is:
Introducing Micropython to the Equation
Once Micropython is added in the RAM situation becomes more dire:
Total sizes: DRAM .data size: 16168 bytes DRAM .bss size: 28952 bytes Used static DRAM: 45120 bytes ( 79460 available, 36.2% used) Used static IRAM: 123765 bytes ( 7307 available, 94.4% used) Flash code: 942736 bytes Flash rodata: 214932 bytes Total image size:~1297601 bytes (.bin may be padded larger)
Micropython runs in a FreeRTOS task of its own with a 16K stack and 32K given to python heap.
The remaining C/C++ heap is now:
This seems sufficient for stable running of the firmware and the low-water-mark of the heap seems to be around 60K under stress tests.
Adding WiFi Support
Total sizes: DRAM .data size: 16720 bytes DRAM .bss size: 34032 bytes Used static DRAM: 50752 bytes ( 73828 available, 40.7% used) Used static IRAM: 125409 bytes ( 5663 available, 95.7% used) Flash code: 1207629 bytes Flash rodata: 256292 bytes Total image size:~1606050 bytes (.bin may be padded larger)
In this final scenario the available heap space when first run is only:
Unfortunately this isn’t enough free heap to handle all functions of the firmware. The WiFi stack includes a web-server and opening more than one page concurrently causes the heap to be exhausted.
Testing with a WROVER
Since the circuit boards for RIC were designed without considering an upgrade to a larger module some mods are needed to try a WROVER with existing hardware. Fortunately the pinouts of the WROOM and WROVER are somewhat compatible:
Removing the WROOM
Removal of the WROOM demanded desoldering and this wasn’t trivial due to the presence of “pins” on three sides of the module. However the combination of a Voltera One and a hot-air rework station finally did the trick:
There are a number of different WROVER modules but the most important thing for me was to make sure it was an ECO-C chip which has a fix for a bug in the caching of SPIRAM. Without this fix a lot more IRAM is required to use SPIRAM and that wouldn’t fit given that we are around 96% of IRAM used already.
Because there was a risk of shorting – though only on the NC pins which shouln’t have mattered, I added some kapton tape:
Soldering the WROVER in place
Since some of the pins on the end of the WROOM footprint are used in the RIC design I needed to attach wires before soldering the WROVER in place.
I’ll need to do some more testing but first impressions are that the WROVER behaves exactly the same as the WROOM as we aren’t (yet) using any of the WROVER’s additional capabilities and the two pins that are unavailable on the WROVER (16 and 17) are spare in the current RIC design.
More testing is needed though!