Project is currently on hold…
I noticed the “External Loader” entry in the ST-LINK utility and wondered how to write a custom external loader plug-in for ST-LINK. The “STM32 ST-LINK Utility software description user Manual” UM0892 has a tiny section 3.9 dedicated to
“Developing custom loaders for external memory”
I have found out by searching the internet that a custom loader is just a library in the ELF format.
Currently I’m collecting info about how to write and build a custom loader, I’ll use Eclips + GCC a STM32F030 and a W25Q32 SPI FLASH memory.
notes:
The loader applet is an ELF object, with specific function/variable names (symbols) which ST’s loader is expecting. It payloads your code into RAM, and then calls you to initialize your hardware (processor clocks, PLL, pins, SPI, etc), and then with data buffers it provides expects you to Read or Write blocks of data to your device, or Erase/Mass Erase, etc. The ST tools are responsible to get your code into memory, and the pattern buffers in/out, and your code is responsible to deal with your hardware as it presents on the device.
LINKER:
Running programs from SRAM
==========================
You can run your firmware directly from SRAM if you want to. Just link it at 0x20000000 looking at the Keil linker configuration: the FlashLoader starts at address 0x20000004
FLASH_LOADER 0x20000004 PI ; FlashLoader Functions { PrgCode +0 ; Code { * (+RO) } PrgData +0 ; Data { * (+RW,+ZI) } } DEVICE_INFO +0 ; Device Info { DevInfo +0 ; Info structure { dev_inf.o } }
I would like to target a Cortex M0 with 4K SRAM so there is not much room for the loader application code + data buffers.
assumptions:
- databuffer size = pagesize = 256 bytes?
API:
operations:
- Init
- Read
- Write
- MassErase
- SectorErase
- Verify
Dev_inf.h
#define MCU_FLASH 1 #define NAND_FLASH 2 #define NOR_FLASH 3 #define SRAM 4 #define PSRAM 5 #define PC_CARD 6 #define SPI_FLASH 7 #define I2C_FLASH 8 #define SDRAM 9 #define I2C_EEPROM 10 #define SECTOR_NUM 10 // Max Number of Sector types struct DeviceSectors { unsigned long SectorNum; // Number of Sectors unsigned long SectorSize; // Sector Size in Bytes }; struct StorageInfo { char DeviceName[100]; // Device Name and Description unsigned short DeviceType; // Device Type: ONCHIP, EXT8BIT, EXT16BIT, ... unsigned long DeviceStartAddress; // Default Device Start Address unsigned long DeviceSize; // Total Size of Device unsigned long PageSize; // Programming Page Size unsigned char EraseValue; // Content of Erased Memory struct DeviceSectors sectors[SECTOR_NUM]; };
Dev_inf.c
#include "Dev_Inf.h" /* This structure containes information used by ST-LINK Utility to program and erase the device */ struct StorageInfo const StorageInfo = { "W25Q32_STM32F0_SPI1", // Device Name + version number SPI_FLASH, // Device Type 0x00000000, // Device Start Address 0x00400000, // Device Size in Bytes 4MBytes/32Mbits) 0x00000100, // Programming Page Size 256 Bytes 0xFF, // Initial Content of Erased Memory // Specify Size and Address of Sectors 0x00000040, // Sector Num : 64 0x00010000, // Sector Size: 64KBytes 0x00000000, // ? 0x00000000, // ? };
Loader_Src.c
#include "stm32f03x.h" #include "stm32_spi_flash.h" #include "board_layout.h" /******************************************************************************************** * Description : * Initilize the MCU Clock, the GPIO Pins corresponding to the * device and initilize the FSMC with the chosen configuration * Inputs : * None * outputs : * "1" : Operation succeeded * "0" : Operation failure * Note: Mandatory for all types of device *********************************************************************************************/ int Init (void) { SystemInit(); sFLASH_Init(); return 1; } /******************************************************************************************** * Description : * Read data from the device * Inputs : * Address : Read location * Size : Length in bytes * buffer : Address where to write readed data * outputs : * "1" : Operation succeeded * "0" : Operation failure * Info : * Alignment and Data size (32/16/8 bits) should be handled in this function * Note : Not Mandatory for SRAM PSRAM and NOR_FLASH *********************************************************************************************/ int Read (uint32_t Address, uint32_t Size, uint8_t* buffer) { sFLASH_ReadBuffer(buffer, Address, Size); return 1; } /******************************************************************************************** * Description : * Write data to the device * Inputs : * Address : Write location * Size : Length in bytes * buffer : Address where to get the data to write * outputs : * "1" : Operation succeeded * "0" : Operation failure * Info : * Alignment and Data size (32/16/8 bits) should be handled in this function * Note : Mandatory for all types except SRAM and PSRAM *********************************************************************************************/ int Write (uint32_t Address, uint32_t Size, uint8_t* buffer) { sFLASH_WriteBuffer(buffer, Address, Size); return 1; } /******************************************************************************************** * Description : * Full erase of the device * Inputs : * None * outputs : * "1" : Operation succeeded * "0" : Operation failure * Info : * Note : Not Mandatory for SRAM PSRAM and NOR_FLASH *********************************************************************************************/ int MassErase (void) { sFLASH_EraseBulk(); return 1; } /******************************************************************************************** * Description : * Erase a full sector in the device * Inputs : * SectrorAddress : Start of sector * outputs : * "1" : Operation succeeded * "0" : Operation failure * Note : Not Mandatory for SRAM PSRAM and NOR_FLASH *********************************************************************************************/ int SectorErase (uint32_t EraseStartAddress ,uint32_t EraseEndAddress) { EraseStartAddress = EraseStartAddress - EraseStartAddress%0x10000; while (EraseEndAddress>=EraseStartAddress) { sFLASH_EraseSector(EraseStartAddress); EraseStartAddress += 0x10000; } return 1; } /******************************************************************************************** * Description : * Initilize the MCU Clock, the GPIO Pins corresponding to the * device and initilize the FSMC with the chosen configuration * Inputs : * FlashAddr : Flash address * RAMBufferAddr : RAM buffer address * Size : Size (in WORD) * outputs : * "0" : Operation succeeded * address of failure : Operation failed (address of failure) * Note: Optional for all types of device ********************************************************************************************/ int Verify (uint32_t MemoryAddr, uint32_t RAMBufferAddr, uint32_t Size) { uint32_t VerifiedData = 0; uint8_t TmpBuffer = 0x00; Size*=4; while (Size>VerifiedData) { sFLASH_ReadBuffer(&TmpBuffer, MemoryAddr+VerifiedData, 1); if (TmpBuffer != *((uint8_t*)RAMBufferAddr+VerifiedData)) return MemoryAddr+VerifiedData; VerifiedData++; } return 0; }
Hi ,,,
Thanks for the very nice article ,, Heart-fully appreciated it.. Can you please help me to understand ,,
a) Without main.c how I can compile this program,
b) As I checked the STLink / External Directory :- There were file named “.STLDR” ( will this file be generated on compiling the program )
c) How can I control STlink ,, lets say that I need to write multiple files at multiple locations for the NOR Flash..
The micro controller that I’m using at present is NUCLEO-F411 , Nor Flash is from micron,, and IDE is Keil
Thanks in advance
LikeLike
I have not finished this project, An example program can be found when installing the ST-Link utility. I’ve used the Atollic example, I did not find a main entry. I have not compiled the example yet.
LikeLike
HI Maurits,
Have you made any progress on this project ?
I have to write an axternal loader for a custom board based on a STM32F7 MCU and I’m totally struggling. As you say, the manual section is really tiny and there are many areas not very clear to me. First of all : How do I generate an output file ?
Thx
LikeLike
The output needs to be an elf file. The st-link utility contains example projects for Atolic and Keil. I have not investigated this any further. Did you find those examples?
LikeLike
Thx for the answer.
How do I generate the elf file ?
There are 4 examples :
– one for a STM32L4 MCU board
– 3 for a STM32F10 MCU boards
The L4 one is not avaible for any toolchain. It’s really too bad because the file structure is the very same as the STM32F7 MCU (which I use).
The F10 ones work with keil, but are not relevant about how I have to build the project. Firstely, It seems to be impossible to install the adequate packs .
Then, the file structure is different and I can’t compile them. So they not very usefull to me for understanding how they are supposed to be compiled.
However they help in understanding the whole file structure (but wasn’t the most difficult part^^)
LikeLike