cancel
Showing results for 
Search instead for 
Did you mean: 

External loader fails to download

nikof
Associate II

Hi all,

I'm trying to put some TouchGFX data (images, text, ...) in an external flash (S25FL128L) on a custom board with STM32H7B0VB mcu. I'm using the octo-spi peripheral as quad-spi.

So, I followed the guide to make an external loader and I did it. It seems to work properly: if I load the .stdlr file in the STM32CubeProgrammer I can read, write, erase sector and mass erase the external flash.

Also, if I try to debug (STM32CubeIDE) a project using the loader without putting elements into external flash all works well and I can see all the memory locations.

The ploblem occur whe I try to put somenthing inside the external flash. I do that in the linker script with TouchGFX sections: IntFlashSection and TextFlashSection. See the script below:

/* Entry Point */
ENTRY(Reset_Handler)
 
/* Highest address of the user mode stack */
_estack = 0x20020000;    /* 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
{
  FLASH (rx)      : ORIGIN = 0x08000000, LENGTH = 2048K
  RAM   (xrw)     : ORIGIN = 0x20000000, LENGTH = 128K
  AXI_SRAM (xrw)  : ORIGIN = 0x24000000, LENGTH = 1024K
  AHB_SRAM (xrw)  : ORIGIN = 0x30000000, LENGTH = 128K
  OCTOSPI (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 */
    *(.RamFunc)        /* .RamFunc sections */
    *(.RamFunc*)       /* .RamFunc* 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) }
 
    IntFlashSection :
  	{
  		*(IntFlashSection IntFlashSection.*)
  		*(.gnu.linkonce.r.*)
  		. = ALIGN(0x4);
  	} >OCTOSPI
 
    TextFlashSection :
  	{
  		*(TextFlashSection TextFlashSection.*)
  		*(.gnu.linkonce.r.*)
  		. = ALIGN(0x4);
  	} >OCTOSPI
 
}

The output of the console when I try to Debug or Run with this linker script is:

STMicroelectronics ST-LINK GDB server. Version 6.1.0
Copyright (c) 2022, STMicroelectronics. All rights reserved.
 
Starting server with the following options:
        Persistent Mode            : Disabled
        Logging Level              : 1
        Listen Port Number         : 61234
        Status Refresh Delay       : 15s
        Verbose Mode               : Disabled
        SWD Debug                  : Enabled
        InitWhile                  : Enabled
 
Waiting for debugger connection...
Debugger connected
Waiting for debugger connection...
Debugger connected
Waiting for debugger connection...
      -------------------------------------------------------------------
                       STM32CubeProgrammer v2.10.0                  
      -------------------------------------------------------------------
 
 
 
Log output file:   c:\users\niko~1.fio\appdata\local\temp\stm32cubeprogrammer_a14888.log
ST-LINK SN  : 34FF74065250343847111043
ST-LINK FW  : V2J39S7
Board       : --
Voltage     : 3.23V
SWD freq    : 4000 KHz
Connect mode: Under Reset
Reset mode  : Hardware reset
Device ID   : 0x480
Revision ID : Rev Z
Device name : STM32H7A/B
Flash size  : 128 KBytes
Device type : MCU
Device CPU  : Cortex-M7
BL Version  : 0x90
 
 
 
Memory Programming ...
Opening and parsing file: st-link_gdb_server_a14888.srec
  File          : st-link_gdb_server_a14888.srec
  Size          : 694.94 KB 
  Address       : 0x08000000 
 
 
Erasing memory corresponding to segment 0:
Erasing internal memory sectors [0 32]
Erasing memory corresponding to segment 1:
Erasing external memory sectors [0 108]
Download in Progress:
 
 
Error: failed to download Segment[0]
Error: failed to download the File
Shutting down...
Exit.

I dont't know how to solve this. Any ideas?

15 REPLIES 15
nikof
Associate II

I made the loader following this guide:

https://www.youtube.com/watch?v=XqCq0xtQmbI&t=505s

The source code of this is available in this repo:

https://github.com/STMicroelectronics/stm32-external-loader/tree/contrib

These are my functions defined in Loader_Src.c file:

int
Init(void) {
 
    *(uint32_t*)0xE000EDF0 = 0xA05F0000; //enable interrupts in debug
 
 
    SystemInit();
	//__disable_irq();
 
    /* ADAPTATION TO THE DEVICE
     *
     * change VTOR setting for H7 device
     * SCB->VTOR = 0x24000000 | 0x200;
     *
     * change VTOR setting for other devices
     * SCB->VTOR = 0x20000000 | 0x200;
     *
     * */
 
    SCB->VTOR = 0x24000000 | 0x200;
 
    //__set_PRIMASK(0); //enable interrupts
 
    HAL_Init();
 
    SystemClock_Config();
 
    MX_GPIO_Init();
 
    __HAL_RCC_OSPI1_FORCE_RESET();		//completely reset peripheral
    __HAL_RCC_OSPI1_RELEASE_RESET();
 
    if (LDR_QUADSPI_Init() != HAL_OK) {
        __set_PRIMASK(1); //disable interrupts
        return LOADER_FAIL;
    }
 
 
    if (CSP_QSPI_EnableMemoryMappedMode() != HAL_OK) {
        __set_PRIMASK(1); //disable interrupts
        return LOADER_FAIL;
    }
 
    /*Trigger read access before HAL_QSPI_Abort() otherwise abort functionality gets stuck*/
    uint32_t a = *(uint32_t*) 0x90000000;
    a++;
 
    __set_PRIMASK(1); //disable interrupts
    return LOADER_OK;
}
 
