# Stack error when jumping from bootloader to application

I have been trying to jump from my bootloader to an application for a while now but I can not figure out what is going wrong. I am hoping someone here might be able to help me.
I am using Texas Instrument's CC2652 and Texas Instrument's Code Composer Studio to develop and flash the bootloader. The code below is the code I use to jump to the application.

void startApp(uint32_t prgEntry) {
static uint32_t temp;
temp = prgEntry;
// Reset the stack pointer,
temp +=4;
asm(" LDR SP, [R0, #0x0] ");
((void (*)(void))(*((uint32_t*)temp)))();
}


When I run this code I will end up in the FaultISR. Here I can use the debugger to look at the registers. In the CFSR (Configurable Fault Status Register) I can see that the STKERR and the IBUSERR bits are set.

prgEntry Is 0x2E000 in this case. I defined this address as the start of the application in the linker command files of both the bootloader and the application as well. I copied the command files further below.

The application I am trying to jump to is first uploaded to the device in intel hex format and looks like this https://pastebin.com/DAerFkXr. Texas Instruments has a Flash Programmer application for Windows with which I can read a range of addresses from the internal flash of the device. I went through the intel hex file by hand and compared it to what I saw in the Flash Programmer application and I believe everything is put in the correct location. I posted a screenshot of the output of the Flash Programmer below the command files.

When I flash the application to the device using Code Composer Studio without my bootloader I can see that the application runs normally so I know it is not a problem with the application.

Application command file:

--stack_size=1024   /* C stack is also used for ISR stack */

--heap_size=256

/* Retain interrupt vector table variable                                    */
--retain=g_pfnVectors
/* Override default entry point.                                             */
--entry_point resetISR
/* Allow main() to take args                                                 */
--args 0x8
/* Suppress warnings and errors:                                             */
/* - 10063: Warning about entry point not being _c_int00                     */
/* - 16011, 16012: 8-byte alignment errors. Observed when linking in object  */
/*   files compiled using Keil (ARM compiler)                                */
--diag_suppress=10063,16011,16012

#define BOOT_BASE               0x0
#define BOOT_SIZE               0x8000
#define FLASH_BASE              0x2E000
#define FLASH_SIZE              0x2A000
#define RAM_BASE                0x20000000
#define RAM_SIZE                0x14000
#define GPRAM_BASE              0x11000000
#define GPRAM_SIZE              0x2000

/* System memory map */

