Skip to main content
Associate II
September 15, 2025
Solved

Animated Image and RGB565 compression

  • September 15, 2025
  • 6 replies
  • 882 views

Hi. While testing the animation, I noticed strange behavior in the Animated Image widget when using the RGB565 image format with compression.

I'm using an STM32U599, LTDC/RGB24bit, the animation is started with a button.

Immediately after startup, the widget area turns white with dots. I could understand this if it were some kind of limitation resulting from the compression. But...
If the widget is placed in a Swipe Container widget, after changing the screen and returning, the white area disappears, and the animation executes correctly. What could be the cause? I'm concerned about compression, because in this case, the size difference is tenfold.

I also want to know if there's an option somewhere to prevent the framebuffer from being placed in flash memory every time the project is generated? Currently, I add the "__attribute__ ((section (".noinit")));" parameter, but this has to be done every time the configuration changes...

Best answer by Osman SOYKURT

Hello @Jin454 , ok so this is the issue. CubeIDE indeed generates a linker script but it's uncomplete. When you use TouchGFX you have to add the framebuffer section that I mentioned in my previous message : 

 


@Osman SOYKURT  wrote:

Hello @Jin454 ,

Could you double check if you have correctly activated image compression feature in TouchGFX Designer? We have this article that might help.
For your second question, framebuffers are supposed to be placed in RAM memory and not in flash since you have to write its content whenever a change on screen happens. In all our examples, you could see we're storing the framebuffer in RAM. For instance, this is what we have in the linker file for our STM32U5A9J-DK TBS :

 FramebufferSection (NOLOAD) :
 {
 *(TouchGFX_Framebuffer TouchGFX_Framebuffer.*)
 *(.gnu.linkonce.r.*)
 . = ALIGN(0x4); 

...
...
 } >RAM

 

You can check one of our TBS's linker script (for instance the STM32U5A9J-DK TBS , the linker is called STM32U5A9NJHXQ_FLASH.ld) if you need an example.

6 replies

Osman SOYKURT
Technical Moderator
September 19, 2025

Hello @Jin454 ,

Could you double check if you have correctly activated image compression feature in TouchGFX Designer? We have this article that might help.
For your second question, framebuffers are supposed to be placed in RAM memory and not in flash since you have to write its content whenever a change on screen happens. In all our examples, you could see we're storing the framebuffer in RAM. For instance, this is what we have in the linker file for our STM32U5A9J-DK TBS :

 FramebufferSection (NOLOAD) :
 {
 *(TouchGFX_Framebuffer TouchGFX_Framebuffer.*)
 *(.gnu.linkonce.r.*)
 . = ALIGN(0x4); 

...
...
 } >RAM

 

Osman SOYKURTST Software Developer | TouchGFX
Jin454Author
Associate II
September 20, 2025

Thanks for the reply.
Regarding the compression problem, I found the cause.When using compression, the image format must be identical to the framebuffer format. I was using an RGB888 framebuffer, but the image was in RGB565 format. The problem only occurred when compression was enabled. Maybe this information will be useful to someone.

Regarding the framebuffer location problem, after generating the project in the Stm32CubeIDE, it generates the TouchGFXGeneratedHAL.cpp file with the code:

namespace
{
// Use the section "TouchGFX_Framebuffer" in the linker script to specify the placement of the buffer
LOCATION_PRAGMA_NOLOAD("TouchGFX_Framebuffer")
uint32_t frameBuf[(480 * 480 * 2 + 3) / 4 * 2] LOCATION_ATTRIBUTE_NOLOAD("TouchGFX_Framebuffer");
static uint16_t lcd_int_active_line;
static uint16_t lcd_int_porch_line;
}


This causes the framebuffer to be placed in both RAM and flash, as shown in the attached image. The problem definitely occurs on the Stm32U5 and Stm32H5. I haven't tested the others.
Zrzut ekranu 2025-09-20 215336.png


After each code generation, you need to change the code to:

namespace
{
// Use the section "TouchGFX_Framebuffer" in the linker script to specify the placement of the buffer
LOCATION_PRAGMA_NOLOAD("TouchGFX_Framebuffer")
uint32_t frameBuf[(480 * 480 * 2 + 3) / 4 * 2] __attribute__ ((section (".noinit")));
static uint16_t lcd_int_active_line;
static uint16_t lcd_int_porch_line;
}

