This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CCS/CC2640R2F: Firmware update using Position Independent Executable/Code.

Part Number: CC2640R2F


Tool/software: Code Composer Studio

I have already realized firmware update on the CC2640R2F (Proprietary radio mode) in IAR using -ropi option and it works on all posiible image positions in the flash.

The firmware updater itself uses one of two positions in the Flash where the image can be stored. (0x1000 and 0xC000)

Now the same shall be realized using GCC under CCS (9.3).


The Linker Script is following:

ENTRY( ResetISR )

MEMORY
{
	CRC (RX)		: ORIGIN = 0x00001000, LENGTH = 0x00000004
	OHD (RX)		: ORIGIN = 0x00001004, LENGTH = 0x0000000C
	INT_VEC (RX)	: ORIGIN = 0x00001010, LENGTH = 0x000000C8
	FWU_DESCR (RX)	: ORIGIN = 0x000010D8, LENGTH = 0x00000040
	APP_DESCR (RX)	: ORIGIN = 0x00001118, LENGTH = 0x00000040
	FLASH (RX)      : ORIGIN = 0x00001158, LENGTH = 0x0000AF2F
	SRAM (RWX)      : ORIGIN = 0x20000000, LENGTH = 0x00005000
	/* Application can use GPRAM region as RAM if cache is disabled in the CCFG
	(DEFAULT_CCFG_SIZE_AND_DIS_FLAGS.SET_CCFG_SIZE_AND_DIS_FLAGS_DIS_GPRAM = 0) */
	GPRAM (RWX) 	: ORIGIN = 0x11000000, LENGTH = 0x2000
}

/*. Generate a link error if heap and stack don’t fit into RAM .*/
_Min_Heap_Size = 0x800;
_Min_Stack_Size = 0x800;

/*. Highest address of the stack. Used in startup file .*/
_estack = ORIGIN(SRAM) + LENGTH(SRAM); /*end of SRAM .*/

REGION_ALIAS("REGION_TEXT", FLASH);
REGION_ALIAS("REGION_BSS", SRAM);
REGION_ALIAS("REGION_DATA", SRAM);
REGION_ALIAS("REGION_STACK", SRAM);
REGION_ALIAS("REGION_HEAP", SRAM);
REGION_ALIAS("REGION_ARM_EXIDX", FLASH);
REGION_ALIAS("REGION_ARM_EXTAB", FLASH);


/* Section allocation in memory */

