Building a custom external loader for ST-LINK

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.

STM32F030Fx_SPI_loader

notes:

ST Forum – custom loader

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;
}

This entry was posted in STM32. Bookmark the permalink.

5 Responses to Building a custom external loader for ST-LINK

  1. N9t_Reck3r says:

    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

    Like

  2. Maurits van de Lande says:

    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.

    Like

  3. EnimA says:

    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

    Like

    • 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?

      Like

      • EnimA says:

        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^^)

        Like

Leave a comment