Hello. I inherited a project that is running on a TI TM4C1230H6PM microcontroller and I've run into a bit of a snag.
We have a bootloader running Keil RTX that starts at address 0x0000 which ultimately launches FW running Keil RTX starting at address 0x8000. After adding lots of new functionality to the FW (including several new tasks) I found that we were encountering random stack overflow issues.
After some heavy debugging, I discovered that the Main Stack Pointer (MSP) was overrunning the stack of one of my new tasks and causing the error. Essentially, what I see happening is that when the code jumps over from the bootloader to the FW the MSP is loaded with the initial stack pointer from the bootloader (0x20003EB8) loaded from address 0x0000. This, apparently, never caused an issue in the past, but I now have a task whose stack ends at 0x20003E38. So, not only is the main stack not where it should be, but it's dangerously close to the top of a process stack.
The original code to jump from the bootloader to the firmware looked as follows
jump(*(U32 *)code_start, *(U32 *)(code_start + 4)); ; jump to application code AREA asm_func, CODE, READONLY EXPORT jump jump MOV R13, R0 BX R1 END
The problem I found here is that this executes in User context and so R13 refers to the PSP rather than the MSP.
I tried several different ways of resolving this issue by loading the contents (0x20007280) of address 0x8000 into the MSP register prior to branching, but no matter what I do I get a hardware fault almost immediately after the FW begins to run.
Can anyone shed some light on what's going on here?
Any assistance in solving this would be greatly appreciated.
The code I used to jump to application FW from bootloader is listed below:
typedef void (*pFunction)(void); uint32_t timingdelay; pFunction Jump_To_Application; uint32_t JumpAddress; // function which never returns, // if conditions not met, return with 0 BOOL JumpToFirmware(void) { int USER_FLASH_FIRST_PAGE_ADDRESS; USER_FLASH_FIRST_PAGE_ADDRESS = 0x08020200; // Check if valid stack address (RAM address) then jump to user application if (((*(__IO uint32_t*)USER_FLASH_FIRST_PAGE_ADDRESS) & 0x2FFE0000 ) == 0x20000000) { // Jump to user application JumpAddress = *(__IO uint32_t*) (USER_FLASH_FIRST_PAGE_ADDRESS + 4); Jump_To_Application = (pFunction) JumpAddress; // Initialize user application's Stack Pointer __set_MSP(*(__IO uint32_t*) USER_FLASH_FIRST_PAGE_ADDRESS); Jump_To_Application(); } return 0; }
Georg
Thanks for the response Georg. I tried this and got the same results as with my assembly code. It successfully changes the MSP and then jumps to the correct code, but almost immediately hits a HW fault. I believe the fault is occurring during the __main RTX initialization function which I do not have source code for.
Does anyone know if RTX is doing some sort of check that PSP and MSP aren't equal/within some range or any other check on the pointer that may have been configured by the bootloader?
I ask because I just arbitrarily subtracted 256 from the FW's MSP value and got the code to run w/o causing an immediate fault. Obviously, this isn't really a solution though since I just reduced the main stack by 256 bytes.
So after observing the state of the processor when initially booting into the bootloader I came up with the following that seems to work...
; jump to application coode AREA asm_func, CODE, READONLY EXPORT jump jump MOV R4, #0x0 MSR PSP, R4 ; set PSP to zero MSR MSP, R0 ; set MSP to 1st argument MRS R4, CONTROL ; read control into R4 (don't care to preserve R4) MOV R5, #0x2 ; 0x2 into R5 (don't care to preserve R5) MVN R5, R5 ; NOT R5 AND R4, R4, R5 ; set the ASP bit low (MSP) and preserve any other bits that were set in CONTROL MSR CONTROL, R4 ; write the control regsister ISB ; Instruction Synchronisation Barrier BX R1 END
Here I set the PSP to 0x0000 and the MSP to the value stored at the beginning of the FW binary. I then switch the processor into handler mode before jumping to the reset handler in the FW image.
Is this the correct way to handle this? Are there any potential perils I'm not seeing here?