lvgl / lv_port_esp32

LVGL ported to ESP32 including various display and touchpad drivers
MIT License
1.06k stars 440 forks source link

This project will not build correctly on the ESP32-S2 #252

Closed jockm closed 3 years ago

jockm commented 3 years ago

Description

If you try and compile this project using the ESP32-S2 you get the following error

section `.dram0.bss' will not fit in region `dram0_0_seg'
/Users/jock/.espressif/tools/xtensa-esp32s2-elf/esp-2020r3-8.4.0/xtensa-esp32s2-elf/bin/../lib/gcc/xtensa-esp32s2-elf/8.4.0/../../../../xtensa-esp32s2-elf/bin/ld: region `dram0_0_seg' overflowed by 31296 bytes

The reason for this that the ESP32-S2 has less SRAM than the ESP32 (320MB v 520MB) and a smaller SRAM0 segment.

Out of the box the default max resolution of 480x320, if you use the ILI9341 TFT Controller, the DISP_BUF_SIZE is 480642, os 60K. Because the default is to use double buffering this then allocates a total of 120K an overruns SRAM0.

Proposed Solutions

  1. Document this on the github readme so people using the ESP32-S2 can at least know what they need to do
  2. use malloc() to allocate the buffers so they will be fit into a ram segment where they can fit
  3. use an attribute to indicate where the buffers should be allocated ala #define DRAM_ATTR _SECTION_ATTR_IMPL(".dram1", __COUNTER__) for SRAM1
  4. Allocate in PSRAM (if present), at which point you could have a larger buffer if you wanted

This is a frustrating and yet easily solved issue Regardles

davidjade commented 3 years ago

Some of these options may not be valid as the buffer needs to be in DMA capable memory. That rules out PSRAM, regular malloc(), etc... SRAM is the only place that can be used for DMA buffers and transaction descriptors. The only realistic option may be to just use smaller buffers that fit in available SRAM.

jockm commented 3 years ago

@davidjade OK fair, but the size of the buffers is pre calculated based on the horizontal size in the config files, the code either needs to be modified to come up with sizes that will work with the -S2, or documented to ignore the example given.

And fine you can't use regular clib malloc, but one could use pvPortMallocCaps() which would still be called "malloc". My point still stands on that one ;)

Regardless of the solution, the fact that this code was apparently never tested against the -S2 is a bit sad. It's been available for the better part of a year now

davidjade commented 3 years ago

If you look at the ESP docs for DMA, it states that heap_caps_malloc(size, MALLOC_CAP_DMA) must be used for DMA buffers and that flag is going to force it right back into the SRAM heap.

I suspect it will be necessary to reduce the buffer size for SRAM constraint devices. I personally don't have an S2 device so I cannot test this.

embeddedt commented 3 years ago

Regardless of the solution, the fact that this code was apparently never tested against the -S2 is a bit sad. It's been available for the better part of a year now

Please keep in mind that many of us are hobbyists doing this in our free time, and we don't necessarily have access to the latest hardware immediately. We of course appreciate reports like this and will do our best to resolve the issue.

jockm commented 3 years ago

@embeddedt I am, but I am also cognizant that there is a company that is offering services and support. That raises the bar of what I expect a little. The -S2 was announced in 2019, boards were available in march of 2020. So no, I don't expect people to jump as soon as a new board is out, but after about 6-10 months or so I do kinda expect that someone to take the 5-10 minutes to idf.py set-target esp32s2 && idf.py build and see if it actually compiles

embeddedt commented 3 years ago

@jockm Fair enough; that's a reasonable point.

jockm commented 3 years ago

@davidjade I think the larger point is that in the time we have quibbled over DMA and various forms of malloc, y’all could have closed this bug simply by documenting that the example does on work on the -S2 as is. It was one of the courses of action I suggested

However right now anyone who has a -S2 and wants a GUI aid going to be frustrated and possibly baffled by the error. They are more likely to simply have a bad opinion about lvgl than anything else

jockm commented 3 years ago

@davidjade I have read the docs — I had to dig into them deeply to fully understand the nature of this problem before I reported it. I will refer you to the documentation, you will find this note:

Due to a technical limitation, the maximum statically allocated DRAM usage is 160KB. The remaining 160KB (for a total of 320KB of DRAM) can only be allocated at runtime as heap.

If you dig further you will find that the statically allocated DRAM area is actually about 114K* before the LVGL example gets to allocate anything. This almost explains the amount of the overrun, but if you do some form of malloc it will be allocated in the other 160K block. Which is why I suggested that as an option.

Now I agree that lowering the size of the buffers may still be called for (depending on how much storage is needed by the rest of the app) as ~38% of SRAM is a lot to consume just for buffers.

If I choose to use LVGL on this project I would probably be writing my own drivers as the included ones do not include the 8/16 bit parallel mode the CPU has support for, and might need the slightly slower but heap freeing option of putting the buffer in PSRAM.

*: This isn't documented, but what I have been able to observe

jockm commented 3 years ago

I am just going to put this here for the morbidly curious, but I have filed a related issue (#255) noting that the default buffer size for the ILI9341 (the default as shipped) defines a DISP_BUF_SIZE that is 1.6x the default for other displays. If it were set to 40 like the others were, then the -S2 wouldn't overrun the static area. This would leave about 14K left for for other static storage.

tore-espressif commented 3 years ago

Hello @jockm,

I can see that some damage has been already done by not having this example updated to 'new' HW. Nevertheless, you got the solution right with allocation the buffers in DMA-capable heap, see #259 .

I'd also like to shed some light onto some of the topics that you mentioned in this thread:

  1. It is true that DMA does not have access to external RAM. But the SPI driver won't crash if you pass it pointer to external memory. The SPI driver would copy its content to internal memory and start the transaction -> this is extremely inefficient in terms of CPU time and memory (see here) so I don't recommend you doing it this way, it is just an FYI.
  2. At the time of writing this comment, only dynamic allocation to external RAM is supported; static allocation (.bss segment) is not supported in ESP32-S2. You can watch this issue for details.
  3. ESP32-S2 enhaces its peripherals (SPI and I2S) with serial and parallel LCD interface, but their drivers are work in progress in ESP-IDF. Of course, you can use the feature, we just don't provide IDF-like drivers yet. For detail refer to ESP32-S2 technical reference manual chapters 8.4.6, 8.4.8 and 9.10.

At this point at must add, that I always assume that you have PSRAM available, although it is not present on all ESP32-S2 modules/SoC, see ordering information chapter 2.

I didn't check this solution on a system without PSRAM.

C47D commented 3 years ago

Thanks for the request @tore-espressif , can you validate it works for you @jockm ?

@tore-espressif I've seen you're improvements into this and the drivers repo, thanks for the help 😃