LIFsCode / ELOC-3.0

Firmware for ELOC 3.0 Hardware
MIT License
3 stars 3 forks source link

Activate PSRAM #16

Closed LIFsCode closed 12 months ago

LIFsCode commented 1 year ago

We are using the ESP32-WROVER-IE-N16R8 which has 8MB PSRAM. But in order to use it it needs to be activated because the "standard" ESP32 does not have this PSRAM.

EDsteve commented 1 year ago

Notes i got from Fabi to make use of the PSRAM:

A freelancer will hopefully make that work soon.

OOHehir commented 1 year ago

Just started looking, will add some notes here.

Interesting although the WROVER module has 8MB RAM on the SPI bus the manual states:

External SRAM can be mapped into CPU data memory space. Up to 4 MB can be mapped at a time. 8-bit, 16-bit and 32-bit reads and writes are supported. ESP32-WROVER-E and ESP32-WROVER-IE integrate a 4 MB SPI flash and an 8 MB PSRAM for more memory space.

Looks like it complicates things a bit, I'm not sure how this mapping is handled (i.e. by the application or automatically).

Link to Espressif documentation of feature.

Using ArduinoJSON with this external RAM

https://www.upesy.com/blogs/tutorials/get-more-ram-on-esp32-with-psram

OOHehir commented 1 year ago

So there seems to be 4 ways of sing external (SPI) RAM as detailed here:

  1. Integrate RAM into the ESP32 Memory Map Probably don't want this, have to manually handle allocation & de-allocation
  2. Add External RAM to the Capability Allocator Application specifically calls 'special' malloc to store to external RAM using heap_caps_malloc. Could be useful for allocating the (large/ very large) TensorFlow array.
  3. Provide External RAM via malloc() Application calls malloc in regular way. The build can be configured to try & allocate memory requests over a certain size to external RAM.
  4. Allow .bss Segment to Be Placed in External Memory Not particularly useful?
  5. Allow .noinit Segment to Be Placed in External Memory Not particularly useful?

So I would suggest 2 or 3 seems to be the better options. Any thoughts @LIFsCode @EDsteve

LIFsCode commented 1 year ago

I aggree with you, Option 2&3are the best for our purpose. We do not have any large segments of bss or noinit data, unless the AI part is using it, but as far as I understood it, this is all dynamically allocated. Hence I would actually use option 2 so you have control in the code where it's allocated.

OOHehir commented 1 year ago

@LIFsCode Ok, Will plan on implementing option 2

OOHehir commented 1 year ago

Its enabled now via the menuconfig:

Component Config> ESP32-specific > Support for external, SPI-connected RAM

&

SPI RAM config --> SPI RAM access method (Make RAM allocatable using heap_caps_malloc(..., MALLOC_CAP_SPIRAM)) ----> Make RAM allocatable using heap_caps_malloc(..., MALLOC_CAP_SPIRAM)

EDsteve commented 1 year ago

Great. That was easier than expected :) Noob question: Does that mean our RAM problems are gone now or the code has to be still adjusted?

OOHehir commented 1 year ago

I should have the WROVER tomorrow & Thurs so can test then but hopefully!

On Tue 25 Jul 2023, 16:59 EDsteve, @.***> wrote:

Great. That was easier than expected :) Noob question: Does that mean our RAM problems are gone now or the code has to be still adjusted?

— Reply to this email directly, view it on GitHub https://github.com/LIFsCode/ELOC-3.0/issues/16#issuecomment-1650112993, or unsubscribe https://github.com/notifications/unsubscribe-auth/AJSSOW444WTC2NF4EJYUXH3XR7UOZANCNFSM6AAAAAAYWUPRGU . You are receiving this because you commented.Message ID: <LIFsCode/ELOC-3. @.***>

OOHehir commented 1 year ago

Well of course it's never really that easy!

As soon as I enabled the options I started getting build errors:

