enabling 8 mb psram within micropython 1.19.1 on an esp32-s3 development board

I’ve managed to build MicroPython 1.19.1 with ESP-IDF v4.3.3 with PSRAM enabled. The screen capture above shows the free memory (the free heap, actually) in megabytes. The ESP32-S3-DevKitC-1-N8R8 has 8 MB of flash and 8 MB of external PSRAM, of which only half of that is shown. That’s because MicroPython only shows half of it in its environment. The build date is back on 16 December. The IDF version is 4.4.3, which is the last major version before 5.0 was released. I’m glad I was able to achieve this with 4.4.3 as there’s going to have to be some major changes to MicroPython 1.19.1 because of breaking changes to ESP-IDF 5.0.

The file to edit is micropython/ports/esp32/ boards/GENERIC_S3_SPIRAM/sdkconfig.board, which is listed below. The lines I added are highlighted in green and start at line 14. I found those lines by using idf.py menuconfig with one of my other ESP-IDF projects and enabling SPIRAM/PSRAM on a specific ESP32-S3 development board. That development board has 8 MB FLASH and 8 MB PSRAM. I then opened an editor with the configuration file modified by idf.py and a second window with the same configuration file in the MicroPython port board and copied from the modified configuration to the port board configuration file. Once the copy was finished the changes were saved and I moved to micropython/ports/esp32 and executed make BOARD=GENERIC_S3_SPIRAM, then flashed the development board with the product of make. After that I used idf.py -p /dev/ttyUSB0 monitor (because that’s the port my ESP32-S3 development board was connected to) and I was able to run the REPL without issue. I was also able to develop on the board with Thonny, again without any issue.

I’m so satisfied to have found this because every other explanation for how to make this work I found via searches did not work, or worked with a very old beta of ESP-IDF and involved too many file changes. This change only required modification of one file, and then a make.

CONFIG_FLASHMODE_QIO=yCONFIG_ESPTOOLPY_FLASHFREQ_80M=yCONFIG_ESPTOOLPY_FLASHSIZE_DETECT=yCONFIG_ESPTOOLPY_AFTER_NORESET=yCONFIG_SPIRAM_MEMTEST=CONFIG_ESPTOOLPY_FLASHSIZE_4MB=CONFIG_ESPTOOLPY_FLASHSIZE_8MB=yCONFIG_ESPTOOLPY_FLASHSIZE_16MB=CONFIG_PARTITION_TABLE_CUSTOM=yCONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-8MiB.csv"## START OF ADDED CONFIGURATIONS FOR PSRAM ENABLEMENT#CONFIG_SOC_PSRAM_DMA_CAPABLE=yCONFIG_SOC_GDMA_SUPPORT_PSRAM=yCONFIG_SOC_GDMA_PSRAM_MIN_ALIGN=16## ESP PSRAM#CONFIG_SPIRAM=y## SPI RAM config## CONFIG_SPIRAM_MODE_QUAD is not setCONFIG_SPIRAM_MODE_OCT=yCONFIG_SPIRAM_TYPE_AUTO=y# CONFIG_SPIRAM_TYPE_ESPPSRAM64 is not setCONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY=y## PSRAM Clock and CS IO for ESP32S3#CONFIG_DEFAULT_PSRAM_CLK_IO=30CONFIG_DEFAULT_PSRAM_CS_IO=26# end of PSRAM Clock and CS IO for ESP32S3# CONFIG_SPIRAM_FETCH_INSTRUCTIONS is not set# CONFIG_SPIRAM_RODATA is not set# CONFIG_SPIRAM_SPEED_80M is not setCONFIG_SPIRAM_SPEED_40M=yCONFIG_SPIRAM_SPEED=40CONFIG_SPIRAM_BOOT_INIT=y# CONFIG_SPIRAM_IGNORE_NOTFOUND is not set# CONFIG_SPIRAM_USE_MEMMAP is not set# CONFIG_SPIRAM_USE_CAPS_ALLOC is not setCONFIG_SPIRAM_USE_MALLOC=yCONFIG_SPIRAM_MEMTEST=yCONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=16384# CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP is not setCONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=32768# CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY is not set# CONFIG_SPIRAM_ECC_ENABLE is not set# end of SPI RAM config# end of ESP PSRAM

additional esp32 work and github repo checkin

Two broad items this post.

The first is that I’ve moved all my Espressif project work to my GitHub account here: https://github.com/wbeebe/EspressifProjects . The projects are broken into ESP-IDF V4.x projects, and ESP-IDF V5.x projects. The older version is for those who want to see what I’ve done and who are still working with some version of V4.x. I know those tool chains are still being developed because ESP-IDF v4.1.4 was released two days ago, on 12 December. But all of my work going forward will be with version 5.

The second is a test application I wrote using ESP-IDF v5.0 with the ESP32-S3-DevKitC-1-N32R8V, which is a development board with 32 MB of FLASH and 8 MB of PSRAM. I’ve already successfully enabled the PSRAM and it appears, from my very limited testing, to work. However, I tried to enable the entire 32 MB of FLASH and the ESP-IDF framework will only allow up to 16MB of FLASH to be enabled. What follows is the code followed by a sample run. Note that this code is also checked into my GitHub repo.

