cancel
Showing results for 
Search instead for 
Did you mean: 

OSPI external loader fails to read/write (linker issue?) on STM32H7A3 MCU

Emilmart
Senior

Hi everyone,

I’m working on a custom display board with a STM32H7A3 MCU and a MX66LM1G45G 128Mb OSPI flash. I have build a custom external loader following ST tutorial, with H7 params. I use JTAG to flash.

When it comes to use my .stldr custom loader in CubeIDE or CubeProgrammer (v2.7), it fails.

Here’s what’s CubeProgrammer says when I try to flash my .bin app (touchgfx project) using the external loader:

[…]

w ap 0 @0x90000000 0x000D083C bytes Data 0x00000000 // Error: failed to download Segment[1]

With CubeIDE using the external loader, it also fails at Segment[1]

(see full logs attached)

When I try to read a data at 0x90000000 with CubeProgrammer, it also fails (see file log_cubeprogrammer_ReadData.log attached)

I have successfully tested my OSPI functions in the main.c of the external loader (writing/reading/erasing) on my board (without the external loader linker modifications).

In my TouchGFX applicative project I implemented the same OSPI functions and was also able to read datas in memory mapped mode.

I’m not sure about the linker part in my external loader, and my guess is that the problem comes from there. I’m not sure at which adress I should store the external loader code, considering that my STM32H7A3 has some AXI_SRAM (0x24000000)/ AHB_SRAM (0x30000000) by default in STM32H7A3ZITX_FLASH.ld. The RAM is at 0x20000000 in this linker and is only 128KB (not enough for the external loader code), so in the end I followed the example for the H7 which says to store the loader code at 0x24000004 (same RAM origin and size than my TouchGFX project though).

With that linker config I’m able to go at the end of my system Initialisation (Init()) in Loader_Src.c in debug mode.

It may not be that but here are my linkers for the external loader and for the TouchGFX project:

external loader linker:

/* Entry Point */
ENTRY(Init)
 
/* 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_D1 */
/* Generate a link error if heap and stack don't fit into RAM_D1 */
_Min_Heap_Size = 0x1000 ;      /* required amount of heap  */
_Min_Stack_Size = 0x1000 ; /* required amount of stack */
 
/* Specify the memory areas */
MEMORY
{
	RAM_D1 (xrw)      : ORIGIN = 0x24000004, LENGTH = 1024K
}								
 
/* Define output sections */
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 = .;
    *(.ARM.exidx*)
    __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_D1, 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;
    *(.bss)
    *(.bss*)
    *(COMMON)
 
    . = 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 */
    *(.eh_frame)
 
    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_D1 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) }
}

TouchGFX project linker:

ENTRY(Reset_Handler)
 
_estack = ORIGIN(RAM) + LENGTH(RAM);	/* end of "RAM" Ram type memory */
 
_Min_Heap_Size = 0x1000 ;	/* required amount of heap  */
_Min_Stack_Size = 0x1000 ;	/* required amount of stack */
 
MEMORY
{
  DTCMRAM    (xrw)    : ORIGIN = 0x20000000,   LENGTH = 128K
  ITCMRAM    (xrw)    : ORIGIN = 0x00000000,   LENGTH = 64K
  RAM    (xrw)    : ORIGIN = 0x24000000,   LENGTH = 1024K
  FLASH    (rx)    : ORIGIN = 0x8000000,   LENGTH = 2048K
  OCTOSPI (r)    : ORIGIN = 0x90000000, LENGTH = 128M
}
 
/* Sections */
SECTIONS
{
  /* The startup code into "FLASH" Rom type memory */
  .isr_vector :
  {
    . = ALIGN(4);
    KEEP(*(.isr_vector)) /* Startup code */
    . = ALIGN(4);
  } >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 into "FLASH" Rom type memory */
  .rodata :
  {
    . = ALIGN(4);
    *(.rodata)         /* .rodata sections (constants, strings, etc.) */
    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
    . = ALIGN(4);
  } >FLASH
 
  .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 */
 
    . = ALIGN(4);
    _edata = .;        /* define a global symbol at data end */
 
  } >RAM AT> FLASH
 
  . = 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
 
  ._user_heap_stack :
  {
    . = ALIGN(8);
    PROVIDE ( end = . );
    PROVIDE ( _end = . );
    . = . + _Min_Heap_Size;
    . = . + _Min_Stack_Size;
    . = ALIGN(8);
  } >RAM
 
  /DISCARD/ :
  {
    libc.a ( * )
    libm.a ( * )
    libgcc.a ( * )
  }
 
  .ARM.attributes 0 : { *(.ARM.attributes) }
  ExtFlashSection :
  {
	*(ExtFlashSection ExtFlashSection.*)
	*(.gnu.linkonce.r.*)
    . = ALIGN(0x4);
  } >OCTOSPI
	
  FontFlashSection :
  {
	*(FontFlashSection FontFlashSection.*)
	*(.gnu.linkonce.r.*)
    . = ALIGN(0x4);
  } >OCTOSPI
 
  TextFlashSection :
  {
	*(TextFlashSection TextFlashSection.*)
	*(.gnu.linkonce.r.*)
    . = ALIGN(0x4);
   } >OCTOSPI
}

You will find my full external loader project here:

https://github.com/pa0694/External_loader

Thanks for your support !

15 REPLIES 15
GChau.2
Associate II

Hi @DMari.3​ , @Emilmart​ ,

If I modify entry point into linker file and startup file as follow I have the following result :

startup.s

linker.ld 

STM32 Programmer

If I let entry point as default (as mentionned into the tutorial), I have the following result :

startup.s

linker.ld

STM32 Programmer

So it is the same result. I can make full chip erase for external memory.

Could anyone share function Init, Write, SectorErase, MassErase please? I have used function given for BSP stm32h7b3i_discovery_ospi.c/.h modifying .h file pinout for my bord.

GChau.2
Associate II

Sorry picture were deleted when I publish my comment

Bellow the two cases :

startup.s :

/* Call the application's entry point.*/

 bl main

Or

/* Call the application's entry point.*/

 bl Init

linker.ld :

/* Entry Point */

ENTRY(Init)

Or

/* Entry Point */

ENTRY(Reset_Handler)

GChau.2
Associate II

Hi everyone,

If it can help somebody you can find here a repository with source code for external loaders : https://github.com/STMicroelectronics/stm32-external-loader

Freedom_Neo
Senior

Hi @Emilmart​ I have similir problem. Can you support me please?

I am using below development tools

MCU: STM32H7B3IIT6

IDE: STM32CubeIDE Version: 1.8.0

GUI: TouchGFX Version: 4.18.1

SDRAM: IS45S16800F-7CTLA1-TR

FLASH: MX25LM51245GMI00

I have failure detail below.

0693W00000Kbom9QAB.png 

Do you have any solution? I need your support.

GChau.2
Associate II

Hi,

I had similar issue, sinced I am using ST/LINK V2 instead of nucleo SWD it works for me using the same external loader.

Hope it could help you.

Best regards