SECTIONS
{


    UDMACC26XX_CONFIG_BASE = 0x20000400;


    DMA_SPI0_RX_CONTROL_TABLE_ENTRY_ADDRESS   = (UDMACC26XX_CONFIG_BASE + 0x30);
    DMA_SPI0_TX_CONTROL_TABLE_ENTRY_ADDRESS   = (UDMACC26XX_CONFIG_BASE + 0x40);
    DMA_ADC_PRI_CONTROL_TABLE_ENTRY_ADDRESS   = (UDMACC26XX_CONFIG_BASE + 0x70);
    DMA_GPT0A_PRI_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x90);
    DMA_SPI1_RX_CONTROL_TABLE_ENTRY_ADDRESS   = (UDMACC26XX_CONFIG_BASE + 0x100);
    DMA_SPI1_TX_CONTROL_TABLE_ENTRY_ADDRESS   = (UDMACC26XX_CONFIG_BASE + 0x110);
    DMA_ADC_ALT_CONTROL_TABLE_ENTRY_ADDRESS   = (UDMACC26XX_CONFIG_BASE + 0x270);
    DMA_GPT0A_ALT_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x290);

    UDMACC26XX_dmaSpi0RxControlTableEntry_is_placed = 0;
    .dmaSpi0RxControlTableEntry DMA_SPI0_RX_CONTROL_TABLE_ENTRY_ADDRESS (NOLOAD) : AT (DMA_SPI0_RX_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaSpi0RxControlTableEntry)} > REGION_DATA

    UDMACC26XX_dmaSpi0TxControlTableEntry_is_placed = 0;
    .dmaSpi0TxControlTableEntry DMA_SPI0_TX_CONTROL_TABLE_ENTRY_ADDRESS (NOLOAD)  : AT (DMA_SPI0_TX_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaSpi0TxControlTableEntry)} > REGION_DATA

    UDMACC26XX_dmaADCPriControlTableEntry_is_placed = 0;
    .dmaADCPriControlTableEntry DMA_ADC_PRI_CONTROL_TABLE_ENTRY_ADDRESS (NOLOAD) : AT (DMA_ADC_PRI_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaADCPriControlTableEntry)} > REGION_DATA

    UDMACC26XX_dmaGPT0APriControlTableEntry_is_placed = 0;
    .dmaGPT0APriControlTableEntry DMA_GPT0A_PRI_CONTROL_TABLE_ENTRY_ADDRESS (NOLOAD) : AT (DMA_GPT0A_PRI_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaGPT0APriControlTableEntry)} > REGION_DATA

    UDMACC26XX_dmaSpi1RxControlTableEntry_is_placed = 0;
    .dmaSpi1RxControlTableEntry DMA_SPI1_RX_CONTROL_TABLE_ENTRY_ADDRESS (NOLOAD) : AT (DMA_SPI1_RX_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaSpi1RxControlTableEntry)} > REGION_DATA

    UDMACC26XX_dmaSpi1TxControlTableEntry_is_placed = 0;
    .dmaSpi1TxControlTableEntry DMA_SPI1_TX_CONTROL_TABLE_ENTRY_ADDRESS (NOLOAD) : AT (DMA_SPI1_TX_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaSpi1TxControlTableEntry)} > REGION_DATA

    UDMACC26XX_dmaADCAltControlTableEntry_is_placed = 0;
    .dmaADCAltControlTableEntry DMA_ADC_ALT_CONTROL_TABLE_ENTRY_ADDRESS (NOLOAD) : AT (DMA_ADC_ALT_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaADCAltControlTableEntry)} > REGION_DATA

    UDMACC26XX_dmaGPT0AAltControlTableEntry_is_placed = 0;
    .dmaGPT0AAltControlTableEntry DMA_GPT0A_ALT_CONTROL_TABLE_ENTRY_ADDRESS (NOLOAD) : AT (DMA_GPT0A_ALT_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaGPT0AAltControlTableEntry)} > REGION_DATA


	.SHADOW_CRC :
	{
		KEEP(*(.SHADOW_CRC))
	} > CRC = 0xFF

	.IMAGE_HEADER :
	{
		KEEP(*(.IMAGE_HEADER))
	} > OHD = 0xFF

	.intvec :
	{
		KEEP(*(.vectors))
	} > INT_VEC = 0xFF

	.firmwareDescr :
	{
		KEEP(*(.firmwareDescr))
	} >  FWU_DESCR = 0xFF

	.applicationDescr :
	{
		KEEP(*(.applicationDescr))
	} >  APP_DESCR = 0xFF

	.text : {
        CREATE_OBJECT_SYMBOLS
        *(.text)
        *(.text.*)
        . = ALIGN(0x4);
        __init_array_start = .;
        KEEP (*(.init_array*))
        __init_array_end = .;
        *(.init)
        *(.fini*)
    } > REGION_TEXT AT> REGION_TEXT = 0xFF

    PROVIDE (__etext = .);
    PROVIDE (_etext = .);
    PROVIDE (etext = .);

    .rodata : {
        *(.rodata)
        *(.rodata.*)
    } > REGION_TEXT AT> REGION_TEXT = 0xFF

    .data :
    {
	_ldata = LOADADDR(.data);
        _data = .;
        *(vtable)
        *(.data)
        *(.data*)
        _edata = .;
    } > REGION_DATA AT > REGION_TEXT  = 0xFF

    .ARM.exidx : {
        __exidx_start = .;
        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
        __exidx_end = .;
    } > REGION_ARM_EXIDX AT> REGION_ARM_EXIDX

    .ARM.extab : {
        *(.ARM.extab* .gnu.linkonce.armextab.*)
    } > REGION_ARM_EXTAB AT> REGION_ARM_EXTAB

    .bss : {
        __bss_start__ = .;
        *(.shbss)
        _bss = .;
        *(.bss)
        *(.bss.*)
        *(COMMON)
        . = ALIGN (4);
        _ebss = .;
        __bss_end__ = .;
    } > REGION_BSS AT> REGION_BSS

    .heap : {
        __heap_start__ = .;
        end = __heap_start__;
        _end = end;
        __end = end;
        . = . + _Min_Heap_Size;
        KEEP(*(.heap))
        __heap_end__ = .;
        __HeapLimit = __heap_end__;
    } > REGION_HEAP AT> REGION_HEAP

    .stack (NOLOAD) : ALIGN(0x8) {
        _stack = .;
        __stack = .;
        KEEP(*(.stack))
        . += _Min_Stack_Size;
        _stack_end = .;
        __stack_end = .;
    } > REGION_STACK AT> REGION_STACK
}