#include <array>#include <cinttypes>#include <string>#include "freertos/FreeRTOS.h"#include "freertos/task.h"#include "driver/gpio.h"#include "esp_log.h"#include "led_strip.h"#include "sdkconfig.h"#include "esp_chip_info.h"#include "esp_system.h"static const char *TAG = "ESP32-S3-DevKitC-1.1-N32R8";#define stringify( _name ) #_namestatic const char* translate_esp_chip_model(esp_chip_model_t model){switch(model) {case CHIP_ESP32:   return stringify(CHIP_ESP32);case CHIP_ESP32S2: return stringify(CHIP_ESP32S2);case CHIP_ESP32S3: return stringify(CHIP_ESP32S3);case CHIP_ESP32C3: return stringify(CHIP_ESP32C3);case CHIP_ESP32H2: return stringify(CHIP_ESP32H2);case CHIP_ESP32C2: return stringify(CHIP_ESP32C2);//case CHIP_ESP32C6: return stringify(CHIP_ESP32C6);}return "CHIP_UNKNOWN";}using std::string;static void decode_features(uint32_t features, string &results) {if (features == 0) {results = "NO_FEATURES";return;}if (features & CHIP_FEATURE_EMB_FLASH) results += "FLASH ";if (features & CHIP_FEATURE_WIFI_BGN) results += "WIFI ";if (features & CHIP_FEATURE_BLE) results += "BLE ";if (features & CHIP_FEATURE_BT) results += "BT ";if (features & CHIP_FEATURE_IEEE802154) results += "IEEE802154 ";if (features & CHIP_FEATURE_EMB_PSRAM) results += "PSRAM";}// Create an array of color arrays to cycle through continuously.//using std::array;const array<array<int, 3>, 7> colors {{{32,0,0},  // red{0,32,0},  // green{0,0,32},  // blue{0,32,32}, // cyan{32,0,32}, // magenta{32,16,0}, // yellow{0,0,0}// black}};static led_strip_handle_t led_strip;static void initialize_neo_pixel() {led_strip_config_t strip_config = {.strip_gpio_num = CONFIG_BLINK_GPIO,.max_leds = 1, // at least one LED on board};led_strip_rmt_config_t rmt_config = {.resolution_hz = 10000000, // 10 MHz};ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &led_strip));// Darken NeoPixel by setting individual LED values to 0//led_strip_clear(led_strip);}static void blink_neo_pixel() {for(auto color : colors) {led_strip_set_pixel(led_strip, 0, color[0], color[1], color[2]);led_strip_refresh(led_strip);vTaskDelay(800 / portTICK_PERIOD_MS);led_strip_clear(led_strip);vTaskDelay(200 / portTICK_PERIOD_MS);}}extern "C" void app_main(void) {esp_chip_info_t chip_info;esp_chip_info(&chip_info);string features;decode_features(chip_info.features, features);ESP_LOGI(TAG, "BEGIN");ESP_LOGI(TAG, "ESP-IDF VERSION %s", esp_get_idf_version());ESP_LOGI(TAG, "CHIP MODEL %s", translate_esp_chip_model(chip_info.model));ESP_LOGI(TAG, "CHIP FEATURES %s", features.c_str());ESP_LOGI(TAG, "REVISION %X", chip_info.revision);ESP_LOGI(TAG, "FREE HEAP %" PRIu32, esp_get_free_heap_size());ESP_LOGI(TAG, "INITIALIZE NEOPIXEL");initialize_neo_pixel();ESP_LOGI(TAG, "ENTER MAIN LOOP");while (true) {blink_neo_pixel();}}

And here is a sample run.

