Platform Integration: Memory Footprint

In almost every embedded system, the available data memory (e.g. SRAM, SDRAM, PSRAM, HyperRAM, ...) and the available flash memory (e.g. ROM, QSPI flash, OctoSPI flash, ...) are limited system resources and they have to be managed carefully. This article helps to estimate the overall memory footprint and gives you some guidelines to optimize and to reduce the memory footprint.

Embedded Wizard GUI applications can be used in a wide range of systems or environments, e.g. as Javascript application in a browser, as executable on a microprocessor (MPU) with Embedded Linux or as part of a binary on a microcontroller (MCU). Even though Embedded Wizard is a complex and powerful GUI solution, it is designed for the needs of all embedded systems and can be configured to fulfill the requirements of low-end MCUs with hard memory constraints. Due to the fact that the overall memory consumption depends mostly on your GUI application, on your target system and on the system configuration, it is always difficult to provide absolute numbers in terms of kilobytes. Nevertheless, the complete memory footprint can be analyzed and optimized.

Flash Memory (ROM) usage

Usually, the flash memory is used for the entire code and all constant data. Beside the GUI application itself, there are a lot of other software components in a real system requiring flash memory: operating system, standard libraries, device drivers, BSP and finally, your entire software stack (business logic, middleware, ...).

In order to run an Embedded Wizard generated GUI application, the Runtime Environment and the Graphics Engine are needed. These are provided as libraries (for customers using the 'Small Business' edition or for users working with the 'Free' edition) or as source code (for customers using the 'Professional' edition). In case you have the source code available, the Graphics Engine can be configured by a couple of macros to optimize the flash (ROM) usage.

The following list contains all items of a GUI application that have to be located within the flash memory:

Classes - the implementation (the logic) of your GUI application. Only those classes of your project are generated (and require flash memory) that are used within your GUI application.

Constants - all constant members of your project.

Strings - all the converted contents of all string constant members and string literals found in your project. The flash consumption for strings can be controlled with the attribute FormatOfStringConstants within the Profile of your GUI application.

Autoobjects - the initialization for all Autoobject members (global objects) of your GUI project.

Bitmap Resources - all bitmap resource members of your project together with the converted pixel data. The flash consumption for bitmap resources can be controlled with the attribute FormatOfBitmapResources within the Profile of your GUI application.

Font Resources - all font resource members of your GUI project together with the converted glyph pixel data and metrics. Fonts are usually stored compressed within the flash memory and loaded dynamically during runtime into the RAM.

Data Memory (RAM) usage

The situation with data memory (RAM) consumption is similar to the flash consumption: Beside the GUI application itself, a lot of other software components are using data memory for static / global variables, or they are allocating data memory dynamically by a memory manager during runtime. This depends completely on the software components that you are using.

Additionally, the stack has to be located within the data memory. The recommended stack size for Embedded Wizard GUI applications is 4...8 kilobyte.

Within an Embedded Wizard GUI application, the following items are allocating data memory (RAM):

Chora objects - memory for all dynamically created Chora objects.

Signals and observers - memory needed to store signals and observers.

Strings - memory for dynamically created strings or for constant strings that are stored compressed within the flash memory. In case that string constants are stored uncompressed within the flash memory, there is no need to load them into the data memory during runtime.

Glyph cache - all glyphs that are required to draw text are loaded from the font resource into the glyph cache. The size of the glpyh cache can be configured.

Bitmap resources - memory for the bitmap resource that are stored compressed within the flash memory and that are loaded into data memory for drawing operations. In case that bitmap resources are stored uncompressed within the flash memory, there is no need to load them into the data memory during runtime.

Off-screen buffers - memory for buffered GUI components.

Interal - memory for path-data, text rendering and data structures to process all drawing instructions.

Optional: Off-screen framebuffer - memory used as a separate off-screen buffer (e.g. composition buffer used on Linux systems).

Beside of static variables, all the memory that is required for the Embedded Wizard GUI application is allocated dynamically by a memory manager.

Finally, data memory (RAM) is used for the framebuffer. Depending on the framebuffer concept that is used on the target system, memory is necessary for one or two framebuffers.

The necessary memory size in bytes for one framebuffer can be calculated by: FRAME_BUFFER_WIDTH * FRAME_BUFFER_HEIGHT * FRAME_BUFFER_DEPTH. In most cases, the physical size of the framebuffer has to correspond to the ScreenSize of the GUI project.

In case that an external display controller with its own graphics memory (GRAM) is used, there is no need for a complete framebuffer. In this case, Embedded Wizard GUI applications can be created that are using a small scratch-pad buffer, which requires only data memory for a few display lines.

Monitoring the Data Memory (RAM) usage

Embedded Wizard provides an 'in-target' debugging/analyzing feature for monitoring the memory (RAM) usage during runtime. This option is controlled by the macro EW_PRINT_MEMORY_USAGE. The function EwPrintProfilerStatistic() which is placed within the main loop will then print a short report about the current memory allocation of Chora objects, strings and resources. Additionally, the current total memory allocation and the maximum peak value is reported.

Data Memory (RAM) usage of a GUI example reported from target via serial connection to console window.

