STM32H743 .bin file is enormous
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2021-10-06 5:49 AM
Hi !
I'm used to working with F4 and F7 devices, and I've always made '.bin' files to distribute the firmware upgrades, which can be flashed via a custom bootloader, directly on the board, from an SD card.
With my current project however, on a STM32H743BI, the generated '.bin' file is almost 700MiB in size!
My two questions are:
- How come this is so big ? Does this have to do with the H7 memory mapping ?
- What reasonable options do I have ? Can '.hex' files be as easily read and written to FLASH memory ? Should I rather generate several '.bin' files to split sections ?
Here's my linkerscript for reference:
ENTRY(Reset_Handler)
STACK_SIZE = 0x8000;
/* Non cacheable RAM for DMA
This can be adjusted as needed
*/
DMA_RAM_SIZE = 32k;
MIN_HEAP_SIZE = 0x2000; /* required amount of heap */
BOOTLOADER_SIZE = 256k;
FLASH_ORIGIN = 0x08000000;
/* Specify the memory areas */
MEMORY
{
bootloader (rx) : ORIGIN = FLASH_ORIGIN, LENGTH = BOOTLOADER_SIZE
FLASH (rx) : ORIGIN = FLASH_ORIGIN + BOOTLOADER_SIZE, LENGTH = 2048K - BOOTLOADER_SIZE
DTCMRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
DMA_RAM (xrw) : ORIGIN = 0x24000000, LENGTH = DMA_RAM_SIZE
RAM (xrw) : ORIGIN = 0x24000000 + DMA_RAM_SIZE, LENGTH = 512K - DMA_RAM_SIZE
RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 288K
RAM_D3 (xrw) : ORIGIN = 0x38000000, LENGTH = 64K
ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K
SDRAM (xrw) : ORIGIN = 0xC0000000, LENGTH = 32M
}
/* Define output sections */
SECTIONS
{
/* created for EXTERNAL SDRAM allocation */
.external_ram (NOLOAD) :
{
. = ALIGN(4);
*(.external_ram)
*(.external_ram*)
. = ALIGN(4);
} >SDRAM
.dma_ram :
{
. = ALIGN(4);
*(.)
*(.dma_ram*)
. = ALIGN(4);
} >DMA_RAM
.ram_d2 :
{
. = ALIGN(4);
*(.ram_d2)
*(.ram_d2*)
. = ALIGN(4);
} >RAM_D2
.ram_d3 :
{
. = ALIGN(4);
*(.ram_d3)
*(.ram_d3*)
. = ALIGN(4);
} >RAM_D3
.dtcmram :
{
. = ALIGN(4);
*(.dtcmram)
*(.dtcmram*)
. = ALIGN(4);
} >DTCMRAM
/* 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
/* Copy specific fast-executing code to ITCM RAM */
itcm_data = LOADADDR(.itcm_text);
.itcm_text :
{
. = ALIGN(4);
itcm_text_start = .;
*(.itcm_text)
*(.itcm_text*)
. = ALIGN(4);
itcm_text_end = .;
} >ITCMRAM 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
/* Stack section in RAM, it must be 8-byte aligned. */
.stack (NOLOAD):
{
. = ALIGN(8);
_sstack = .;
. = . + STACK_SIZE;
. = ALIGN(8);
_estack = .;
} > DTCMRAM
/* User_heap section, used to check that there is enough RAM left */
._user_heap :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + MIN_HEAP_SIZE;
. = ALIGN(8);
} >RAM
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
}
The 'bin' file is made with the simplest command:
arm-none-eabi-objcopy -O binary firmware.elf firmware.bin
Thanks for your time and help
Solved! Go to Solution.
- Labels:
-
Flash
-
STM32CubeProgrammer
-
STM32H7 series
Accepted Solutions
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2021-10-12 9:37 AM
For reference, I found the underlying issue. The sections I created to use the different RAM regions should have been marked NOLOAD.
I changed the linker script following this SO reply: https://stackoverflow.com/a/65577906/6386478
Now my sections look like this, for example:
/* .dtcmram contains value-initialized data, so we need to store that init data in flash at address _si_dtcmram */
.dtcmram (NOLOAD) :
{
. = ALIGN(4);
_s_dtcmram = .;
KEEP(*(.dtcmram))
. = ALIGN(4);
_e_dtcmram = .;
} >DTCMRAM AT> FLASH
_si_dtcmram = LOADADDR (.dtcmram);
/* .ram_d2 only contains data that needs to be zero-initialized, no need for flash storage */
.ram_d2 (NOLOAD) :
{
. = ALIGN(4);
_s_ram_d2 = .;
KEEP(*(.ram_d2))
. = ALIGN(4);
_e_ram_d2 = .;
} >RAM_D2
Then, following this guide: https://www.youtube.com/watch?v=7stymN3eYw0
I migrated the startup code from ASM to C, which made it way easier to initialize my custom sections, either with zeros or with init data stored in flash, for example:
void Reset_Handler(void)
{
//...
// Initialise .dtcmram section with data stored in flash
uint32_t* dtcmram_init = &_si_dtcmram;
uint32_t* _dtcmram = &_s_dtcmram;
while(_dtcmram < &_e_dtcmram) *_dtcmram++ = *dtcmram_init++;
//...
}
If that reply can save someone the few days I spent on this, it'll be worth it.
Cheers
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2021-10-06 5:58 AM
If you create a HEX, it will be considerably smaller because it can contain several blocks, each with a start address.
BIN files must contain everything in one block so that every memory hole in the address space is also mapped in the BIN.
Yes, HEX can be easily written to the Flash memory, e.g. using the STM32CubeProgrammer.
Regards
/Peter
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2021-10-06 5:59 AM
Hi,
Have had this too with some projects for STM32H743 and STM32L476.
Quick answer - Use the ELF or Hex files instead of BIN file (I prefer ELF, but your choice, extra debug data may be in ELF).
Long answer:
- It has something to do with extra sections defined in linker file
- We added some user defined sections for FLASH and RAM for "non-volatile" parameters for our design.
- Moving these sections to end of linker file fixed our STM32L476 BIN, but only made our STM32H743 BIN slightly less insane.
- I expect if you juggle the order of any sections you added to the default linker files it may fix your problem
- The BIN file generation seems to mistakenly be adding RAM areas to BIN according to order in linker file.
Alternative:
- don't define the extra sections in linker, hard code them as pointers instead (yuck!)
- share the ELF or HEX files instead of BIN files.
Paul
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2021-10-06 6:38 AM
Looks like you're only using FLASH to store data, as SDRAM is marked as NOLOAD. You should be able to create a BIN file for the new firmware that only contains contents for FLASH.
Look at the map file and figure out what data is being placed elsewhere and correct that.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2021-10-06 6:42 AM
Thanks for your replies, @Peter BENSCH​ & @Community member​ !
Using .hex seems like a reasonable solution, but would require that I write a hex parser to program the flash from the bootloader...
But it also seems like I could generate several .bin files for several sections. Do you have any clue as to which sections should be kept, and which should be dropped ?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2021-10-06 6:53 AM
Ah ! So my dedicated sections for RAM might need to be marked as NOLOAD as well, actually.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2021-10-06 7:40 AM
Shuffling the sections around, I was indeed able to shave 200MiB off, but the file is still 450MiB, so, as you said it's only "slightly less insane"...
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2021-10-12 9:37 AM
For reference, I found the underlying issue. The sections I created to use the different RAM regions should have been marked NOLOAD.
I changed the linker script following this SO reply: https://stackoverflow.com/a/65577906/6386478
Now my sections look like this, for example:
/* .dtcmram contains value-initialized data, so we need to store that init data in flash at address _si_dtcmram */
.dtcmram (NOLOAD) :
{
. = ALIGN(4);
_s_dtcmram = .;
KEEP(*(.dtcmram))
. = ALIGN(4);
_e_dtcmram = .;
} >DTCMRAM AT> FLASH
_si_dtcmram = LOADADDR (.dtcmram);
/* .ram_d2 only contains data that needs to be zero-initialized, no need for flash storage */
.ram_d2 (NOLOAD) :
{
. = ALIGN(4);
_s_ram_d2 = .;
KEEP(*(.ram_d2))
. = ALIGN(4);
_e_ram_d2 = .;
} >RAM_D2
Then, following this guide: https://www.youtube.com/watch?v=7stymN3eYw0
I migrated the startup code from ASM to C, which made it way easier to initialize my custom sections, either with zeros or with init data stored in flash, for example:
void Reset_Handler(void)
{
//...
// Initialise .dtcmram section with data stored in flash
uint32_t* dtcmram_init = &_si_dtcmram;
uint32_t* _dtcmram = &_s_dtcmram;
while(_dtcmram < &_e_dtcmram) *_dtcmram++ = *dtcmram_init++;
//...
}
If that reply can save someone the few days I spent on this, it'll be worth it.
Cheers
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2021-10-12 9:45 AM
See also
https://community.st.com/s/question/0D53W00000PpuUgSAJ/split-bin-in-multiple-regions
.HEX files tend to be 2.5x the size of data described by separate binaries. They are however not unduly difficult to build a loader around
.DFU files allow for multiple regions to be described in a binary object format, without all the clutter usually carted around by .ELF/.AXF formats
Up vote any posts that you find helpful, it shows what's working..
