cancel
Showing results for 
Search instead for 
Did you mean: 

External vs. internal flash memory for touchGFX assets

HP
Senior III

When developing touchGFX applications you tend to get a pretty high memory need.

I'm working with the CubeIDE integration of TouchGFX and tried to add a third screen (with a third background image). I got an error saying that the application would not fit in my FLASH.

After a bit of digging it seems that the linker files don't mention the QSPI at all.

I can add that to the linker files but I would like to know if there is an official way of doing this?

I found some documentation on this but I'm not sure if this is the right way to go about it.

What goes where in the memory and how do I control it? if at all?

Thanks!

1 ACCEPTED SOLUTION

Accepted Solutions
HP
Senior III

Just to close this one up I have made a video guide on how to configure the F746 DISCO board for external memory use.

You can find it here:

https://youtu.be/237lPdMsDZs

View solution in original post

40 REPLIES 40
Martin KJELDSEN
Chief III

Hi @HP​,

I guess it all depends on how you created your project. There are no guarantees, as far as CubeMX and CubeIDE are concerned, that the linker script is correct when it comes to TouchGFX. If you create an application using one of our Application Templates, you'll see the correct references to memory regions in the linker script for each compiler for each board.

Was this a custom board? The same concepts go here - Try to get some inspiration from what we already have through the Designer.

Let me know.

/Martin

HP
Senior III

This is for the F746-DISCO board but I will be working on a custom board in a short while. That board will have a larger flash since the one on the dev-board is obsolete.

I'll have a look on one of the generated files and try to update the ones in my current project. However, there is two files, one for flash and one for RAM. I guess it's only the flash one I should be looking into?

Martin KJELDSEN
Chief III

Which two files are those? Are you referring to different .icf files for IAR? Let me show you the linker scripts for The STM32F746G-DISCO. It defines both RAM and FLASH sections.

gcc (STM32F746NGHx_FLASH.ld):

/* Entry Point */
ENTRY(Reset_Handler)
 
/* Highest address of the user mode stack */
_estack = 0x20050000;    /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x200;      /* required amount of heap  */
_Min_Stack_Size = 0x400; /* required amount of stack */
 
/* Specify the memory areas */
MEMORY
{
RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 320K
FLASH (rx)     : ORIGIN = 0x8000000, LENGTH = 1024K
QUADSPI (r)    : ORIGIN = 0x90000000, LENGTH = 16M
}
 
/* Define output sections */
SECTIONS
{
  /* The startup code goes first into FLASH */
  .isr_vector :
  {
    . = ALIGN(4);
    KEEP(*(.isr_vector)) /* Startup code */
    . = ALIGN(4);
  } >FLASH
 
  /* The program code and other data goes into FLASH */
  .text :
  {
    . = ALIGN(4);
    *(.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))
 
    . = ALIGN(4);
    _etext = .;        /* define a global symbols at end of code */
  } >FLASH
 
  /* Constant data goes into FLASH */
  .rodata :
  {
    . = ALIGN(4);
    *(.rodata)         /* .rodata sections (constants, strings, etc.) */
    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
    . = ALIGN(4);
  } >FLASH
 
  .ARM.extab   : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
  .ARM : {
    __exidx_start = .;
    *(.ARM.exidx*)
    __exidx_end = .;
  } >FLASH
 
  .preinit_array     :
  {
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP (*(.preinit_array*))
    PROVIDE_HIDDEN (__preinit_array_end = .);
  } >FLASH
  .init_array :
  {
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT(.init_array.*)))
    KEEP (*(.init_array*))
    PROVIDE_HIDDEN (__init_array_end = .);
  } >FLASH
  .fini_array :
  {
    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 goes into RAM, load LMA copy after code */
  .data : 
  {
    . = ALIGN(4);
    _sdata = .;        /* create a global symbol at data start */
    *(.data)           /* .data sections */
    *(.data*)          /* .data* sections */
 
    . = ALIGN(4);
    _edata = .;        /* define a global symbol at data end */
  } >RAM AT> FLASH
 
  
  /* Uninitialized data section */
  . = ALIGN(4);
  .bss :
  {
    /* This is used by the startup in order to initialize the .bss secion */
    _sbss = .;         /* define a global symbol at bss start */
    __bss_start__ = _sbss;
    *(.bss)
    *(.bss*)
    *(COMMON)
 
    . = ALIGN(4);
    _ebss = .;         /* define a global symbol at bss end */
    __bss_end__ = _ebss;
  } >RAM
 
  /* User_heap_stack section, used to check that there is enough RAM left */
  ._user_heap_stack :
  {
    . = ALIGN(8);
    PROVIDE ( end = . );
    PROVIDE ( _end = . );
    . = . + _Min_Heap_Size;
    . = . + _Min_Stack_Size;
    . = ALIGN(8);
  } >RAM
 
  /* Remove information from the standard libraries */
  /DISCARD/ :
  {
    libc.a ( * )
    libm.a ( * )
    libgcc.a ( * )
  }
 
  .ARM.attributes 0 : { *(.ARM.attributes) }
 
	ExtFlashSection :
	{
		*(ExtFlashSection ExtFlashSection.*)
		*(.gnu.linkonce.r.*)
        . = ALIGN(0x4);
	} >QUADSPI
 
/* Un comment this section to place fonts and text in external flash
  FontFlashSection :
	{
		*(FontFlashSection FontFlashSection.*)
		*(.gnu.linkonce.r.*)
        . = ALIGN(0x4);
	} >QUADSPI
 
  TextFlashSection :
	{
		*(TextFlashSection TextFlashSection.*)
		*(.gnu.linkonce.r.*)
        . = ALIGN(0x4);
	} >QUADSPI
*/
}