/.platformio/packages/toolchain-xtensa-esp32/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld: .pio/build/esp32dev/firmware.elf section `.iram0.text' will not fit in region `iram0_0_seg'
/.platformio/packages/toolchain-xtensa-esp32/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld: IRAM0 segment data does not fit.
/.platformio/packages/toolchain-xtensa-esp32/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld: region `iram0_0_seg' overflowed by 8876 bytes

It seems a little counter-intuitive that adding external RAM causes data not to fit but the reason lies in silicon bug workarounds introduced by Espressif:

Aside from linking to a recompiled version of Newlib with the additional flag, ESP-IDF also does the following: Avoids using some ROM functions Allocates static memory for the Wi-Fi stack

So these 'workarounds' actually increase code size. They are present until Rev 3.0 at which point they state:

_ESP32 rev v3.0 fixes the PSRAM cache issue found in rev v1.0. When CONFIG_ESP32_REV_MIN option is set to rev v3.0, compiler workarounds related to PSRAM will be disabled._

So by running Menuconfig & selecting:

(Top) → Component config → ESP32-specific → Minimum Supported ESP32 Revision -> Rev 3

The build completes successfully.

I checked the chip I have in the WROVER using

esptool flash_id

& got:

Detecting chip type... ESP32
Chip is ESP32D0WDQ5 (revision 3)

I assume previous versions have been out of circulation for a while but might be worth checking yours when you get a chance..

Hopefully this completes/ closes this issue

EDsteve commented 1 year ago

Well of course it's never really that easy! Where would be the challenge if it would be? Haha. Hope it didn't took too long for you to find the solution. I just checked and our board also uses Rev 3. So I am super happy to hear that you got the PSRAM working. Well done :)

OOHehir commented 1 year ago

Not too long thankfully!

As a quick check I added the line to main.cpp:

ESP_LOGI(TAG, "Free memory: %d bytes", esp_get_free_heap_size());

Without the options above enabled it returns:

main: Free memory: 211640 bytes

With the options enabled it returns:

main: Free memory: 4403587 bytes

Difference is 4191947, which divided by 1048576 (bytes per MB) returns 3.99. Although 8MB is present on the board as noted above its limited to 4MB at a time.

OOHehir commented 1 year ago

Not particularly interesting but I thought it's worth documenting in case it comes up in future..

I thought it would simply be a matter of adding these to platform.ini:

build_flags =
    -DBOARD_HAS_PSRAM
    -DCONFIG_SPIRAM_CACHE_WORKAROUND

But no, when enabling SPI RAM via menuconfig a host of options are changed:

#
# SPI RAM config
#
CONFIG_SPIRAM_TYPE_AUTO=y
# CONFIG_SPIRAM_TYPE_ESPPSRAM16 is not set
# CONFIG_SPIRAM_TYPE_ESPPSRAM32 is not set
# CONFIG_SPIRAM_TYPE_ESPPSRAM64 is not set
CONFIG_SPIRAM_SIZE=-1
CONFIG_SPIRAM_SPEED_40M=y
CONFIG_SPIRAM=y
CONFIG_SPIRAM_BOOT_INIT=y
# CONFIG_SPIRAM_IGNORE_NOTFOUND is not set
# CONFIG_SPIRAM_USE_MEMMAP is not set
CONFIG_SPIRAM_USE_CAPS_ALLOC=y
# CONFIG_SPIRAM_USE_MALLOC is not set
CONFIG_SPIRAM_MEMTEST=y
# CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP is not set
# CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY is not set
# CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY is not set
CONFIG_SPIRAM_CACHE_WORKAROUND=y

#
# SPIRAM cache workaround debugging
#
CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_MEMW=y
# CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_DUPLDST is not set
# CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_NOPS is not set
# end of SPIRAM cache workaround debugging

By default this also sets these options:

#
# SPIRAM workaround libraries placement
#
CONFIG_SPIRAM_CACHE_LIBJMP_IN_IRAM=y
CONFIG_SPIRAM_CACHE_LIBMATH_IN_IRAM=y
CONFIG_SPIRAM_CACHE_LIBNUMPARSER_IN_IRAM=y
CONFIG_SPIRAM_CACHE_LIBIO_IN_IRAM=y
CONFIG_SPIRAM_CACHE_LIBTIME_IN_IRAM=y
CONFIG_SPIRAM_CACHE_LIBCHAR_IN_IRAM=y
CONFIG_SPIRAM_CACHE_LIBMEM_IN_IRAM=y
CONFIG_SPIRAM_CACHE_LIBSTR_IN_IRAM=y
CONFIG_SPIRAM_CACHE_LIBRAND_IN_IRAM=y
CONFIG_SPIRAM_CACHE_LIBENV_IN_IRAM=y
CONFIG_SPIRAM_CACHE_LIBFILE_IN_IRAM=y
CONFIG_SPIRAM_CACHE_LIBMISC_IN_IRAM=y
# end of SPIRAM workaround libraries placement

Which causes the error:

...firmware.elf section `.iram0.text' will not fit in region `iram0_0_seg'

The solution is to modify menuconfig:

Component config → ESP32-specific → Support for external, SPI-connected RAM → SPI RAM config → SPIRAM workaround libraries placement

& deselect all.

OOHehir commented 12 months ago

I'll mark this closed as it appears to be functioning correctly in the ai branch, about to be merged to master.