/**
 * @brief   Program memory.
 * @param   Address: page address
 * @param   Size   : size of data
 * @param   buffer : pointer to data buffer
 * @retval  LOADER_OK = 1       : Operation succeeded
 * @retval  LOADER_FAIL = 0 : Operation failed
 */
int
Write(uint32_t Address, uint32_t Size, uint8_t* buffer) {
 
    //__set_PRIMASK(0); //enable interrupts
 
    if (HAL_OSPI_Abort(&hospi1) != HAL_OK) {
        __set_PRIMASK(1); //disable interrupts
        return LOADER_FAIL;
    }
 
    if (CSP_QSPI_Write((uint8_t*) buffer, (Address & (0x0fffffff)), Size) != HAL_OK) {
        __set_PRIMASK(1); //disable interrupts
        return LOADER_FAIL;
    }
 
    __set_PRIMASK(1); //disable interrupts
    return LOADER_OK;
}
 
/**
 * @brief   Read memory. (not mandatory)
 * @param   Address: page address
 * @param   Size   : size of data
 * @param   buffer : pointer to data buffer
 * @retval  LOADER_OK = 1       : Operation succeeded
 * @retval  LOADER_FAIL = 0 : Operation failed
 */
int
Read(uint32_t Address, uint32_t Size, uint8_t* buffer) {
 
	int i = 0;
 
    //__set_PRIMASK(0); //enable interrupts
 
    if (HAL_OSPI_Abort(&hospi1) != HAL_OK) {
		__set_PRIMASK(1); //disable interrupts
		return LOADER_FAIL;
	}
 
    if (CSP_QSPI_EnableMemoryMappedMode() != HAL_OK) {
        __set_PRIMASK(1); //disable interrupts
        return LOADER_FAIL;
    }
 
    for (i=0; i < Size;i++)
	{
		*(uint8_t*)buffer++ = *(uint8_t*)Address;
		Address ++;
	}
 
    __set_PRIMASK(1); //disable interrupts
    return LOADER_OK;
}
 
/**
 * @brief   Sector erase.
 * @param   EraseStartAddress :  erase start address
 * @param   EraseEndAddress   :  erase end address
 * @retval  LOADER_OK = 1       : Operation succeeded
 * @retval  LOADER_FAIL = 0 : Operation failed
 */
int
SectorErase(uint32_t EraseStartAddress, uint32_t EraseEndAddress) {
 
    //__set_PRIMASK(0); //enable interrupts
 
    if (HAL_OSPI_Abort(&hospi1) != HAL_OK) {
        __set_PRIMASK(1); //disable interrupts
        return LOADER_FAIL;
    }
 
    if (CSP_QSPI_EraseSector(EraseStartAddress, EraseEndAddress) != HAL_OK) {
        __set_PRIMASK(1); //disable interrupts
        return LOADER_FAIL;
    }
 
    __set_PRIMASK(1); //disable interrupts
    return LOADER_OK;
}
 
/**
 * Description :
 * Mass erase of external flash area
 * Optional command - delete in case usage of mass erase is not planed
 * Inputs    :
 *      none
 * outputs   :
 *     none
 * Note: Optional for all types of device
 */
int
MassErase(void) {
 
    //__set_PRIMASK(0); //enable interrupts
 
    if (HAL_OSPI_Abort(&hospi1) != HAL_OK) {
        __set_PRIMASK(1); //disable interrupts
        return LOADER_FAIL;
    }
 
    if (CSP_QSPI_Erase_Chip() != HAL_OK) {
        __set_PRIMASK(1); //disable interrupts
        return LOADER_FAIL;
    }
 
    __set_PRIMASK(1); //disable interrupts
    return LOADER_OK;
}

I tried to disable interrupts but nothing changed.

Also, in the guide there is a testing file for external flash. Downloading this file into ext flash (starting from 0x90000000) works well. Like you said I think the problem occurs when I need to switch between internal and external loader.

So, following your suggestion it seems to be a problem of RAM.

Xzhiy.1
Associate II

Following words may be wrong? IntFlashSection is apparently not SPI memory, just a hint.

  1. IntFlashSection :
  2. {
  3. *(IntFlashSection IntFlashSection.*)
  4. *(.gnu.linkonce.r.*)
  5. . = ALIGN(0x4);
  6. } >OCTOSPI

nikof
Associate II

It seems not a problem. I tried to remove the IntFlashSection from the OCTOSPI but doesn't work.

This could be because you need to initialize the external loader in your debug configuration inside STM32CubeIDE.

Do you know if this checkbox is checked?

0693W00000QKqWcQAL.png

It was unchecked, but checking it doesn't resolve the problem.

Sara BEN HADJ YAHYA
ST Employee

Hello,

Please check N. SANTINI comment in this thread.

Sara.