ESP-ROM:esp32s3-20210327Build:Mar 27 2021rst:0x1 (POWERON),boot:0x18 (SPI_FAST_FLASH_BOOT)SPIWP:0xeeOctal Flash Mode EnabledFor OPI Flash, Use Default Flash Boot Modemode:SLOW_RD, clock div:1load:0x3fce3810,len:0x167cload:0x403c9700,len:0xbe8load:0x403cc700,len:0x2e98entry 0x403c9904I (32) boot: ESP-IDF v5.0 2nd stage bootloaderI (32) boot: compile time 08:19:25I (32) boot: chip revision: v0.1I (34) boot_comm: chip revision: 1, min. bootloader chip revision: 0I (41) boot.esp32s3: Boot SPI Speed : 80MHzI (46) boot.esp32s3: SPI Mode   : SLOW READI (51) boot.esp32s3: SPI Flash Size : 16MBI (56) boot: Enabling RNG early entropy source...I (61) boot: Partition Table:I (65) boot: ## LabelUsage  Type ST Offset   LengthI (72) boot:  0 nvs  WiFi data01 02 00009000 00006000I (80) boot:  1 phy_init RF data  01 01 0000f000 00001000I (87) boot:  2 factory  factory app  00 00 00010000 00100000I (95) boot: End of partition tableI (99) boot_comm: chip revision: 1, min. application chip revision: 0I (106) esp_image: segment 0: paddr=00010020 vaddr=3c020020 size=0d30ch ( 54028) mapI (127) esp_image: segment 1: paddr=0001d334 vaddr=3fc92f00 size=02ce4h ( 11492) loadI (130) esp_image: segment 2: paddr=00020020 vaddr=42000020 size=1e860h (125024) mapI (162) esp_image: segment 3: paddr=0003e888 vaddr=3fc95be4 size=004f0h (  1264) loadI (163) esp_image: segment 4: paddr=0003ed80 vaddr=40374000 size=0ee10h ( 60944) loadI (185) esp_image: segment 5: paddr=0004db98 vaddr=50000000 size=00010h (16) loadI (191) boot: Loaded app from partition at offset 0x10000I (191) boot: Disabling RNG early entropy source...I (205) octal_psram: vendor id: 0x0d (AP)I (205) octal_psram: dev id   : 0x02 (generation 3)I (205) octal_psram: density  : 0x03 (64 Mbit)I (210) octal_psram: good-die : 0x01 (Pass)I (215) octal_psram: Latency  : 0x01 (Fixed)I (221) octal_psram: VCC  : 0x00 (1.8V)I (226) octal_psram: SRF  : 0x01 (Fast Refresh)I (232) octal_psram: BurstType: 0x01 (Hybrid Wrap)I (238) octal_psram: BurstLen : 0x01 (32 Byte)I (243) octal_psram: Readlatency  : 0x02 (10 cycles@Fixed)I (249) octal_psram: DriveStrength: 0x00 (1/1)I (254) esp_psram: Found 8MB PSRAM deviceI (259) esp_psram: Speed: 40MHzI (263) cpu_start: Pro cpu up.I (267) cpu_start: Starting app cpu, entry point is 0x403754480x40375448: call_start_cpu1 at /home/mint/Develop/esp/esp-idf-v5.0/components/esp_system/port/cpu_start.c:142I (0) cpu_start: App cpu up.I (1004) esp_psram: SPI SRAM memory test OKI (1014) cpu_start: Pro cpu start user codeI (1014) cpu_start: cpu freq: 240000000 HzI (1014) cpu_start: Application information:I (1018) cpu_start: Project name: esp32-s3-r8n32I (1023) cpu_start: App version:  1I (1028) cpu_start: Compile time: Dec 14 2022 08:19:15I (1034) cpu_start: ELF file SHA256:  52102a3bd7bc4632...I (1040) cpu_start: ESP-IDF:  v5.0I (1045) heap_init: Initializing. RAM available for dynamic allocation:I (1052) heap_init: At 3FC96B90 len 00052B80 (330 KiB): D/IRAMI (1059) heap_init: At 3FCE9710 len 00005724 (21 KiB): STACK/DRAMI (1065) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAMI (1072) heap_init: At 600FE010 len 00001FF0 (7 KiB): RTCRAMI (1078) esp_psram: Adding pool of 8192K of PSRAM memory to heap allocatorI (1087) spi_flash: detected chip: mxicW (1090) spi_flash: Detected flash size > 16 MB, but access beyond 16 MB is not supported for this flash model yet.I (1101) spi_flash: flash io: dioW (1105) spi_flash: Detected size(32768k) larger than the size in the binary image header(16384k). Using the size in the binary image header.I (1120) cpu_start: Starting scheduler on PRO CPU.I (0) cpu_start: Starting scheduler on APP CPU.I (1139) esp_psram: Reserving pool of 32K of internal memory for DMA/internal allocationsI (1139) ESP32-S3-DevKitC-1.1-N32R8: BEGINI (1149) ESP32-S3-DevKitC-1.1-N32R8: ESP-IDF VERSION v5.0I (1149) ESP32-S3-DevKitC-1.1-N32R8: CHIP MODEL CHIP_ESP32S3I (1159) ESP32-S3-DevKitC-1.1-N32R8: CHIP FEATURES WIFI BLE I (1169) ESP32-S3-DevKitC-1.1-N32R8: REVISION 1I (1169) ESP32-S3-DevKitC-1.1-N32R8: FREE HEAP 8726608I (1179) ESP32-S3-DevKitC-1.1-N32R8: INITIALIZE NEOPIXELI (1189) gpio: GPIO[38]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0 I (1189) ESP32-S3-DevKitC-1.1-N32R8: ENTER MAIN LOOP

The biggest line to point out in this run is line 69. Even though the ESP32-S3 devkit has 32 MB of FLASH, the latest ESP-IDF tool chain, v5.0, will not enable all 32 MB of FLASH, only 16 MB, or half of it. I would swear that I thought I read that version 5 would allow the full 32 MB of FLASH, but I guess I misread that somewhere. At least I have 16 MB and I have all 8 MB of the PSRAM. What I’m working on now is an application that can take full advantage of both FLASH and PSRAM maximum amounts.

It’s heading into Christmas and I have a lot of family things to do, so this may be one of my last posts for 2022.