Optimizing the Flash Memory (ROM) usage

The following list contains recommendations to reduce the flash memory (ROM) consumption of your Embedded Wizard UI application. Please note, that some measures to reduce flash memory can result in increased RAM consumption.

Font Resources - Try to avoid too many different fonts and font sizes. Each font resource in your project causes Embedded Wizard to generate an extra set of glyphs. If you need many different font sizes and/or very large character ranges, it might be better to use a Platform Package with an external True Type Font Engine.

Font Resources - Reduce the font range to the necessary limit. By using the Excel sheet template for managing your strings, you can extract the used character codes of your strings in order to define the minimum range.

Font Resources - If possible, you can try to reduce the font quality. Even if the glyphs are compressed in the code, reducing the quality may help to save flash memory. Unfortunately, this measure can also degrade the display quality of texts.

Strings - Setting the attribute FormatOfStringConstants to Compressed ensures that all string constants are stored compressed within the flash memory. Please consider that compressed strings are loaded on request into RAM during runtime.

Bitmap Resources - Setting the attribute FormatOfBitmapResources to Compressed ensures that the bitmap pixel information of the bitmap resources are stored compressed within the flash memory. Please consider that compressed bitmap resources are loaded on request into RAM during runtime.

Bitmap Resources - Merge similar icons or images to a single file. By this way Embedded Wizard can reach a higher compression with the resource converter and you can easily access such an image frame by setting the attribute FrameSize and select the frame number in your image views.

Software architecture - Try to make an object-oriented software design by using inheritance in your class hierarchy. Try to avoid copies of similar classes in order to reduce the code size.

Compiler optimization - Use compiler optimization to get a compact binary.

Optimizing the Data Memory (RAM) usage

The following list contains recommendations to reduce the data memory (RAM) consumption of your Embedded Wizard UI application. Please note, that some measures to save data memory can result in an increased flash footprint.

Color Format Selection - In order to save memory for the framebuffer, a Graphics Engine with a reduced color format can be selected. The attribute PlatformPackage determines the color format of the target system - this has to correspond to the color format of the framebuffer.

Framebuffer Configuration - The selection of the framebuffer concept has a big impact to the resulting memory footprint. For many GUI applications without excessive animations, the use of double buffering is not necessary. The macro EW_USE_DOUBLE_BUFFER can be used to switch on/off the usage of a double-buffered framebuffer.

Strings - Setting the attribute FormatOfStringConstants to DirectAccess ensures that all string constants are stored uncompressed within the flash memory so that there is no need to load them into RAM during runtime. Please consider that uncompressed string constants require more flash memory than compressed string constants.

Bitmap Resources - Setting the attribute FormatOfBitmapResources to DirectAccess ensures that the bitmap pixel information of the bitmap resources are stored uncompressed within the flash memory. These type of bitmaps are drawn directly from the flash memory without the need to load them into the RAM during runtime. Please consider that uncompressed bitmap resources require more flash memory than compressed bitmap resources.

Buffered Objects - Try to avoid buffered GUI components as these are allocating an internal bitmap to render their content. The size of the bitmaps correspond to the actual size of the components.

Glyph Cache - Define a reasonable/minimal size for the glyph cache: The width and height of the gylph cache surface can be configured by using the macros EW_MAX_GLYPH_SURFACE_WIDTH and EW_MAX_GLYPH_SURFACE_HEIGHT. This surface stores all glyphs used during text drawing operations. The larger the surface the more glyphs can be reused without needing to decompress or rasterize them again. The resulting RAM usage is EW_MAX_GLYPH_SURFACE_WIDTH * EW_MAX_GLYPH_SURFACE_HEIGHT * 1 byte.

Surface Cache - Define a reasonable/minimal size for the surface cache: The macro EW_MAX_SURFACE_CACHE_SIZE specifies the threshold value for the capacity of the surface cache. This cache stores often used bitmap resources and keeps them within the cache as long as there is enough space. The value for this macro is expressed in bytes as an integer number lying between 0 and 0x20000000.

String Cache - Define a reasonable/minimal size for the string cache: The macro EW_MAX_STRING_CACHE_SIZE specifies the threshold value for the capacity of the string cache. The string cache stores frequently used string constants preventing them from being reloaded repeatedly. Embedded Wizard tracks the amount of memory occupied by all string constants and as soon as this size exceeds the value specified in the macro, discards oldest unused strings from the cache automatically. The value for this macro is expressed in bytes as an integer number lying between 0 and 0x800000.

Instruction Buffer - Define a reasonable/minimal size for the instruction buffer: The macro EW_MAX_ISSUE_TASKS specifies the capacity of the instruction buffers used to store drawing operations. Larger buffers improve the optimization and elimination of superfluous drawing operations. In turn, small buffers cause the drawing process to be often interrupted to flush the prepared operations. The value for this macro is expressed in 'tasks' as an integer number lying between 1 and 8192. You should ensure that the issue buffer is at least as large as the most complex drawing operation performed in your application. The following equation can be used to calculate the approximated RAM usage resulting from the configuration of the macro: (( EW_MAX_ISSUE_TASKS * 64 ) + 512 ) * 1 byte.