How to keep RAM usage low

Description

I’ve been playing around with the examples of the benchmark and demo widgets on a Teensy 4.1 and when I compile and upload the code to the Teensy I can see that program storage comes to around 273kb and RAM usage is around 360kb on the demo widgets example.


On a test sketch I built that includes just one screen, a gauge, an image and some labels with custom fonts the RAM usage jumps to around 672kb, and I only have 512kb available to use.

How do I keep the RAM usage low or under 500kb? I’m baffled as the demo widgets includes so much more objects yet consumes half the amount of the static memory and half the RAM.

What MCU/Processor/Board and compiler are you using?

Teensy 4.1 with 8Mb flash and 512kb RAM

What LVGL version are you using?

7.4.0

What do you want to achieve?

Low or fair level of RAM consumption

Code to reproduce

The main code is attached here. It does not include my custom fonts that were generated at 4bpp ranging from 10,12,14,16,18,20,22,24,26,28,30 and 32 px
gauge_lvgl_demo.zip (138 KB)

Hi @reso ,

Looking at your code very quickly it looks like your gauge background image is probably using the majority of the memory. I am not familiar with the Teensy, but I would suggest looking to see if there is a way of accessing the image from the flash memory directly from the program without having to copy it to the RAM.

Here is a post in the Teensy forum that should give you some ideas hopefully:

https://forum.pjrc.com/threads/62966-issues-on-program-with-large-dataset?highlight=flash+memory+data+storage

I hope that helps,

Kind Regards,

Pete

1 Like

Hi @pete-pjb, thanks for the quick response!

Does LV_IMG_DECLARE(guage_bg_bar); place it into the RAM?

I ask because I’ve used bigger and multiple images on the same Teensy before, by just including them using #include <> and they seem to be put automatically into the flash memory.
I then use my display driver to present them on the screen with a function such as drawRect(x,y,h,w,color) where color is the reference to the image

I can do that here, the question is how do I set LVGL to read them? What method do I use read the image?

Also, I thought I’d also reduce my font files from 4bpp to 2 bpp to try and keep a clean look to it and low memory usage at the same time

Hi @reso ,

LV_IMG_DECLARE just declares the image constant and external so the linker can resolve the symbol at link time as the image is typically in a separate source file.

This is the definition for reference:

#define LV_IMG_DECLARE(var_name) extern const lv_img_dsc_t var_name;

Are you able to get your development tools to generate a map file which you can post for me to take a look at?

Kind Regards,

Pete

Hi @reso,

I’m sorry I was a bit vague in the previous post, I should have said can you generate a map file for a project which compiles okay and contains images.

Kind Regards,

Pete

Hi again @reso ,

If your project contains a .ld linker script file it would also be very useful if you could post that too.

Kind Regards,

Pete

I’ve found the following files:

I think the .elf might be useful if you can convert it to a map file - I tired via the IDE by adding a command but it broke a bunch of other stuff

Hi @reso ,

Sorry my previous post was very wrong I believe, I think you should try this instead:

Line 1305 of gauge_bg_bar.c

// Change
const lv_img_dsc_t guage_bg_bar = {

// to
const PROGMEM lv_img_dsc_t guage_bg_bar = {

And add #include <avr/pgmspace.h> to the top of the file.

Leave the rest of your code as is…

Please can you try that and let me know if it compiles?

Kind Regards,

Pete.

1 Like

@pete-pjb I’ll try that as soon as I get back to my other Mac.
I think your suggestion will work, as the previous image generator I used generated the following, which seems to have placed the image in the flash memory.

Perhaps an option to do so can be added to the image converter on the lvgl website

// Generated by   : ImageConverter 565 Online
// Memory usage   : 231200 bytes

#if defined(__AVR__)
    #include <avr/pgmspace.h>
#elif defined(__PIC32MX__)
    #define PROGMEM
#elif defined(__arm__)
    #define PROGMEM
#endif

const unsigned short test_image[115600] PROGMEM={
...
}
1 Like

I think this can be done with the current converter using LV_ATTRIBUTE_IMG_<image name in uppercase>.

1 Like

I tired your suggestion, and it compiled but with the same memory usage as before.
So I also made this change in line 12:

const PROGMEM LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_GUAGE_BG_BAR uint8_t guage_bg_bar_map[] = {

RAM is down:

Global variables use 385716 bytes (73%) of dynamic memory, leaving 138572 bytes for local variables. Maximum is 524288 bytes.

I think I need to also do the same for the font files to reduce RAM even more, which should be good

Hi @reso,

Are yes that makes sense, glad you are on the right track now, yes I agree moving the fonts should also help.

I believe you can also do the same with any functions you have which are used for initialisation or not performance critical which will help to keep the faster RAM memory clear for important things.

I believe to make a function execute directly from FLASH you would need to declare it like this…

myReturnType PROGMEM MyFunction( MyParameters ) {

     Code for Function....

}

As I don’t have experience with this platform, apologies in advance if any info is not quite correct…

Kind Regards,

Pete

1 Like

@pete-pjb you’ve been super helpful with this, and I think even with your limited knowledge on the Teensy/Arduino platform you still know more than I do ! :smile:

I’ve been able to shave off a few more kilobytes by doing the following in all of my font files:

I’m now down to 60% RAM usage - that’s 13% less than before! and flash is only at 6% usage = 550Kb out of 8 megabytes!

1 Like

Hi @reso,

No worries, that’s great, as I mentioned in my last post you could also make some of your own functions execute directly from FLASH which could save you more RAM also, there is probably a small performance penalty but if you just do it for initialisation functions and functions where the best performance is not required, it should be fine. The Teensy appears to have pretty impressive performance anyway so even more reason to go that route…

Although I’m not familiar with the Teensy, I am familiar with working with resource constrained systems, having worked with micros for over 30 years, back then ‘resource constrained’ was all that existed! :smiley: So I know a few tricks to get the most out of the device…

Kind Regards,

Pete