cancel
Showing results for 
Search instead for 
Did you mean: 

How do I properly jump and reset ''things'' in order to switch execution area?

arnold_w
Senior
Posted on May 30, 2016 at 16:17

I am working with the Discovery Development Board and a custom-made PCB with anSTM32F405 microcontroller. My 2 projects are very similar and usually I use the custom-made board, but when I need to probe or measure something I use the Discovery Development Board. My projects have identical bootloaders, that I wrote myself, and I experience problems when I jump from my bootloader to the application. In order to do that I use the following:

#define JMP(addr) \
__asm__(''mov pc,%0'' \
: /*output*/ \
: /*input*/ \
''r'' (addr) \
);
JMP(0x08010004)

The code seems to hang when I do the jump on the custom-made PCB, but it works fine on the Discovery Development Board. However, if I do a reset (NVIC_SystemReset()) and then do the same jump when the microcontroller boots back up again, then it works fine. This makes me suspect that I need to do something before I do the jump, such as resetting the stack pointer or something else. Does anybody know all the required steps to take before doing a jump like this? My vector file (system\src\cmsis\vectors_stm32f405xx.c) looks like this:

void __attribute__ ((section(''.after_vectors''),noreturn))
Reset_Handler (void)
{
_start ();
}
__attribute__ ((section(''.isr_vector''),used))
pHandler __isr_vectors[] =
{
// Cortex-M Core Handlers
(pHandler) &_estack, // The initial stack pointer
Reset_Handler, // The reset handler
NMI_Handler, // The NMI handler
HardFault_Handler, // The hard fault handler
.
.
.

SCB->VTOR is set to 0x08010000. #uphill-skiing
7 REPLIES 7
Posted on May 30, 2016 at 17:34

Recapping M4 facts

You can't jump to EVEN addresses, it will fault

The Vector Table contains a list of addresses/vectors, these are indirect, and not actually executable code, ie you must read the address IN the table, and jump to that, not jump to the address OF the table.

When you jump to a secondary application be aware that the processor is already running, and the clocks and PLLs might have already been started, SystemInit call from the app should be aware it is not being called at Reset conditions, and doesn't need to break the RCC clocks down and start over.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
arnold_w
Senior
Posted on May 30, 2016 at 19:57

So I should jump to the address that is stored in the 2nd element in the __isr_vectors array, which is denoted ''Reset_Handler''? Isn't there a risk that the address on that location changes between builds and therefore would make my code break? Is it somehow possible to lock the address in the 2nd element to a specific address?

Posted on May 30, 2016 at 21:41

Yes, it could change, but you know the address of the table and can read the content.

 LDR R0,=0x08010004
 LDR R0, [R0]
 BX R0

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
arnold_w
Senior
Posted on May 31, 2016 at 15:22

Sometimes I want to run the application project alone without the bootloader, but keep the application at the addresses where it should be (I don't want to have duplicate sets of linker script files). In that case the microcontroller will look for the isr_vector-array at address 0x08000000 upon power-up to find out where to go, but there will be none. How would I create small isr_vector-array at address 0x08000000 that can tell the microcontroller where to go upon power-up? It would only be a power-up problem because the very first thing I do in main() is to set the SCB->VTOR to 0x08010000 so interrupts will be handled properly.

Posted on May 31, 2016 at 15:57

Minimal code at 0x08000000

...
__Vectors DCD 0x20002000 ; Top of Stack
DCD Reset_Handler ; Reset Handler
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
LDR R0, =0x08010000
LDR SP, [R0, #0]
LDR R0, [R0, #4]
BX R0
ENDP
...

SCB->VTOR is typically set in SystemInit() *before* main() is called. If you want it to be agnostic, make the linker fixup the symbols

extern void * __Vectors;
NVIC_SetVectorTable((u32)(&__Vectors), 0x0); // Smart Base Location
or
/**
* @brief Setup the microcontroller system
* Initialize the Embedded Flash Interface, the PLL and update the
* SystemFrequency variable.
* @param None
* @retval None
*/
void SystemInit(void)
{
...
/* Configure the System clock source, PLL Multiplier and Divider factors,
AHB/APBx prescalers and Flash settings ----------------------------------*/
SetSysClock();
/* Configure the Vector Table location add offset address ------------------*/
SCB->VTOR = (u32)(&__Vectors); /* Vector Table Relocation */
}

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
arnold_w
Senior
Posted on May 31, 2016 at 17:07

Your suggestion in your post from5/30/2016 worked great, but I'm unable to get your suggestion from5/31/2016 to work (I'm not sure how to put the assembler instructions into the array). I assume 0x20002000 was a typo, it should be 0x20020000, right? Should the array at address 0x08000000 look like below?

__attribute__ ((section(''.startUpVector''),used)) pHandler __startUpVector[] =
{
(pHandler) 0x20020000,
(pHandler) 0x08010000,
};

Posted on May 31, 2016 at 18:13

This is like Uphill Skiing...

0x20002000 is a valid RAM address from which the stack could descend in the few instruction cycles before it loads the one at your alternate table. Not going to happen, but whatever..

We have already established that 0x08010000 is a table of addresses, and NOT CODE, setting the PC to it WILL CAUSE FAILURE.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..