I've written a boot loader for the Atmel SAM4E device which is working to a point, it can receive new application code via SPI, erase flash and write to flash, but I don't understand how to execute the new application. I've learned the VTOR can be relocated, but I'm not sure how. (my application sits at address 0x00420000).I'm very new to writing code for ARM, so I'd appreciate any help.
Many thanks
Paul
Thank you for your reply.
I just tried using this code in my bootloader to reset the stack pointer and change the program counter;
// Jump to a foreign application as if it were a reset (load SP and PC)
//
extern void start_application(unsigned long app_link_location)
{
asm(" ldr sp, [r0,#0]");
asm(" ldr pc, [r0,#4]");
}
the function is then called like this ;
start_application(0x00420000);
the idea being that the stack pointer and correct start address are pulled from the applications VTOR.
The application on first start is still setting the VTOR to 0x00420000.
I still got "stack overflow 0"
Hi,
This is probably an issue with your inline assembly not properly exposing its intentions to the compiler. You should tell the compiler that it is using app_link_location like this:
extern void start_application(unsigned long app_link_location) { asm volatile( "LDR SP, [%0, #0] \n" "LDR PC, [%0, #4]" : /* No outputs */ : "r" (app_link_location) : /* No clobbers */ ); }
asm volatile( "LDR SP, [%0, #0] \n"
"LDR PC, [%0, #4]"
: /* No outputs */
: "r" (app_link_location)
: /* No clobbers */ );
Quick explanation:
You can find more information regarding inline assembly syntax here.
Hope that helps.
Thanks, I tried that but sadly it gives the same result.
If I compile my application to start at 0x00400000 it works fine, so I'm fairly confident it's not a problem with the initialisation of the stack pointer in the app.
Hello Paul,
what is the address of _JumpBootLoader?
Is it possible to jump from the _JumpBootLoader to 0x00423c3c?
Best regards,
Yasuhiko Koumoto.
Yasuhiko Koumoto
Originally I was trying to jump directly to the start of the code. Since then I've found that the actual address is the second entry in the VTOR.
So I have a function that reads the boot address (i.e. "main()" ) from the VTOR and display it on screen, first I define a pointer;
static uint32_t *MyAddress = 0x00420004;
Then when I want to view the content of the boot address in the VTOR I do this
printf("NewBootVTORValue = 0x%08x\r\n", *MyAddress );
which for my latest application (one that just flashes an LED) gives me this on the debug port;
NewBootVTORValue = 0x004220f9
I've also tried this;
//Typedef the entrypoint
typedef void start_fn(void);
And then when I want to boot to the new application;
//Will branch and execute at the entry point at 0x00450004 which is the reset vector in the VTOR in the new application code
((start_fn *) *((uint32_t *) 0x00420004))();
Again, the same thing, it certainly jumps to the right location in memory, but I get a Stack Overflow every time.
aren't your boot program located on SRAM?
If it is correct, the direct brabch to 0x004220f9 would be impossible.
I think the reason is it why you used the function pointer.
By the way, what is the stack pointer value when you execute "((start_fn *) *((uint32_t *) 0x00420004))()"?Was it reasonable?
When you located your app codes from 0x00400000, to what address did the boot loader jump?
Was it the address in 0x00420004?
How about trying the below codes?
uint32_t v=0x00420000; asm volatile ("ldr sp,[%0,#0]": "=r" (v) : "0" (v)); ((start_fn *) *((uint32_t *) 0x00420004))();
These would be the same as the followings.
uint32_t v=0x00420000; asm volatile ("ldr sp,[%0,#0]\n\r" "ldr pc,[%0,#4]": "=r" (v) : "0" (v));
Best regards,Yasuhiko Koumoto.
Hello Yusuhiko, thank for your reply.
no, my boot program is located at the lowest point of flash (0x00400000).
Yes, my stack point after I pause the debugging is showing as - 0x200148FC
it jumped to 0x004220f9
the same as the one it jumped to - 0x004220f9
The disassembly show that I'm stuck in an infinte loop;
0042206C b #-4
I assume this is an error trap to stop the processor just running off and doing crazy things.
I will try your suggested restart code.
I tried this code ;
Here's the output of my boot loader
-- Boot Loader --
VTOR:0x00400000 <- I have a printf to show me the current VTOR value
BootLoader Starting....
BootVTORValue = 0xffffffff <- This is the value read from flash location 0x00420004, before receiving the code
waiting..... for 165 bytes <- this is my code waiting for data
PageNumber:511 <- This is the code showing it has recived 512 pages (each being 256 bytes, so 64K)
65536 Bytes Page Written to 00420000 <- This is showing
Wait For Flash Ready <- Pause whilst flash writes
NewBootVTORValue = 0x004220f9 <- This is the value read from flash location 0x00420004, after receiving the code
reboot <- This is sent by the bootloader just before jumping to the new code.
stack overflow 20015b68 Monitor <- this is what I got after trying your code.
At this point, the PC is wrong, it's showing - 0x0040660A
The SP is showing - 0x20014AC0
I just checked the code in flash;
:020000040042B8
:10000000A0450020F92042006920420069204200FA
Pulling out the first 32bit word in the VTOR gives me the SP; A0450020
Putting that the correct way round gives; 200045A0,
Stepping through the code, after this line has run - asm volatile ("ldr sp,[%0,#0]": "=r" (v) : "0" (v));
it does indeed show SP as 200045A0
However when the next line - ((start_fn *) *((uint32_t *) 0x00420004))();
Causes the stack overflow but the PC is showing as 0x0040660A, so is in the boot loader code rather than the application code.
I don't know the meaning of ":10000000" but it seems that the SP and PC initial values are respectively 0x200045A0 and 0x004220f9 from the code.What is the meaning of "when the next line - ((start_fn *) *((uint32_t *) 0x00420004))();"?I think the next step of the line would be 0x004220f9.Can you show us the dis-assembly code around 0x0040660A?
Hello again Paul,
it is the Intel Hex, isn't it?I understand and it would be reasonable.However, it is strange "((start_fn *) *((uint32_t *) 0x00420004))()" causes a stack overflow.Did you set the stack pointer before execution the asm statement?Otherwise, you should add the "__attribute__((naked))" attribute to the bootloader function in order not to use stack.
I have found the problem
It would seem that on boot a number of things are 'assumed' as being in a certain state by the compiler.
If I disable the global interrupts, cpu_irq_disable() , before jumping, and then re-enable them, cpu_irq_enable() in the application, it works.
My next challenge is reading and writing a single value to a specific location in flash (say 0x0048FFFF) so I can detect if I should be self writing or jumping to the application.
I am afraid to change a single position of a flash would be impossible as the flash should be block erased before writing a new code.
If you want to do so, you can copy the whole data of the flash block to SRAM, changing a value on the SRAM and write back to the SRAM contents to the flash.