2025-03-26 1:51 PM - edited 2025-03-26 2:04 PM
I'm working with the STM32H757 Eval board and I'm using TouchGFX.
Using the designer, I created the Dice Animation demo project and got it running on the board.
I then duplicated this project and hooked it into our code ecosystem (we use Visual Studios with VisualGDB instead of CubeIDE and have numerous platform submodules that we incorporate into our system). All of that is working. I even have the two environments cross building with each other. Visual Studios will call the TouchGFX makefile and generate assets and build all the UI elements, and then incorporate those files into our build system on our platform. I can then program the board from Visual Studios and it will program the external QSPI flash with the UI data and the Dice Animation program will boot up. I even have it working the other way so that from the TouchGFX Designer when you hit program, it will go out and call the Visual Studios make and build the system that way and then program the board and external flash via CubeProgrammer CLI. This way the UI design guys can work in their environment (TouchGFX) and I can work in my environment (Visual Studios). All that is working great.
There is now one thing left that I absolutely have been unable to get working... separating the internal and external memories for programming purposes. The Demo Project calls the following line in it's makefile
@$(objcopy) --remove-section=ExtFlashSection --remove-section=TextFlashSection $@ $(@D)/intflash.elf
That results in the following output (normally these are suppressed, but I removed that part from the makefile while debugging)
arm-none-eabi-objcopy: CM7/TouchGFX/build/bin/target.elf: warning: Empty loadable segment detected at vaddr=0x90000000, is this intentional?
arm-none-eabi-objcopy: CM7/TouchGFX/build/bin/intflash.elf: section ._user_heap_stack lma 0x8039f70 adjusted to 0x8046640
Those make sense based.
When I execute the same command on my .elf file, I get these warnings/errors
C:/SysGCC/arm-eabi/bin/arm-none-eabi-objcopy.exe: Debug/STM32H757Eval-CM7.elf: warning: empty loadable segment detected at vaddr=0x4beb4390000000, is this intentional?
C:/SysGCC/arm-eabi/bin/arm-none-eabi-objcopy.exe: Debug/intflash.elf: section ._user_heap_stack lma 0x4be9480805a5a8 adjusted to 0x4be95300000000
C:/SysGCC/arm-eabi/bin/arm-none-eabi-objcopy.exe: Debug/intflash.elf: symbol `textsGb' required but not present
C:/SysGCC/arm-eabi/bin/arm-none-eabi-objcopy.exe: Debug/intflash.elf: no symbols
So, first things first, the error "textsGb" required but not present. That comes from the TouchGFX generated file Texts.cpp and also lives in LanguageGB.cpp. I did a diff of those two files from my project and compared them to the Dice Animation project, they are 100% identical.
Second, the addresses listed on mine are absolutely bonkers. Where did those come from? This elf file works when I program it on the board so where are those coming from?
I am using the exact same linker file as Dice Animations project (I copied it to my folder and use it without any changes). Just so you don't have to go look it up, here it is:
ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = ORIGIN(RAM_D1) + LENGTH(RAM_D1); /* end of "RAM_D1" Ram type memory */
_Min_Heap_Size = 0x1000 ; /* required amount of heap */
_Min_Stack_Size = 0x1000 ; /* required amount of stack */
/* Memories definition */
MEMORY
{
RAM_D1 (xrw) : ORIGIN = 0x24000000, LENGTH = 512K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K /* Memory is divided. Actual start is 0x08000000 and actual length is 2048K */
QSPI (rx) : ORIGIN = 0x90000000, LENGTH = 128000K
DTCMRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 288K
RAM_D3 (xrw) : ORIGIN = 0x38000000, LENGTH = 64K
ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K
SDRAM2 (rw) : ORIGIN = 0xD0000000, LENGTH = 67100K
}
/* Sections */
SECTIONS
{
/* The startup code into "FLASH" Rom type memory */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >FLASH
/* The program code and other data into "FLASH" Rom type memory */
.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 into "FLASH" Rom type memory */
.rodata :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} >FLASH
ExtFlashSection :
{
ExtThirdPartyHeader = .;
KEEP(*(.ExtFlashSection));
ExtThirdPartyHeader_end = .;
} >QSPI
TextFlashSection :
{
ExtThirdPartyHeader = .;
KEEP(*(.TextFlashSection));
ExtThirdPartyHeader_end = .;
} >QSPI
.ARM.extab : {
. = ALIGN(4);
*(.ARM.extab* .gnu.linkonce.armextab.*)
. = ALIGN(4);
} >FLASH
.ARM : {
. = ALIGN(4);
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
. = ALIGN(4);
} >FLASH
.preinit_array :
{
. = ALIGN(4);
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(4);
} >FLASH
.init_array :
{
. = ALIGN(4);
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(4);
} >FLASH
.fini_array :
{
. = ALIGN(4);
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(4);
} >FLASH
/* Used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections into "RAM" Ram type memory */
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
*(.RamFunc) /* .RamFunc sections */
*(.RamFunc*) /* .RamFunc* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM_D1 AT> FLASH
/* Uninitialized data section into "RAM" Ram type memory */
. = ALIGN(4);
.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)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM_D1
/* 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_D1
/* Remove information from the compiler libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
FramebufferSection (NOLOAD) :
{
*(TouchGFX_Framebuffer TouchGFX_Framebuffer.*)
*(.gnu.linkonce.r.*)
. = ALIGN(0x4);
} >SDRAM2
}
... What am I missing? Why does this work with the Dice Animation program but mine goes absolutely insane?
Something occurred to me while I was typing this so decided to go test it. My build environment has a newer version of objcopy than Touchgfx. I manually ran it through the TouchGFX version of the program and the absolutely bonkers addresses are gone... so I guess I can work around it by specifically calling that one. However, I still get the "symbol `textsGb' required but not present" error, so that doesn't completely resolve my problem. Anyone have any ideas?
... What are the chances that this is caused by the fact that I'm using an old version of GCC, 10.3.1 and TouchGFX is using an absolutely ancient version of GCC, 7.3.1? Side note, why is TouchGFX using such an old version of GCC?
Update: Not a function of GCC version. Just hacked my build setup so that it called the TouchGFX binaries and I still get the same symbol missing.
Solved! Go to Solution.
2025-03-28 7:22 AM - edited 2025-03-28 7:23 AM
Well, finally lucked into a solution, so figured I'd share it just in case someone else stumbles across the same type of issue.
Instead of removing the section, mark it as noload
arm-none-eabi-objcopy.exe --set-section-flags ExtFlashSection=noload --set-section-flags TextFlashSection=noload
It seems like this should be doing the exact same thing as this:
ExtFlashSection (NOLOAD) :
{
ExtThirdPartyHeader = .;
KEEP(*(.ExtFlashSection));
ExtThirdPartyHeader_end = .;
} >QSPI
TextFlashSection (NOLOAD) :
{
ExtThirdPartyHeader = .;
KEEP(*(.TextFlashSection));
ExtThirdPartyHeader_end = .;
} >QSPI
but I tried every variation of that I could think of and the linker ended up just trying to put everything that was in QSPI into internal flash.
I do not know why adding the 'noload' section after the fact works and doing it before hand breaks it... but at this point I don't care. It works and I can finally move onto something else :)
2025-03-28 7:22 AM - edited 2025-03-28 7:23 AM
Well, finally lucked into a solution, so figured I'd share it just in case someone else stumbles across the same type of issue.
Instead of removing the section, mark it as noload
arm-none-eabi-objcopy.exe --set-section-flags ExtFlashSection=noload --set-section-flags TextFlashSection=noload
It seems like this should be doing the exact same thing as this:
ExtFlashSection (NOLOAD) :
{
ExtThirdPartyHeader = .;
KEEP(*(.ExtFlashSection));
ExtThirdPartyHeader_end = .;
} >QSPI
TextFlashSection (NOLOAD) :
{
ExtThirdPartyHeader = .;
KEEP(*(.TextFlashSection));
ExtThirdPartyHeader_end = .;
} >QSPI
but I tried every variation of that I could think of and the linker ended up just trying to put everything that was in QSPI into internal flash.
I do not know why adding the 'noload' section after the fact works and doing it before hand breaks it... but at this point I don't care. It works and I can finally move onto something else :)