2016-05-30 07:17 AM
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
2016-05-30 08:34 AM
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.2016-05-30 10:57 AM
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?
2016-05-30 12:41 PM
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
2016-05-31 06:22 AM
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.
2016-05-31 06:57 AM
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 */
}
2016-05-31 08:07 AM
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,
};
2016-05-31 09:13 AM
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.