ARM Cortex-M Scatter Loading Working Example
-Aviral Mittal avimit att yahu dat cam.
https://www.linkedin.com/in/avimit/
SITE HOME

Scatter-Loading Working Example.
In the Previous Section, we learned the theory part of the scatter loading and about XIP.
Let us now look at a very small practical self-contained example use of scatter-loading.
The objective here is to place a user defined function called 'add' at a specific location in the memory say at 0x3000_0000, using Scatter-loading mechanism.
We will need the following:
You can use any target processor to compile/link these files, we will use cortex-m3 as the processor.

The 'main.c' will declare a 'extern' function called 'add'. The full code for the 'add' function will be present in separate file called 'add.c'.
We will compile the file 'main.c' and 'add.c' separately to produce the respective object files 'c.o' and 'add.o'.
We will then compile the 'startup.s' file separately to produce the object file 'a.o'
We will then write a simple 'scatter.sct' file, which will instruct the linker to place the 'add.o' at a specific memory location.
We will then 'link' the 3 above produced object files: 'c.o', 'add.o' and 'a.o' , using the 'scatter.sct' scatter load file to produce a single binary executable called 'image.bin'.
We will then convert the binary file 'image.bin' into its disassembly code, 'image.txt' to see how the function 'add' has been placed.
We will then notice that the function 'add' has been placed at 0x3000_0000, as desired by the 'scatter.sct' file.

startup.s
Stack_Size EQU 0x00000401
               AREA STACK,NOINIT,READWRITE,ALIGN=3
__stack_limit
Stack_Mem       SPACE Stack_Size
__initial_sp

; Vector Table Mapped to Address 0 at Reset
 AREA RESET, DATA, READONLY
 EXPORT __Vectors
 EXPORT __Vectors_End
 EXPORT __Vectors_Size
__Vectors DCD __initial_sp ; Top of Stack
          DCD Reset_Handler ; Reset Handler
      
__Vectors_End
 
__Vectors_Size EQU __Vectors_End - __Vectors
                AREA |.text|, CODE, READONLY
Reset_Handler   PROC
                                EXPORT Reset_Handler [Weak]
                                IMPORT __main
                                LDR R0, =__main
                                BX  R0
                                ENDP
                EXPORT   __stack_limit
                EXPORT   __initial_sp

                                END




datatypes.h
typedef unsigned int uint32_t;
#define CPU_SAU_REG_BASE ((uint32_t) 0xE000EDD0)
#define CPU_SCB_REG_BASE ((uint32_t) 0xE002ED08)
#define __IO
#define __RO
#define __RW
#define SCR *((uint32_t *) (0xE000ED10))
#define GPIO_1 *((uint32_t *) (0x20000ff0))
#define GPIO_2 *((uint32_t *) (0x20000df0))
#define GPIO_3 *((uint32_t *) (0x20000cf0))
#define GPIO_4 *((uint32_t *) (0x20000bf0))

#define GPIO_5 *((uint32_t *) (0x20000af0))



main.c
#include "datatypes.h"
extern int add(int a, int b);
void go_to_dsleep ()
{
  SCR = 0x00000004; //bit 2 of SCR for deepsleep
  __asm("WFE");
}

int main ()
{
    int ii;
    //write at location 0x40E0_0018, a value of 0x87654321
    *((uint32_t *)0x40E00018) = 0x87654321;
    asm("NOP");
    GPIO_5 = 0x5a5a5a5a;
    GPIO_4 = add(ii,ii);
    go_to_dsleep();
    while(1){}
}




add.c
#include "datatypes.h"
int add(int a, int b)
{
  GPIO_4 = 0x44; This has no specific purpose
  return a + b;
}

scatter.sct
LR_IROM1 0x10000000 0x00080000  {
  RX_IRAM1 0x10000000 0x00010000  {  ; load region = execution region.
   .ANY (+RW +RO)
  }
  RW_IRAM1 0x40000000 0x00010000  {  ; RW data
   .ANY (+RW +ZI)
  }
  RX_IRAM2 0x30000000 0x00010000  {  ; Keep the add function at 0x3000_0000
    add.o
  }
}

Compile commands:
Compile add.c to produce object file add.o
/pkg/ARM/bin/armclang add.c -c --target=arm-arm-none-eabi -mcpu=cortex-m3 -o add.o -O1

Compile main.c to produce object file c.o
/pkg/ARM/bin/armclang main.c -c --target=arm-arm-none-eabi -mcpu=cortex-m3 -o c.o -O1

Compile startup.s to produce object file a.o
/pkg/ARM/bin/armasm startup.s --cpu=cortex-m3 -o a.o

Link 'a.o', 'c.o', 'add.o' to produce '__image.axf'
/pkg/ARM/bin/armlink a.o c.o add.o --entry Reset_Handler --scatter=scatter.sct --first __Vectors

Convert the '__image.axf' file into disassembly text version 'image.txt' 
/pkg/ARM/bin/fromelf --text -c -s -t -z --output image.txt __image.axf

Produce a 'hex' version of the file '__image.axf' called 'image.hex', just to see how the hex file looks like.
/pkg/ARM/bin/fromelf -cvf __image.axf --vhx --8x1 -o image.hex
Convert the '__image.axf' file to binary executable file 'image.bin'.
/pkg/ARM/bin/fromelf --bin -o image.bin __image.axf


The above compile commands will produce binary executable called 'image.bin', and the disassembly file 'image.txt', full disassembly file 'image.txt' can be seen here.

Note that the 'add' function has been placed at 0x3000_000, as shown below:

    add
        0x30000000:    f64032f0    @..2    MOVW     r2,#0xbf0
        0x30000004:    f2c20200    ....    MOVT     r2,#0x2000
        0x30000008:    2344        D#      MOVS     r3,#0x44
        0x3000000a:    6013        .`      STR      r3,[r2,#0]
        0x3000000c:    4408        .D      ADD      r0,r0,r1
        0x3000000e:    4770        pG      BX       lr



You May also use Keil uVision to compile this project. To use scatter files with Keil uVision 5 Click Here.
For a introductory Keil uVision 5 Tutorial, Click Here.

Click Here to Make Comments or ask Questions
                                                                      
<= PREV  : Scatter Loading :                     Next => No Next