ScratchbufferA and B shouldn't be only in RAM either?

LOCATION_PRAGMA_NOLOAD("Nemagfx_Memory_Pool_Buffer")
static uint8_t nemagfx_pool_mem[NEMAGFX_MEM_POOL_SIZE] LOCATION_ATTRIBUTE_NOLOAD("Nemagfx_Memory_Pool_Buffer"); /* NemaGFX memory pool */

LOCATION_PRAGMA_NOLOAD("Nemagfx_Stencil_Buffer")
static uint8_t nemagfx_stencil_buffer_mem[NEMAGFX_STENCIL_POOL_SIZE] LOCATION_ATTRIBUTE_NOLOAD("Nemagfx_Stencil_Buffer"); /* NemaGFX stencil buffer memory */

 

Osman SOYKURT
Technical Moderator
September 22, 2025

@Jin454 Could you show your linker script?

Osman SOYKURTST Software Developer | TouchGFX
Jin454Author
Associate II
September 22, 2025

FLASH.ld

/*
******************************************************************************
**
** File : LinkerScript.ld
**
** Author : STM32CubeIDE
**
** Abstract : Linker script for STM32U599xJ Device from STM32U5 series
** 4096Kbytes FLASH
** 2512Kbytes RAM
**
** Set heap size, stack size and stack location according
** to application requirements.
**
** Set memory bank area and size if external memory is used.
**
** Target : STMicroelectronics STM32
**
** Distribution: The file is distributed as is without any warranty
** of any kind.
**
*****************************************************************************
** @attention
**
** Copyright (c) 2025 STMicroelectronics.
** All rights reserved.
**
** This software is licensed under terms that can be found in the LICENSE file
** in the root directory of this software component.
** If no LICENSE file comes with this software, it is provided AS-IS.
**
*****************************************************************************
*/

/* Entry Point */
ENTRY(Reset_Handler)

/* Highest address of the user mode stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */

_Min_Heap_Size = 0x2000; /* required amount of heap */
_Min_Stack_Size = 0x4000; /* required amount of stack */

/* Memories definition */
MEMORY
{
 RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 2496K
 SRAM4 (xrw) : ORIGIN = 0x28000000, LENGTH = 16K
 FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 4096K
}