MEMORY
{
/* Application stored in and executes from internal flash */
FLASH (RX) : origin = FLASH_BASE, length = FLASH_SIZE
/* Application uses internal RAM for data */
SRAM (RWX) : origin = RAM_BASE, length = RAM_SIZE
/* 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 = GPRAM_BASE, length = GPRAM_SIZE
}

/* Section allocation in memory */

SECTIONS
{
.intvecs        :   > FLASH_BASE
.text           :   > FLASH
.TI.ramfunc     : {} load=FLASH, run=SRAM, table(BINIT)
.const          :   > FLASH
.constdata      :   > FLASH
.rodata         :   > FLASH
.binit          :   > FLASH
.cinit          :   > FLASH
.pinit          :   > FLASH
.init_array     :   > FLASH
.emb_text       :   > FLASH
.ccfg           :   > FLASH (HIGH)

.vtable         :   > SRAM
.vtable_ram     :   > SRAM
vtable_ram     :   > SRAM
.data           :   > SRAM
.bss            :   > SRAM
.sysmem         :   > SRAM
.stack          :   > SRAM (HIGH)
.nonretenvar    :   > SRAM

.gpram          :   > GPRAM
}


--stack_size=1024   /* C stack is also used for ISR stack */

--heap_size=256

/* Retain interrupt vector table variable                                    */
--retain=g_pfnVectors
/* Override default entry point.                                             */
--entry_point resetISR
/* Allow main() to take args                                                 */
--args 0x8
/* Suppress warnings and errors:                                             */
/* - 10063: Warning about entry point not being _c_int00                     */
/* - 16011, 16012: 8-byte alignment errors. Observed when linking in object  */
/*   files compiled using Keil (ARM compiler)                                */
--diag_suppress=10063,16011,16012

#define BOOT_BASE               0x0
#define BOOT_SIZE               0x8000
#define FLASH_BASE              0x2E000
#define FLASH_SIZE              0x2A000
#define RAM_BASE                0x20000000
#define RAM_SIZE                0x14000
#define GPRAM_BASE              0x11000000
#define GPRAM_SIZE              0x2000

/* System memory map */

MEMORY
{
/* The bootloader will be stored and executed from this location in internal flash */
BOOT (RX)  : origin = BOOT_BASE, length = BOOT_SIZE
/* Application stored in and executes from internal flash */
FLASH (RX) : origin = FLASH_BASE, length = FLASH_SIZE
/* Application uses internal RAM for data */
SRAM (RWX) : origin = RAM_BASE, length = RAM_SIZE
/* 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 = GPRAM_BASE, length = GPRAM_SIZE
}

/* Section allocation in memory */

SECTIONS
{
.intvecs        :   > BOOT_BASE
.text           :   > BOOT
.TI.ramfunc     : {} load=BOOT, run=SRAM, table(BINIT)
.const          :   > BOOT
.constdata      :   > BOOT
.rodata         :   > BOOT
.binit          :   > BOOT
.cinit          :   > BOOT
.pinit          :   > BOOT
.init_array     :   > BOOT
.emb_text       :   > BOOT
.ccfg           :   > BOOT (HIGH)

.vtable         :   > SRAM
.vtable_ram     :   > SRAM
vtable_ram     :   > SRAM
.data           :   > SRAM
.bss            :   > SRAM
.sysmem         :   > SRAM
.stack          :   > SRAM (HIGH)
.nonretenvar    :   > SRAM

.gpram          :   > GPRAM
}


Screenshot from Flash Programmer:

Description of STKERR: Stacking from exception has caused one or more bus faults. The SP is still adjusted and the values in the context area on the stack might be incorrect. BFAR is not written.

Description of IBUSERR: Instruction bus error flag. This flag is set by a prefetch error. The fault stops on the instruction, so if the error occurs under a branch shadow, no fault occurs. BFAR is not written.

Edit:
This is the disassembly of the startApp function:

void startApp(uint32_t prgEntry) {
startApp():
push       {r3, r14}
str        r0, [r13]
temp = prgEntry;
ldr        r1, [pc, #0x18]
ldr        r0, [r13]
str        r0, [r1]
temp +=4;
ldr        r1, [pc, #0x14]
ldr        r0, [r1]
str        r0, [r1]
asm(" LDR SP, [R0, #0x0] ");
ldr.w      r13, [r0]
((void (*)(void))(*((uint32_t*)temp)))();
ldr        r0, [pc, #8]
ldr        r0, [r0]
ldr        r0, [r0]
blx        r0
}

• You have to disassemble startApp and see what's going on, then see if the generated machine code matches the calling convention of your particular compiler. Generally, C code doesn't exist in a predictable state until the SP is initialized, nor does it like the co-exist in the same function with code manually setting the SP. – Lundin Mar 27 at 9:28
• @lundin I added the disassembly of the startApp function, do you see if there is anything wrong with it? I am new to this and don't know much about assembly. – Vincent Kenbeek Mar 27 at 10:31
• I don't know this calling convention. If you don't know that either, then no can do - you must study this in compiler documentation. You can't just cast some integer to a function pointer and call it. – Lundin Mar 27 at 10:54
• @lundin This function was directly taken from the Boot Image Manager example provided by Texas Instruments for this board. So I think this function should just work right? I did modify the prgEntry of course so it pointed to the first address of the firmware. – Vincent Kenbeek Mar 27 at 11:36

I think you should single-step through this code to see what is in R0 just before the LDR SP, [R0]. Remember that the value in R0 is interpreted as an address, and the instruction fetches whatever is at that address and shoves it into the stack pointer.