I am doing a minor project (small realtime kernel) for an STM32, running on the STM32-P103 from Olimex. I configured the board to boot from RAM (a couple of pins used to configure that).
To start my code, I load it to the board using GDB via OpenOCD and the GDB “load” command, which smoothly downloads the program to the board. I put my exception vectors at 0x20000000. In my boot code I then reconfigure the NVIC_VTOR register so that the core knows where my vectors are. From now on, I am fine.
My problem is that when powered on, the CPU starts executing random code from RAM which means that it pretty soon ends up in an undesired state (in handler mode). When I stop the CPU and download the code I would like to have the CPU running the boot code cleanly from thread mode and on the main stack, just like a boot from flash where the exception vectors are in the right place from power on.
This problem might be mostly cosmetic, but I still would like to have a “clean” load and startup from RAM. How do you guys do this?
The purpose of running from RAM in my case is that I would like to avoid erasing and writing the flash every time I compile. Also, as opposed to in the LPC case (NXP microcontrollers), RAM cannot be remapped to 0.
My fix is a minor boot code in flash, including vectors, that reads the stack pointer at 0x20000000, the reset vector at 0x20000004 and jumps to it, after having set the vector table offset register to RAM. This seems to work pretty well, and I don’t have to reprogram the flash part. Now I can just download my application to RAM and reset the STM32, making it boot from flash and jump to ram.
FWIW, here’s the bootstrap code I use:
static void reset();
unsigned int *vectors[2] __attribute__ ((section(".vectors"))) = {
(unsigned int *) 0, /* No stack used. */
(unsigned int *) reset
};
__attribute__ ((naked)) static void reset()
{
/* We enter here, running as privileged in thread mode. TRM 2.2.
We use SP_main. TRM 2.2.1 and 5.4.
NVIC interrupts disabled. NMI and Hard Fault disabled. TRM 5.9. */
/* Remap vectors to 0x20000000.
Read stack top and entry point from
user's RAM-based vectors. Jump to
entry point. */
asm("mov r0, #0x20000000\n\t"
"ldr r1, =0xE000ED08\n\t"
"str r0, [r1]\n\t"
"ldr sp, [r0]\n\t"
"ldr pc, [r0, #4]");
}