How to set the starting address and size of the IAP program and APP program for the STM32 development board on platformIO


I am a beginner, and I want to store my IAP program and APP program in the place I want and set the size I want, just like Traget on MDK is easy to set. How can I set it?
I didn’t see any link files generated by my project.This is my ini configuration file.

[platformio]
src_dir =  Core/Src

[env:genericSTM32F103RC]
build_type = debug
platform = ststm32
board = genericSTM32F103RC
framework = stm32cube
build_flags = 
    -ICore/Inc
    -ICore/Src/aCoral/include
    -ICore/Src/aCoral/SX1278/include
    -ICore/Src/aCoral/DHT11/include
    -ICore/Src/aCoral/OLED/include
    -ICore/Src/aCoral/LightSensor/include
    -ICore/Src/aCoral/LED/include
    
upload_protocol = jlink
debug_tool = jlink
monitor_speed = 115200
debug_server = 
    C:\Users\ASUS\.platformio\packages\tool-jlink\JLinkGDBServerCL.exe
    -singlerun
    -if
    JTAG
    -select
    USB
    -port
    2331
    -device
    STM32F103RC

extra_scripts = post:extra_script.py

This is my extra_script.py file.

Import("env")


env.AddPostAction(
    "$BUILD_DIR/${PROGNAME}.elf",
    env.VerboseAction(" ".join([
        "$OBJDUMP", "-S", "-d",  
        "$BUILD_DIR/${PROGNAME}.elf", ">", "$BUILD_DIR/${PROGNAME}.d"
    ]), "Building $BUILD_DIR/${PROGNAME}.d")
)

Do I need to set up a linked file? If so, how should it be set?

The start loading address during compilation is determined by the linker script in GCC-based toolchains.

With this framework, PlatformIO will either use a pregenerated linkerscript (if it exists in tool-ldscripts-stm32), generate one based on a template, or use one as indicated by board_build.ldscript = .... in the platformio.ini (documentation, code).

So in your genericSTM32F103RC case, it will use the STM32F103RCTX_FLASH.ld from the afforementioned package, which has content

/*
******************************************************************************
**
** @file        : LinkerScript.ld
**
** @author      : Auto-generated by STM32CubeIDE
**
** @brief       : Linker script for STM32F103RCTx Device from STM32F1 series
**                      256Kbytes FLASH
**                      48Kbytes RAM
**
**                Set heap size, stack size and stack location according
**                to application requirements.
**
**                Set memory bank area and size if external memory is used
**
**  Target      : STMicroelectronics STM32
**
**  Distribution: The file is distributed as is, without any warranty
**                of any kind.
**
******************************************************************************
** @attention
**
** <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
** All rights reserved.</center></h2>
**
** This software component is licensed by ST under BSD 3-Clause license,
** the "License"; You may not use this file except in compliance with the
** License. You may obtain a copy of the License at:
**                        opensource.org/licenses/BSD-3-Clause
**
******************************************************************************
*/

/* Entry Point */
ENTRY(Reset_Handler)

/* Highest address of the user mode stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */

_Min_Heap_Size = 0x200; /* required amount of heap */
_Min_Stack_Size = 0x400; /* required amount of stack */

/* Memories definition */
MEMORY
{
  RAM    (xrw)    : ORIGIN = 0x20000000,   LENGTH = 48K
  FLASH    (rx)    : ORIGIN = 0x8000000,   LENGTH = 256K
}

/* Sections */
SECTIONS
{
  /* The startup code into "FLASH" Rom type memory */
  .isr_vector :
  {
    . = ALIGN(4);
    KEEP(*(.isr_vector)) /* Startup code */
    . = ALIGN(4);
  } >FLASH

  /* The program code and other data into "FLASH" Rom 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))

    . = ALIGN(4);
    _etext = .;        /* define a global symbols at end of code */
  } >FLASH

  /* Constant data into "FLASH" Rom type memory */
  .rodata :
  {
    . = ALIGN(4);
    *(.rodata)         /* .rodata sections (constants, strings, etc.) */
    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
    . = ALIGN(4);
  } >FLASH

  .ARM.extab   : {
    . = ALIGN(4);
    *(.ARM.extab* .gnu.linkonce.armextab.*)
    . = ALIGN(4);
  } >FLASH

  .ARM : {
    . = ALIGN(4);
    __exidx_start = .;
    *(.ARM.exidx*)
    __exidx_end = .;
    . = ALIGN(4);
  } >FLASH

  .preinit_array     :
  {
    . = ALIGN(4);
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP (*(.preinit_array*))
    PROVIDE_HIDDEN (__preinit_array_end = .);
    . = ALIGN(4);
  } >FLASH

  .init_array :
  {
    . = ALIGN(4);
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT(.init_array.*)))
    KEEP (*(.init_array*))
    PROVIDE_HIDDEN (__init_array_end = .);
    . = ALIGN(4);
  } >FLASH

  .fini_array :
  {
    . = ALIGN(4);
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP (*(SORT(.fini_array.*)))
    KEEP (*(.fini_array*))
    PROVIDE_HIDDEN (__fini_array_end = .);
    . = ALIGN(4);
  } >FLASH

  /* Used by the startup to initialize data */
  _sidata = LOADADDR(.data);

  /* 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 */
    *(.RamFunc)        /* .RamFunc sections */
    *(.RamFunc*)       /* .RamFunc* sections */

    . = ALIGN(4);
    _edata = .;        /* define a global symbol at data end */

  } >RAM AT> FLASH

  /* Uninitialized data section into "RAM" Ram type memory */
  . = ALIGN(4);
  .bss :
  {
    /* This is used by the startup in order to initialize the .bss section */
    _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" Ram  type memory left */
  ._user_heap_stack :
  {
    . = ALIGN(8);
    PROVIDE ( end = . );
    PROVIDE ( _end = . );
    . = . + _Min_Heap_Size;
    . = . + _Min_Stack_Size;
    . = ALIGN(8);
  } >RAM

  /* Remove information from the compiler libraries */
  /DISCARD/ :
  {
    libc.a ( * )
    libm.a ( * )
    libgcc.a ( * )
  }

  .ARM.attributes 0 : { *(.ARM.attributes) }
}

You can just create a new file, e.g. stm32f103rctx_flash_app.ld (and iap), in the same directory as the platformio.ini, copy paste the original content, modify the

MEMORY
{
  RAM    (xrw)    : ORIGIN = 0x20000000,   LENGTH = 48K
  FLASH    (rx)    : ORIGIN = 0x8000000,   LENGTH = 256K
}

section to your likings and refernece it with

board_build.ldscript = stm32f103rctx_flash_app.ld

Then the firmware.elf file will be built with the correct flash starting address, and since PlatformIO uploads the .elf file by default, OpenOCD will be able to read this start address from the ELF file and flash it to the correct address as well.

Note that when changing the start address for the APP part, you might need to correct the vector table offset, so that the vector table from the APP firmware is used. You can e.g. add SCB->VTOR = 0x80000000u + (offset); in the early App code for that.

2 Likes

Can you be more specific? For example, if I want to download my code to the location 0x08010000 in Flash, how should I set it?

FYI, If you will not manage to get the stm32cube framework to work (I hope you do), you also have the option of going ‘frameworkless’. This is what I did with my recent STM32 project.

Then you would set

MEMORY
{
  RAM    (xrw)    : ORIGIN = 0x20000000,   LENGTH = 48K
  FLASH    (rx)    : ORIGIN = 0x08010000,   LENGTH = 192K
}

in the linker script.