IAR (stm32f746xx_flash.icf):

/*###ICF### Section handled by ICF editor, don't touch! ****/
/*-Editor annotation file-*/
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\cortex_v1_0.xml" */
/*-Specials-*/
define symbol __ICFEDIT_intvec_start__ = 0x08000000;
/*-Memory Regions-*/
define symbol __ICFEDIT_region_ROM_start__     = 0x08000000;
define symbol __ICFEDIT_region_ROM_end__       = 0x080FFFFF;
define symbol __ICFEDIT_region_RAM_start__     = 0x20000000;
define symbol __ICFEDIT_region_RAM_end__       = 0x2004FFFF;
define symbol __ICFEDIT_region_ITCMRAM_start__ = 0x00000000;
define symbol __ICFEDIT_region_ITCMRAM_end__   = 0x00003FFF;
/*-Sizes-*/
define symbol __ICFEDIT_size_cstack__ = 0x400;
define symbol __ICFEDIT_size_heap__ = 0x200;
/**** End of ICF editor section. ###ICF###*/
 
define symbol __region_QSPI_start__ = 0x90000000;
define symbol __region_QSPI_end__   = 0x90FFFFFF;
 
define memory mem with size = 4G;
define region ROM_region      = mem:[from __ICFEDIT_region_ROM_start__   to __ICFEDIT_region_ROM_end__];
define region RAM_region      = mem:[from __ICFEDIT_region_RAM_start__   to __ICFEDIT_region_RAM_end__];
define region QSPI_region   = mem:[from __region_QSPI_start__ to __region_QSPI_end__];
define region ITCMRAM_region  = mem:[from __ICFEDIT_region_ITCMRAM_start__ to __ICFEDIT_region_ITCMRAM_end__];
 
define block CSTACK    with alignment = 8, size = __ICFEDIT_size_cstack__   { };
define block HEAP      with alignment = 8, size = __ICFEDIT_size_heap__     { };
 
initialize by copy { readwrite };
do not initialize  { section .noinit };
 
place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec };
 
place in ROM_region   { readonly };
place in RAM_region   { readwrite,
                        block CSTACK, block HEAP };
 
place in QSPI_region { section ExtFlashSection, section FontFlashSection, section TextFlashSection };

HP
Senior III

I've done a bit of testing and the results are in: from a memory perspective this works like a charm - and might I suggest that this be implemented as a checkbox during project generation?

Prerequisites:

  • Working project in CubeIDE
  • This is tested only on the F746-DISCO board but I take it that it will work on all boards with QSPI.

The issue is that all assets (fonts, images etc) are stored in the internal flash of the MCU. this creates quite a memory footprint even with just a few font sizes and backgrounds.

This picture shows the memory usage with just 2 screens with two different font sizes (20pt and 200pt) and a single button. We are already maxed out here!!

0690X00000AQtMdQAL.png

