Showing results for 
Search instead for 
Did you mean: 

Why can I not program more 470KB into external memory with STM32_Programmer_CLI?

Associate II

I created a custom external loader to work with STM32H7A3ZG and NOR flash S29GL512S11 (64MB memory, 512 sectors with 128KB. Each sector is divided by pages with 512B size.

With STM32CubeProgrammer I can erase all chip, sector erase, read all memory and write a word in specific address, but I cannot flash files bigger than 470KB into the external memory. It means, after I try to write files bigger than 470KB, only the first part of the file was wrote correctly into the memory.

My Dev_Inf.h is:

#include "Dev_Inf.h"
/* This structure containes information used by ST-LINK Utility to program and erase the device */
#if defined (__ICCARM__)
__root struct StorageInfo const StorageInfo  =  {
struct StorageInfo const StorageInfo  =  {
   "S29GL512S11_BOARD", 	// Device Name + version number
   NOR_FLASH,                      // Device Type
   0x60000000,                        // Device Start Address
   0x4000000,                 	        // Device Size in Bytes 64MBytes
   0x00000200,                 	// Programming Page Size 512 Bytes
   0xFF,                       		// Initial Content of Erased Memory
// Specify Size and Address of Sectors (view example below)
   0x00000200, 0x00020000,

My linker file is like:

**  File        : linker.ld
**                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
/* Entry Point */
/* Generate 2 segment for Loader code and device info */
PHDRS {Loader PT_LOAD ; SgInfo PT_LOAD ; }
/* Highest address of the user mode stack */
_estack = ORIGIN(RAM_D1) + LENGTH(RAM_D1);    /* 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 */
	RAM_D1 (xrw)      : ORIGIN = 0x24000000, LENGTH = 512K
/* Define output sections */
  /* The startup code goes first into FLASH */
  .isr_vector :
  	. = . + 0x1FC;
    . = ALIGN(4);
    KEEP(*(.isr_vector)) /* Startup code */
    . = ALIGN(4);
  } >RAM_D1 :Loader
 .ARM.extab   : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >RAM_D1
  .ARM : {
    __exidx_start = .;
    __exidx_end = .;
  } >RAM_D1 :Loader
  .preinit_array     :
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP (*(.preinit_array*))
    PROVIDE_HIDDEN (__preinit_array_end = .);
  } >RAM_D1 :Loader
  .init_array :
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT(.init_array.*)))
    KEEP (*(.init_array*))
    PROVIDE_HIDDEN (__init_array_end = .);
  } >RAM_D1 :Loader
  .fini_array :
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP (*(SORT(.fini_array.*)))
    KEEP (*(.fini_array*))
    PROVIDE_HIDDEN (__fini_array_end = .);
  } >RAM_D1 :Loader
  /* 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_D1 :Loader
  /* 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;
    . = ALIGN(4);
    _ebss = .;         /* define a global symbol at bss end */
    __bss_end__ = _ebss;
  } >RAM_D1 :Loader
  /* 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 */
    KEEP (*(.init))
    KEEP (*(.fini))
    . = ALIGN(4);
    _etext = .;        /* define a global symbols at end of code */
  } >RAM_D1 :Loader
    .Dev_info :
	KEEP(*Dev_Inf.o ( .rodata* ))
  } :SgInfo
  /* Constant data goes into FLASH */
  .rodata :
    . = ALIGN(4);
    *(.rodata)         /* .rodata sections (constants, strings, etc.) */
    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
    . = ALIGN(4);
  } >RAM_D1 :Loader
  /* User_heap_stack section, used to check that there is enough RAM left */
  ._user_heap_stack :
    . = ALIGN(4);
    PROVIDE ( end = . );
    PROVIDE ( _end = . );
    . = . + _Min_Heap_Size;
    . = . + _Min_Stack_Size;
    . = ALIGN(4);
  } >RAM_D1 :Loader
  .ARM.attributes 0 : { *(.ARM.attributes) }

And I follow the instructions from

I tried to split the file in smaller ones, and flash it one by one and everything work good, but don't work if I try to flash one entire file in once time.

Anyone had this issue before?

Best regards,



>>Anyone had this issue before?

Every time I touch these things I have issues..

I've used the CLI to write and validate 64MB images in the past. Quirky behaviours are not entirely consistent between GUI and CLI versions.

I would recommend instrumenting your loader so you can get side-channel information out of an available serial port to understand the exact nature of the issue. How the functions are being called, and the parameters. Generate a log, at level 3, it helps to understand what's happening.

What ST normally does is use the remaining available SRAM, less the loader size, as a ping-pong buffer such that as you write one portion to the QSPI from your code, it's using the SWD in the background to fill the next buffer. Perhaps it's just using one, although I've seen examples where they call for every sector/page, rather than let the abstraction deal with the device level details.

The basis of the loader should be 0x24000004 for the H7's

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Associate II

Thanks for your reply 🙂

I try to configure the UART to send messages with the size of each package to be write on NOR memory, but the external bootloader if I have HAL_UART_Transmit() in the code the external loader stop working at all. If the code only have the configuration of UART everything work well, but not with the prints.

On my solution I'm using a NOR memory that use FMC module. The most strange thing that the using the CLI or the GUI versions, the program only write exactly half file in the memory with files bigger that around 400KB. I made three tests:

Flash 384KB - All file was wrote correctly in the memory

Flash 815KB(833788 B) - Only until the byte 416924 was wrote and verified.

Flash 941KB(964544 B) - Only until the byte 482272 was wrote and verified.

I don't have a sure, but I think the problem came from the way that STMProgrammer handle the files.

About the linker file, I had before with the address 0x24000004 like the example on gitlab, but the external loader work with the booth start address.

I will continue try to search what can create this issue.