Jump to main content

# 1.3.3.2 SPI Bootloader Linker Configurations for Cortex-M Based MCUs

Linker configurations for SPI Bootloader

- Bootloader library uses a custom linker script which is generated through MCC

- The values populated in the linker script are based on the Bootloader component MCC configurations

- Bootloader is configured to run from RAM to allow updating the bootloader firmware as well

  Note: The below sections provides overview of changes done to bootloader linker scripts when compared to default linker script. The <bootloader_start> address and <bootloader_length> may vary based on the specific device used.

    #define ROM_START <bootloader_start>

    /* Bootloader size is calculated with below criteria with optimization level -O2
     * bootloader size = Minimum Flash Erase Size Or actual bootloader ELF size
                         (Rounded of to nearest erase boundary) whichever is
                         greater.
     */
    #define ROM_SIZE  <bootloader_length>

    /* Bootloader Trigger pattern needs to be stored in starting <trigger_len> Bytes
     * of Ram by the application if it wants to run bootloader at startup without any
     * external trigger.
     * Example:
     *     ram[0] = 0x5048434D;
     *     ram[1] = 0x5048434D;
     *     ....
     *     ram[n] = 0x5048434D;
     */
    #define RAM_START (<ram_start> + <trigger_len>)

    #define RAM_SIZE  (<ram_length> - trigger_len)

    MEMORY
    {
      rom (rx) : ORIGIN = ROM_START, LENGTH = ROM_SIZE
      ram (rwx) : ORIGIN = RAM_START, LENGTH = RAM_SIZE
    }

Refer the below linker script changes if the RAM pattern based bootloader trigger is disabled in MCC:

    SECTIONS
    {
        /*
         * Configure to place the vector table in Flash but to be run from RAM
         */
        .vectors :
        {
            _sfixed = .;   /* RAM address where the vector table from flash will be copied. This will be used by C startup code to copy vector table into RAM*/
            KEEP(*(.vectors .vectors.*))
        } > ram AT > rom

        _vectors_loadaddr = LOADADDR(.vectors);     /* Start address of vector table in flash. This will be used by C startup code to copy vector table into RAM */

        .text :     /* The startup code is linked to run from the ROM (flash) memory */
        {
            . = ALIGN(4);
            ....
            ....
            . = ALIGN(4);
            _efixed = .;            /* End of text section */
        } > rom

        ....
        ....

        . = ALIGN(4);
        _etext = .;     /* Starting address in flash from where the bootloader code will be copied into RAM by the C startup code */

        /* Locate text/rodata in special data section to be copied to RAM
           in startup sequence. */
        .data :
        {
            . = ALIGN(4);
            __data_start__ = .;
            _sdata = .;     /* Starting address in RAM where the bootloader code will be copied by the C startup code*/
            *(.dinit)
            *(.text)
            *(.text.*)
            *(.rodata)
            *(.rodata.*)
            . = ALIGN(4);
            __data_end__ = .;
            _edata = .;     /* End address in RAM after the bootloader code is copied */
        } > ram AT > rom

        ....
    }

Refer the below linker script changes if the RAM pattern based bootloader trigger is enabled in MCC:

    SECTIONS
    {
        /*
         * Configure to place the vector table in Flash but to be run from RAM.
         * When RAM pattern based trigger is enabled, first few bytes in RAM are reserved for the pattern. As a result, an offset of 1024 bytes is addded from the * start location of RAM to satisfy the alignment needs of vector table in Cortex M based MCUs. For example, if the RAM start address is 0x2000000 and the * trigger length is set to 16 bytes, then the RAM_START macro will be set to 0x2000016, and the vector table will be copied from RAM_START - <trigger_len> * + 0x400 which evaluates to 0x2000016 - 16 + 0x400 = 0x2000400.
         */
        .vectors RAM_START - <trigger_len> + 0x400:
        {
            _sfixed = .;   /* RAM address where the vector table from flash will be copied. This will be used by C startup code to copy vector table into RAM*/
            KEEP(*(.vectors .vectors.*))
        } > ram AT > rom

        _vectors_loadaddr = LOADADDR(.vectors);     /* Start address of vector table in flash. This will be used by C startup code to copy vector table into RAM */

        .text :     /* The startup code is linked to run from the ROM (flash) memory */
        {
            . = ALIGN(4);
            ....
            ....
            . = ALIGN(4);
            _efixed = .;            /* End of text section */
        } > rom

        ....
        ....

        . = ALIGN(4);
        _etext = .;     /* Starting address in flash from where the bootloader code will be copied into RAM by the C startup code */

        /* Locate text/rodata in special data section to be copied to RAM
           in startup sequence. */
        .data :
        {
            . = ALIGN(4);
            __data_start__ = .;
            _sdata = .;     /* Starting address in RAM where the bootloader code will be copied by the C startup code*/
            *(.dinit)
            *(.text)
            *(.text.*)
            *(.rodata)
            *(.rodata.*)
            . = ALIGN(4);
            __data_end__ = .;
            _edata = .;     /* End address in RAM after the bootloader code is copied */
        } > ram AT > rom

        ....
    }

Custom startup file for UART, I2C and CAN Bootloaders

- To reduce the size of the binary these bootloaders make use of custom startup file which is generated by MCC

- The startup code copies .vector section from Flash to RAM and relocates the vector table to RAM by updating the VTOR register

- The startup file also copies the entire bootloader code placed in .data section above from Flash to RAM as it is built to run from RAM

      /* Declaration of Reset handler (may be custom) */
      /* Initialize segments */
      extern uint32_t _sfixed;
      extern void _ram_end_(void);

      extern int main(void);

      /**
       * \brief This is the code that gets called on processor reset.
       * To initialize the device, and call the main() routine.
       */

      /* Linker-defined symbols for data initialization. */
      extern uint32_t _sdata, _edata, _etext;
      extern uint32_t _sbss, _ebss;
      extern uint32_t _vectors_loadaddr;

      void __attribute__((noinline, section(".romfunc.Reset_Handler"))) Reset_Handler(void)
      {

          uint32_t *pSrc, *pDst;

          uint32_t i;
          pSrc = (uint32_t *) &_vectors_loadaddr; /* flash address */
          pDst = (uint32_t *) &_sfixed;

          /* Copy .vectors section from flash to RAM */
          for (i = 0; i < sizeof(H3DeviceVectors)/4; i++)
          {
              *pDst++ = *pSrc++;
          }

          pSrc = (uint32_t *) &_etext; /* flash functions start after .text */
          pDst = (uint32_t *) &_sdata;  /* boundaries of .data area to init */

          /* Init .data */
          while (pDst < &_edata)
              *pDst++ = *pSrc++;

          /* Init .bss */
          pDst = &_sbss;
          while (pDst < &_ebss)
            *pDst++ = 0;

      #if defined (__VTOR_PRESENT) && (__VTOR_PRESENT == 1U)
          /*  Set the vector-table base address in RAM */
          pSrc = (uint32_t *) & _sfixed;
          SCB->VTOR = ((uint32_t) pSrc & SCB_VTOR_TBLOFF_Msk);
      #endif /* #if defined (__VTOR_PRESENT) && (__VTOR_PRESENT == 1U) */

           /* Branch to application's main function */
          main();

      #if (defined(__DEBUG) || defined(__DEBUG_D)) && defined(__XC32)
          __builtin_software_breakpoint();
      #endif
      }

MPLAB X Setting for SPI Bootloader

- Below MPLAB X option is enabled by MCC for these bootloaders to remove the XC32 crt0 startup code

- By disabling this crt0 startup code the size is further reduced as it removes the default initialization code by XC32

Rev: G