Jumping from bootloader to main application on SAMD51

Go To Last Post
12 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi all,

 

I am working on a customer bootloader, but I can't get the bootloader code to jump to the main application code.

 

Almost every bootloader I have seen out there uses this code to make the jump:

 

    app_start_address2 = *(uint32_t *)(APP_START_ADDRESS +4);
        /* Re-base the Stack Pointer */
        __set_MSP(*(uint32_t *) APP_START_ADDRESS);

        /* Re-base the vector table base address */
        SCB->VTOR = ((uint32_t) APP_START_ADDRESS & SCB_VTOR_TBLOFF_Msk);

        /* Jump to application Reset Handler in the application */
        asm("bx %0"::"r"(app_start_address2));

 

 

My APP_START_ADDRESS is 0x4000, and I have comfirmed that from reading the Flash, the application code is there.  Any idea why it may not be working?

 

I am pretty fuzzy on:

        /* Re-base the vector table base address */
        SCB->VTOR = ((uint32_t) APP_START_ADDRESS & SCB_VTOR_TBLOFF_Msk)
;

 

Not exactly sure if my SCB_VTOR_TBLOFF_Msk is correct.

 

Also, not sure why it jumps to the application code at APP_START_ADDRESS +4.  I don't think there is anything special I need to do on my app code except place it at 0x4000 which I have confirmed?

 

Anybody have this working on a SAMD51 who could share this jump-out-of-bootloader code?

 

One more question, when erase the chip and put my app code at 0x4000, (No bootloader, all data below 0x4000 is 0xff)  it does not start up.  Should it?

 

Thanks -Troy

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Looks like I need to issue a reset using the application_code_entry();, but I can't find an example of this routine, will hunt around for it.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am making progress on this issue.  The problem is that my main application is crashing because it is trying to re-init things already done in the boot code.

 

I am now working through my code to make sure things only get initialized once, either in the boot code or the app code, but not both.

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Got my bootloader working.  If anyone sees this thread in the future and needs help, message me.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey Troy,

 

I'm working through this same issue right now on a samd51.  Could you share any hints as to what your solution was?

 

Thanks,

Keith

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Keith and all.  Here is the exact code that successfully jumps from the bootloader to the application at 0x4000.  This is working in my SAMD51.  As I explained in my earlier comments, I was confused for awhile because this code was working fine, but certain configuration steps were happening twice (once in the bootloader, once in the main app), and that was crashing my code.  I would recommend starting your app code as soon as possible with a very simple routine like an output pin toggle.  That way, you can insure that jump to the app code was successful, and not a crash during app code configuration.

 

uint32_t APP_START_ADDRESS        =    0x4000;
uint32_t app_start_address2;

    app_start_address2 = *(uint32_t *)(APP_START_ADDRESS +4);
        /* Re-base the Stack Pointer */
        __set_MSP(*(uint32_t *)APP_START_ADDRESS);

        /* Re-base the vector table base address */
        SCB->VTOR = ((uint32_t)APP_START_ADDRESS & SCB_VTOR_TBLOFF_Msk);

        /* Jump to application Reset Handler in the application */
        asm("bx %0"::"r"(app_start_address2));

 

Also, are you sure your app code is being put in the right place?  You can read your .hex file off the chip and check it in a hex editor.  I have this in my linker flags on the main app:

-Wl,--section-start=.text=0x4000

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the response!

 

Reading through that I notice that I wasn't adding 4 to my jump target

 

(APP_START_ADDRESS +4)

 

Changed that I the jump worked.

 

What were the configuration steps that you had to avoid doing twice?  We have a few things like SEEPROM and CRC32 that we want to run in both the bootup code and the application, wondering if we will run into issues there.

 

Thanks,

Keith

 

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I forget exactly, but double configs were a problem.  Once I carefully separated out configs done by the bootloader and those done by the main app, things worked fine.  Glad you got your jump working!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello troy2323,

 

I know this is an old thread but hopefully I can find some answers. Does this needs to be in one binary file? i.e. jumping code as one binary and the main code as another?

How I tried to do this is as follows:
1. Compile the jump code  and write it to the the flash from 0x0000 to whatever the end address is. In my case it was at 0x46C3.
2. I then compiled the main code and wrote it to the flash starting from 0x5000. 

Jump code was adjusted to jump to 0x5000 and the starting address of flash was adjusted to 0x5000 in the linker script. But still it doesn't seem to be working. Any thoughts?

 

Thanks in advance. 

Last Edited: Tue. Jan 19, 2021 - 08:29 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You need to compile two separate programs, combine them, then load the combined file.

 

1) Compile the jump code to get jump.hex

2) Compile the app code to get app.hex, make sure the linker script is changed to relocate the app at a higher address than the jump code

3) Combine the two hex files, use

srec_cat jump.hex -Intel app.hex -Intel -o combined.hex -Intel

You will find a copy of srec_cat, which was installed by Atmel Studio in the "C:\Program Files (x86)\Atmel\Studio\7.0\shellutils" folder.

 

4) Load combined.hex using tools->device programming in Atmel Studio.  Go to the memories tab, and browse for the combined.hex file.

 

The reason your test failed is because the flash was erased when you loaded the second file. 

 

 

John Malaugh

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

malaugh wrote:
You need to compile two separate programs, combine them, then load the combined file

:

:

The reason your test failed is because the flash was erased when you loaded the second file. 

Alternatively, don't erase the entire flash before programming the app - so that the bootloader is left intact

 

there should be an option for this

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello all,

 

Thank you very much for your replies. I tried the above mentioned methods and am still unable to make the code work. Really appreciate if you can have a look at my code.

 

For the jumper code I am using the same as what Troy has mentioned but also clearing the interrupts before calling the asm function.

 

uint32_t APP_START_ADDRESS        =    0x4000;
uint32_t app_start_address2;

// Initialize C library
extern "C" void __libc_init_array(void);

int main() {
	//__libc_init_array();

	//delay(1);

	app_start_address2 = *(uint32_t *)(APP_START_ADDRESS +4);
	__set_MSP(*(uint32_t *)APP_START_ADDRESS);
	SCB->VTOR = ((uint32_t)APP_START_ADDRESS & SCB_VTOR_TBLOFF_Msk);

	NVIC_ClearPendingIRQ(NonMaskableInt_IRQn);
	NVIC_ClearPendingIRQ(HardFault_IRQn);
	NVIC_ClearPendingIRQ(MemoryManagement_IRQn);
	NVIC_ClearPendingIRQ(BusFault_IRQn);
	NVIC_ClearPendingIRQ(UsageFault_IRQn);
	NVIC_ClearPendingIRQ(SVCall_IRQn);
	NVIC_ClearPendingIRQ(DebugMonitor_IRQn);
	NVIC_ClearPendingIRQ(PendSV_IRQn);
	NVIC_ClearPendingIRQ(SysTick_IRQn);

	for(int i=0; i <136; i++){
		NVIC_ClearPendingIRQ((IRQn_Type)i);
	}
	NVIC_ClearPendingIRQ(PERIPH_COUNT_IRQn);

	asm("bx %0"::"r"(app_start_address2));

 

I compile this code with flash originating at 0x0000(please refer fig 1). I have made sure this code doesnt surpass 0x4000.

 

Next I compiled the main app code with flash originating at 0x4000(please refer fig 2).

 

Then I combine the two hex codes and write it to the flash. PS: Both codes were compiled with the linker script not requiring the bootloader. So in the atmel studio I burnt the code to the flash starting from 0x0000.