on
2022-06-30
7:11 AM
- edited on
2025-08-04
1:05 AM
by
Laurids_PETERSE
Application that requires external memories to be manufactured with initial content can be very challenge to debug and become a heavy toll during the production cycle as usually one would need to use two programming process using different toolset, one for the external memory and another for program the STM32 internal flash memory. The STM32CubeProgrammer’s External Loader is a feature that allows a direct access to external memories by STM32CubeProgrammer and even by the STM32CubeIDE to read, program, and erase data without the use of any additional tool other than a regular STLINK and even without ever changing the internal flash memory of the STM32. It is a feasible way to accelerate the debug cycle and the manufacturing program process on applications that uses external memory.
This article main objective is to provide a step-by-step guide on how to develop your own External Loader to manage external memories. This demo implementation uses a NUCLEO-G070RB and simple SPI-Flash memory, but it can be easily tailored for another microcontrollers and memory types.
To develop this article’s demo, the following materials were necessary:
To directly access external memories without having to program the STM32 internal flash memory to host the driver and basic functions, the External Loader replies on loading all these needed functions in the STM32’s RAM. Then the STM32CubeProgrammer can freely access the RAM memory and thus calling these functions using the SWD communication, granting the STM32CubeProgrammer the capability to perform read, program, and erase processes.
The STM32CubeProgrammer already comes with all external loaders created for all our evaluation boards and respective memories, but you can add more memories according to your application. We need to create a project that executes all the management functions from the STM32’s RAM and this will require a custom linker file, a specific header, and function set in order to build a *.stldr file, which is the method used by the STM32CubeProg External Loader to map all the memory features. This *.stldr can be created using a compiler post-build and then manually added in the STM32CubeProgrammer and STM32CubeIDE program folder.
First, we need to create the External Loader with the drivers to manage our external memory, and setup that to run in RAM. So, let us create a project in STM32CubeIDE for the STM32G070RBT6 (NUCLEO-G070RB’s Microcontroller).
Configure the SPI according to the memory specifications, in this example a SPI flash memory is used:
The main code needs the peripheral initialization functions and later the driver for the memory, also, having the peripherals with individual source and header files make the project cleaner and easier to follow. To do this, go to Project Manager -> Code Generator and check the box “Generate peripheral initialization as a pair of ‘.c/.h’ files per peripheral”.
Then Generate the code clicking on “Device Configuration Tool Code Generation” or going to Project -> Generate Code.
Since we need that all the functions run from the RAM, the following changes are needed in the linker file - STM32G070RBTX_FLASH.ld:
/* Entry Point */ ENTRY(Init)
/* Generate 2 segment for Loader code and device info */ PHDRS {Loader PT_LOAD ; SgInfo PT_LOAD ; }
/* Memories definition */ MEMORY { RAM_D1 (xrw) : ORIGIN = 0x20000004, LENGTH = 36K-4 }
.isr_vector : { . = . + 0x1FC; /* ISR vector offset */ . = ALIGN(4); KEEP(*(.isr_vector)) /* Startup code */ . = ALIGN(4); } >RAM_D1 :Loader
/* Highest address of the user mode stack */ _estack = ORIGIN(RAM_D1) + LENGTH(RAM_D1); /* end of "RAM" Ram type memory */
/* The program code and other data into RAM type memory */ .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)) KEEP (*Loader_Src.o ( .text* )) . = ALIGN(4); _etext = .; /* define a global symbol at end of code */ } >RAM_D1 : Loader
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >RAM_D1
/* 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_D1 :Loader
.Dev_Info : { __Dev_info_START = .; *(.Dev_info*) KEEP(*(.Dev_info)) __Dev_info_END = .; } >RAM_D1 :SgInfo
Once all linker edit is completed it is time to import your custom external memory driver for the project. If you do not have one yet, you can use our knowledge base to learn how to create one.
The part 2 will show how to create the necessary files of the External Loader and the relationship between the STM32CubeProgrammer and the created project
See you soon!