2022-07-06 07:49 AM
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?
Solved! Go to Solution.
2022-07-08 02:06 AM
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.
2022-07-11 12:22 AM
Following words may be wrong? IntFlashSection is apparently not SPI memory, just a hint.
2022-07-11 12:28 AM
It seems not a problem. I tried to remove the IntFlashSection from the OCTOSPI but doesn't work.
2022-07-11 02:38 AM
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?
2022-07-11 07:05 AM
It was unchecked, but checking it doesn't resolve the problem.
2022-07-12 07:30 AM