Next step is to edit the linker file so it allows storage in the QSPI memory.

In my working project I have a file called 'STM32F746NGHX_FLASH.ld' Note that we're ONLY editing the FLASH linker script!!!

The file is opened and the memory section is changed so the QUADSPI region is also available. (Just add the last line to the section)

MEMORY
{
    RAM	(xrw)	: ORIGIN = 0x20000000,	LENGTH = 320K
    FLASH	(rx)	: ORIGIN = 0x8000000,	LENGTH = 1024K
    QUADSPI (r)    : ORIGIN = 0x90000000, LENGTH = 16M
}

Now we have defined the QSPI section and by looking in any example code generated by the TouchGFX Designer we can see the following snippet added to the fale BEFORE the last curly brace:

	ExtFlashSection :
	{
		*(ExtFlashSection ExtFlashSection.*)
		*(.gnu.linkonce.r.*)
        . = ALIGN(0x4);
	} >QUADSPI
 
/* Un comment this section to place fonts and text in external flash
  FontFlashSection :
	{
		*(FontFlashSection FontFlashSection.*)
		*(.gnu.linkonce.r.*)
        . = ALIGN(0x4);
	} >QUADSPI
 
  TextFlashSection :
	{
		*(TextFlashSection TextFlashSection.*)
		*(.gnu.linkonce.r.*)
        . = ALIGN(0x4);
	} >QUADSPI
*/

With this change in place we can do another build of the project and the memory footprint now looks like this:

0690X00000AQtMnQAL.png

A pretty radical change 🙂 You should be able to fit almost anything into that QSPI footprint.

But wait - There's more!

The code even states that if you remove the comments for the last section you get the fonts and text moved as well - let's just try that.

Beware that just removing the multi-line comment will result in the decribing text becoming exposed so just move the '*/' to the same line as the beginning of the comment - or remove the comment text altogether.

Now the result is this:

0690X00000AQtMxQAL.pngSo this is it. By adding to the linkerfiler you get muuuuuch more space in your application 🙂

As always - Thank you for your response 🙂

Please check the post below for clarity. Also - feel free to use it for tutorials if you think it can provide some insight to memory placement

HP
Senior III

Hum.. One thing is that the project builds and locates the assets in the right locations in QSPI.

Next issue is with loading the assets onto the external flash. Luckily this have already been solved by @Community member​  and his answer here: https://community.st.com/s/question/0D50X0000Ap1gIO/problem-using-qspi-with-stm32f746-and-touchgfx

The console writes this:

Memory Programming ...
Opening and parsing file: ST-LINK_GDB_server_a04824.srec
  File          : ST-LINK_GDB_server_a04824.srec
  Size          : 830520 Bytes
  Address       : 0x08000000 
 
 
Erasing memory corresponding to segment 0:
Erasing internal memory sectors [0 4]
Erasing memory corresponding to segment 1:
Erasing external memory sectors [0 10]
Download in Progress:
 
 
File download complete
Time elapsed during download operation: 00:00:09.524
 
 
 
Verifying ...

Which is all fine and dandy - note the 'Erasing external memory sectors [0 10]..

But no luck so far - I only get garbage on screen. It looks like the application have a hard time figuring out where to load the images from. Anyone else have luck with this???

Great tip, thanks! The original projects done in CubeIDE with TouchGFX on F746G-DISCO probably only had things in internal flash.

The application should know where to load the images from, but does the QSPI actually have that data? How much garbage do you have? Try creating a box as background and adding a small image in the center, then you should only have garbage in the center. So even though you've got your linker script configured, the QSPI isn't actually programmed.

/Martin

Aargh, this is beyond frustrating!

I have just tried what you suggested - making a box as background and having just some text and a button on that. Even with that I can't get anything to load from QSPI flash. I can switch to internal memory and the application will work just fine.

I have verified that the flash do get programmed (using both ST-Link utility and CubeProg)

I have enabled .hex generation so I could download that to the board directly using ST-Link Utility. I have been looking in the .hex file and verified that the external flash section is there. I can even see that the application is running and communicating with other devices.

I have also tried to load the external flash using CubeProg and disabling the external flash writing in CubeIDE. no luck.

I have absolutely no idea what to try next. The hex file says it's there. The programs says that the chip is programmed. What can I do?