/* Sections */
SECTIONS
{
 /* The startup code into "FLASH" Rom type memory */
 .isr_vector :
 {
 KEEP(*(.isr_vector)) /* Startup code */
 } >FLASH

 /* The program code and other data into "FLASH" Rom type memory */
 .text :
 {
 *(.text) /* .text sections (code) */
 *(.text*) /* .text* sections (code) */
 *(.glue_7) /* glue arm to thumb code */
 *(.glue_7t) /* glue thumb to arm code */
 *(.eh_frame)

 KEEP (*(.init))
 KEEP (*(.fini))

 _etext = .; /* define a global symbols at end of code */
 } >FLASH

 /* Constant data into "FLASH" Rom type memory */
 .rodata :
 {
 *(.rodata) /* .rodata sections (constants, strings, etc.) */
 *(.rodata*) /* .rodata* sections (constants, strings, etc.) */
 } >FLASH

 .ARM.extab (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
 {
 *(.ARM.extab* .gnu.linkonce.armextab.*)
 } >FLASH
 .ARM (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
 {
 __exidx_start = .;
 *(.ARM.exidx*)
 __exidx_end = .;
 } >FLASH

 .preinit_array (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
 {
 PROVIDE_HIDDEN (__preinit_array_start = .);
 KEEP (*(.preinit_array*))
 PROVIDE_HIDDEN (__preinit_array_end = .);
 } >FLASH

 .init_array (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
 {
 PROVIDE_HIDDEN (__init_array_start = .);
 KEEP (*(SORT(.init_array.*)))
 KEEP (*(.init_array*))
 PROVIDE_HIDDEN (__init_array_end = .);
 } >FLASH

 .fini_array (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
 {
 PROVIDE_HIDDEN (__fini_array_start = .);
 KEEP (*(SORT(.fini_array.*)))
 KEEP (*(.fini_array*))
 PROVIDE_HIDDEN (__fini_array_end = .);
 } >FLASH

 /* Used by the startup to initialize data */
 _sidata = LOADADDR(.data);

 /* Initialized data sections into "RAM" Ram type memory */
 .data :
 {
 _sdata = .; /* create a global symbol at data start */
 *(.data) /* .data sections */
 *(.data*) /* .data* sections */
 *(.RamFunc) /* .RamFunc sections */
 *(.RamFunc*) /* .RamFunc* sections */

 _edata = .; /* define a global symbol at data end */
 } >RAM AT> FLASH

 /* Uninitialized data section into "RAM" Ram type memory */
 .bss :
 {
 /* This is used by the startup in order to initialize the .bss section */
 _sbss = .; /* define a global symbol at bss start */
 __bss_start__ = _sbss;
 *(.bss)
 *(.bss*)
 *(COMMON)

 _ebss = .; /* define a global symbol at bss end */
 __bss_end__ = _ebss;
 } >RAM

 /* User_heap_stack section, used to check that there is enough "RAM" Ram type memory left */
 ._user_heap_stack :
 {
 . = ALIGN(8);
 PROVIDE ( end = . );
 PROVIDE ( _end = . );
 . = . + _Min_Heap_Size;
 . = . + _Min_Stack_Size;
 . = ALIGN(8);
 } >RAM




 /* Remove information from the compiler libraries */
 /DISCARD/ :
 {
 libc.a ( * )
 libm.a ( * )
 libgcc.a ( * )
 }

 .ARM.attributes 0 : { *(.ARM.attributes) }
}

RAM.ld

/*
******************************************************************************
**
** File : LinkerScript.ld (debug in RAM dedicated)
**
** Author : STM32CubeIDE
**
** Abstract : Linker script for STM32U599xJ Device from STM32U5 series
** 2512Kbytes RAM
**
** Set heap size, stack size and stack location according
** to application requirements.
**
** Set memory bank area and size if external memory is used.
**
** Target : STMicroelectronics STM32
**
** Distribution: The file is distributed as is without any warranty
** of any kind.
**
*****************************************************************************
** @attention
**
** Copyright (c) 2025 STMicroelectronics.
** All rights reserved.
**
** This software is licensed under terms that can be found in the LICENSE file
** in the root directory of this software component.
** If no LICENSE file comes with this software, it is provided AS-IS.
**
*****************************************************************************
*/

/* Entry Point */
ENTRY(Reset_Handler)

/* Highest address of the user mode stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */

_Min_Heap_Size = 0x200; /* required amount of heap */
_Min_Stack_Size = 0x400; /* required amount of stack */

/* Memories definition */
MEMORY
{
 RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 2496K
 SRAM4 (xrw) : ORIGIN = 0x28000000, LENGTH = 16K
}

/* Sections */
SECTIONS
{
 /* The startup code into "RAM" Ram type memory */
 .isr_vector :
 {
 KEEP(*(.isr_vector)) /* Startup code */
 } >RAM

 /* The program code and other data into "RAM" Ram type memory */
 .text :
 {
 *(.text) /* .text sections (code) */
 *(.text*) /* .text* sections (code) */
 *(.glue_7) /* glue arm to thumb code */
 *(.glue_7t) /* glue thumb to arm code */
 *(.eh_frame)
 *(.RamFunc) /* .RamFunc sections */
 *(.RamFunc*) /* .RamFunc* sections */

 KEEP (*(.init))
 KEEP (*(.fini))

 _etext = .; /* define a global symbols at end of code */
 } >RAM

 /* Constant data into "RAM" Ram type memory */
 .rodata :
 {
 *(.rodata) /* .rodata sections (constants, strings, etc.) */
 *(.rodata*) /* .rodata* sections (constants, strings, etc.) */
 } >RAM

 .ARM.extab (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
 {
 *(.ARM.extab* .gnu.linkonce.armextab.*)
 } >RAM
 .ARM (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
 {
 __exidx_start = .;
 *(.ARM.exidx*)
 __exidx_end = .;
 } >RAM

 .preinit_array (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
 {
 PROVIDE_HIDDEN (__preinit_array_start = .);
 KEEP (*(.preinit_array*))
 PROVIDE_HIDDEN (__preinit_array_end = .);
 } >RAM

 .init_array (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
 {
 PROVIDE_HIDDEN (__init_array_start = .);
 KEEP (*(SORT(.init_array.*)))
 KEEP (*(.init_array*))
 PROVIDE_HIDDEN (__init_array_end = .);
 } >RAM

 .fini_array (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
 {
 PROVIDE_HIDDEN (__fini_array_start = .);
 KEEP (*(SORT(.fini_array.*)))
 KEEP (*(.fini_array*))
 PROVIDE_HIDDEN (__fini_array_end = .);
 } >RAM

 /* Used by the startup to initialize data */
 _sidata = LOADADDR(.data);

 /* Initialized data sections into "RAM" Ram type memory */
 .data :
 {
 _sdata = .; /* create a global symbol at data start */
 *(.data) /* .data sections */
 *(.data*) /* .data* sections */

 _edata = .; /* define a global symbol at data end */
 } >RAM

 /* Uninitialized data section into "RAM" Ram type memory */
 .bss :
 {
 /* This is used by the startup in order to initialize the .bss section */
 _sbss = .; /* define a global symbol at bss start */
 __bss_start__ = _sbss;
 *(.bss)
 *(.bss*)
 *(COMMON)

 _ebss = .; /* define a global symbol at bss end */
 __bss_end__ = _ebss;
 } >RAM

 /* User_heap_stack section, used to check that there is enough "RAM" Ram type memory left */
 ._user_heap_stack :
 {
 . = ALIGN(8);
 PROVIDE ( end = . );
 PROVIDE ( _end = . );
 . = . + _Min_Heap_Size;
 . = . + _Min_Stack_Size;
 . = ALIGN(8);
 } >RAM
 


 /* Remove information from the compiler libraries */
 /DISCARD/ :
 {
 libc.a ( * )
 libm.a ( * )
 libgcc.a ( * )
 }

 .ARM.attributes 0 : { *(.ARM.attributes) }
}


 

 

Unedited. Generated by IDE.

Osman SOYKURT
Osman SOYKURTBest answer
Technical Moderator
October 9, 2025

Hello @Jin454 , ok so this is the issue. CubeIDE indeed generates a linker script but it's uncomplete. When you use TouchGFX you have to add the framebuffer section that I mentioned in my previous message : 

 


@Osman SOYKURT  wrote:

Hello @Jin454 ,

Could you double check if you have correctly activated image compression feature in TouchGFX Designer? We have this article that might help.
For your second question, framebuffers are supposed to be placed in RAM memory and not in flash since you have to write its content whenever a change on screen happens. In all our examples, you could see we're storing the framebuffer in RAM. For instance, this is what we have in the linker file for our STM32U5A9J-DK TBS :

 FramebufferSection (NOLOAD) :
 {
 *(TouchGFX_Framebuffer TouchGFX_Framebuffer.*)
 *(.gnu.linkonce.r.*)
 . = ALIGN(0x4); 

...
...
 } >RAM

 

You can check one of our TBS's linker script (for instance the STM32U5A9J-DK TBS , the linker is called STM32U5A9NJHXQ_FLASH.ld) if you need an example.

Osman SOYKURTST Software Developer | TouchGFX
Jin454Author
Associate II
October 12, 2025

Adding all buffers to the appropriate section solved the problem. Regenerating the project doesn't remove it.
Thanks for your help.

 FramebufferSection (NOLOAD) :
 {
 *(TouchGFX_Framebuffer TouchGFX_Framebuffer.*)
 *(.gnu.linkonce.r.*)
 . = ALIGN(0x4); 

 *(Nemagfx_Stencil_Buffer Nemagfx_Stencil_Buffer.*)
 *(.gnu.linkonce.r.*)
 . = ALIGN(0x4); 

 *(Nemagfx_Memory_Pool_Buffer Nemagfx_Memory_Pool_Buffer.*)
 *(.gnu.linkonce.r.*)
 . = ALIGN(0x4);
 
 *(TouchGFX_ScratchbufferA TouchGFX_ScratchbufferA.*)
 *(.gnu.linkonce.r.*)
 . = ALIGN(0x4); 
 
 *(TouchGFX_ScratchbufferB TouchGFX_ScratchbufferB.*)
 *(.gnu.linkonce.r.*)
 . = ALIGN(0x4); 
 
 
 } >RAM

 

Osman SOYKURT
Technical Moderator
October 14, 2025

You're welcome :)

Osman SOYKURTST Software Developer | TouchGFX