----------------------------------------------------------------------------------------------------------

The Project is compiled with the following flags:

--asm
-fno-strict-aliasing
-fdata-sections
-ffunction-sections
-fno-exceptions
-fpie

The linker is called with the following flags:


-Wl,--gc-sections
-nostartfiles
-mthumb
-lc
-lm
-lgcc
-lnosys
-u __vector_table
-u g_pfnVectors
-pie

Unfortunately, the image works only if it is loaded from the position 0x1000 (Linker Script Origin). If the code is stored in 0xC000, then the default fault handler is called immidetely.
By means of disassembly I have found, that the _ldata = LOADADDR(.data); is not position indepnedent. And usage of the standart GCC Statup file:

void
ResetISR(void)
{
    uint32_t *pSrc;
    uint32_t *pDest;

    //
    // Final trim of device
    //
    SetupTrimDevice();
    
    //
    // Copy the data segment initializers from FLASH to SRAM.
    //
    pSrc = &_ldata;


    for(pDest = &_data; pDest < &_edata; )
    {
        *pDest++ = *pSrc++;
    }


    __asm("    ldr     r0, =_bss\n"
          "    ldr     r1, =_ebss\n"
          "    mov     r2, #0\n"
          "    .thumb_func\n"
          "zero_loop:\n"
          "        cmp     r0, r1\n"
          "        it      lt\n"
          "        strlt   r2, [r0], #4\n"
          "        blt     zero_loop");
    main();'
    FaultISR();
}

Always fails. As workarownd I have added to the data copy a check if the position of the current _data is valid as following (here is C representation, I have used the assembler code instead):

    if((uint32_t)pSrc < (uint32_t)get_pc())
    {
        pSrc+=0xB000;
    }

With this workaround the variables are copied correctly. Unfortenately some of the functions still have the wrong addressing...

Could someone infom me, how to change the linker script, so that the realtive adderssing will be used?

Thanks in Advance

  • Hi Dmytro,

    While I can't give you a good answer, I would like to look closer at this for you. Do you have a small example you could share with me? 

    I could of course take your flags and linker file above but if you could provide an exported project from CCS in this case then I know I'm based of the exact same situation as you. If you do not want to share the project publicly you could PM me instead.

  • Hi M-W,
    Could You please send me your e-Mail for sending of the Project?

    I cannot send anything using the +Connect -> Private Message

    Best Regards
    D.Krush

    dmytro.krush@hsu-hh.de

  • Hi Krush,

    I have been having a look at your example and there is really nothing else I could add to why this might be the case. I was surprised that the "for-loop" in the default startup file does not loop in a relative manner but with fixed lables.

    Unfortunately there has been no one internal that could answer these questions for me, TI do not modify the arm gcc compiler/linker at all, we just ship it. This means that if this is a compiler/linker bug, then it is inside the normal arm gcc toolchain. I actually tried out 3 different versions of the toolchain with no difference in result. 

    Have you tried just the simple "for-loop" example on your side, hoe does that assembly look? This might be a bug that need to be brought up with the GNU GCC community if it is supposed to work. I have tried to find if there is any list of devices that might not support the "PIE" feature for GCC but without any luck.