Hi,
In my Cortex-M0 project, there are two program images residing at different memory locations: 0x0000_0000 and 0x0010_0000. Each program has its own vector table. M0 will boot from the program at 0x0010_0000 then switch to the other program (0x0000_0000) at the end.
What is the correct way to switch to the porgram at 0x0000_0000? I'm not sure whether the following instructions are correct or not.
LDR R6, =0x1 ; set R6 to 0x0000_0001 due to Thumb mode
LDR R0, [R6]
MOV SP, R0
LDR R1, [R6, #4]
BX R1
Can someone please point me the right implementation? Thanks a lot.
Note: r6 should be 0, not 1.
It's only necessary to set bit 0 in PC, that is if you're changing PC directly.
So you should load the SP from address 0x00000000 and PC from address 0x00000004.
Bit 0 is already set for all handlers in the vector table, so you do not need to change anything.
ARM recommends using BX to load PC:
movs r0,#0
ldr r1,=SC
str r0,[r1,#VTOR]
ldr r1,[r0]
mov sp,r1
ldr r1,[r0,#4]
bx r1
... but if you need the code to be shorter, I believe the following will work ...
ldmia r0!,{r0,r1}
mov sp,r0
Edit: I've corrected this answer, so it would work for Cortex-M0+. As mentioned below, the Cortex-M0 (without plus), does not have the hardware register VTOR.
Hello Jens Bauer,
I am trying to develop my own bootloader, so I am facing the same problems dealt in this post. As you have widely explained, VTOR helps a lot to remap the vector table, so I would like to know if it is possible:
Run the bootloader as the first application to run as the system is powered on.
The Vector table is set in the 0x000_0000 address (the reset vector to be more accurate if I am not wrong).
The Bootloader (until I modify the BOOTPROT fuse to 4KB size) occupies 8KB, so it ends at the 0x0000_1FFF address which implies that the vector table must be relocated to the 0x0000_2000 address, musn't it?. So once I finish with the bootloader, before the moving the PC to the address I should set VTOR to 0x0000_2000 I guess.
Is all this stuff possible or I am missing many things?
I would like also to know if you have some examples with the linker-script and some startup-code showing how the ramcode/fascode works. It sounds great if the MCU doesn't have a VTOR.
Thanks in advance.
Any advice or help will be really appreciated.
Best regards,
Hi fulgor3.
It all looks reasonable to me. I have not written a bootloader myself yet, but if you're writing code for the Cortex-M0+, Cortex-M3, Cortex-M4 or Cortex-M7, then it should be very close to the procedure you expect above.
The location and size of the boot code depends on your device (however, I would expect that the location would always be 0x00000000, since that's the default value of VTOR!).
Remember that most (all?) Cortex-M have a built-in ROM-bootloader, which is run first. This bootloader can in most cases be "bypassed", but as it's always executed, in order to determine if it should run any code, I would expect at least 3 instructions would be run from the ROM bootloader on each cold start.
If you're writing a bootloader for private purposes, it might be a good idea to support booting from RAM (eg. if you do a lot of testing, then you don't need to wear down the flash-memory. Personally, I've never worn down any Cortex-M's flash memory, even though I've been flash-programming the same device several times per day, but if you're doing some automated tests, you might want to consider using the RAM.
If you get fancy, you could also try embedding the LZ4 decompressor in your bootloader (it'll work on all the Cortex-M architectures (and some earlier architectures as well).
Hi jensbauer,
Thank you for your fast response.
I didn't know Cortex-M have a built-it ROM bootloader, reading the ATMEL SAM R21 ( The ARM CORTEX M0+ MCU I am using) datasheet I only noticed that there is a FUSE called BOOTPROT (I haven't used a FUSE before, so I don't know if it must be set up using the JTAG or maybe writing flash memory position directly. I say this because there is a lot of references to Non volatile memory when BOOTPROT comes up) to set aside some memory for the BOOTLOADER in the lower rows of the NVM.
Booting from RAM? I haven't done this before, is complicated? It could be great, but I need to develop something similar in a 8051 architecture, so I have some RAM constraints, and I hope that just few applications updates will be required in the future .
The LZ4 decompression routine for Cortex-M0 and later sounds great. It is used to compress the data to be send to the bootloader in order to decompress it to get the final modifications or for the bootloader's code itself??. I will study it. If I get performance improvement it would be really welcome.
Again, thank you very much, and any support will be really appreciate.
Iván Gómez Bustinduy
Hey Jens,
I am trying to write a bootloader for cortex M0 processor and I am interested to follow the #3 route you mention in your previous comment. Could you please send me some guidelines or sample documents on linker script and vector jump code, if possible. Thanks!
Regards,
Sharif
You would need to change the linker ROM start for each application, so they all get their own vector table (below tested for M0+)Can take a couple of short cuts as M0 probably will have less than 64K of flash,and you compile to 1K boundary.
if ( firm1 > firm2) __asm("movs r0, #0x40"); // upper byte for firmware at 0x4000else __asm("movs r0, #0xA0"); // upper byte for firmware at 0xA000 __asm("lsls r0, r0, #8"); __asm("ldr r1, [r0]"); __asm("msr msp, r1"); // Set new MSP __asm("msr psp, r1"); // PSP based on SP __asm("ldr r1, [r0,#0x4]"); __asm("mov pc, r1"); // Jump by changing PC