Tranferring execution from custom bootloader to system code - LPC1853

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Tranferring execution from custom bootloader to system code - LPC1853

1,502 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by dodge55 on Sat Mar 21 08:53:19 MST 2015
I have an older project using a LPC2148 that has a custom bootloader and if certain criteria are met, transfers execution to the system code located at a different location.  However, the same syntax isn't working for the LPC1853. 

The bootloader is placed at 1A000000.  The system code is placed at 1A006010.  The bootloader code runs fine until the system code transfer call is executed.

In debug (using Keil), I placed a breakpoint on the transfer call.  The assembly statement is BLX r4.  'r4' holds 0x1A006010, as I would expect.  When the statement is executed, I get a HardFault.

Here are the items of interest for the call.

#define SYSTEMBEGIN  (volatile unsigned char *) 0x1A006010
typedef void (*SYSTEM_APP)(void);

SYSTEM_APP system_app = (SYSTEM_APP)SYSTEMBEGIN;

system_app();

This syntax works perfect for the LPC2148, but not for the LPC1853, unless I'm missing something else.

Any help.

Thanks,

Sutton
Labels (1)
0 Kudos
27 Replies

1,412 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by dodge55 on Sun Mar 22 20:55:17 MST 2015
Thank you.  Thank you.  Thank you.  Got it working.

I forgot to comment out a call to the Keil called System_Init routine in the application startup file.
0 Kudos

1,412 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by R2D2 on Sun Mar 22 18:56:54 MST 2015

Quote: dodge55
Where could that be getting changed?



In your application startup   :O

http://www.lpcware.com/content/faq/lpcxpresso/debug-from-reset
0 Kudos

1,412 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by dodge55 on Sun Mar 22 18:14:22 MST 2015
I noticed something.  My custom bootloader starts at 0x1A000000.  SCB->VTOR is set to 0x1A000000.  Right before the transfer to my user application at 0x1A006000, I set SCB->VTOR to 0x1A006000.  SCB is located at 0xE000ED00.  If I look at memory 0xE000ED00, it is 0x1A006000.  Perfect.  After the transfer happens to 0x1A006000,  SCB->VTOR is set back to 0x1A000000 somewhere before stopping at the first statement in main().  Therefore, it is not looking at the new relocation vector area.  Where could that be getting changed?
0 Kudos

1,412 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by mc on Sun Mar 22 13:15:19 MST 2015
Check app note here.
http://www.lpcware.com/content/nxpfile/an11651-lpc18xxsecondaryusbhostbootloader
0 Kudos

1,412 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by dodge55 on Sun Mar 22 10:39:33 MST 2015
I'll check the vector table.  I confirmed that Sys_Tick() is not working either in application code (but works in bootloader code).  The interrupt is not firing, just like with T0 and T1.
0 Kudos

1,412 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by mc on Sun Mar 22 10:26:43 MST 2015
Other than interrupt settings pointed out by others try to use DSB instruction just after setting VTOR reg.
0 Kudos

1,412 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by R2D2 on Sun Mar 22 10:23:45 MST 2015

Quote: dodge55
Not sure if that's part of the issue.



Is your application vector table pointing to this ISR addresses?
0 Kudos

1,412 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by dodge55 on Sun Mar 22 10:14:39 MST 2015
No change with your MEMMAP addition.  Timers still don't trigger interrupts in application code.
0 Kudos

1,412 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by mc on Sun Mar 22 09:53:50 MST 2015
Hi dodge55,
LPC1853 has MEMMAP register. Instead of VTOR try to use M3MAP register  as below.

*(volatile unsigned int *)0x40043100 = 0x1A006000;
0 Kudos

1,412 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by dodge55 on Sun Mar 22 09:49:45 MST 2015
Yes, the code works without timers.  Neither Timer0 nor Timer1 are working in the application code.  I noticed that in the bootloader, Timer0_IRQHandler is placed at 0x1A001D4C and Timer1_IRQHandler is placed at 0x1A001DAC.  In the application code, Timer0_IRQHandler is placed at 0x1A009A80 and Timer1_IRQHandler is placed at 0x1A009AE0.  That seems way off as far as the offset from the starting code point of 0x1A006000.  Not sure if that's part of the issue.
0 Kudos

1,412 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by R2D2 on Sun Mar 22 09:41:00 MST 2015

Quote: dodge55
It acts like the interrupt vector is not correct.  If I put a breakpoint in the bootloader Timer1 interrupt, it stops when the timer expires.  It doesn't break in the application code at the same place, but the interrupt bit is set.



If your application is working without interrupts it's time to check their settings  :O

Add __enable_irq() to you application code (just to ensure that interrupts are enabled)...

Then check your NVIC, if Timer1 interrupt is enabled...

Use another Interrupt (SysTick) and check if that interrupt is executed...

Read your (application) vector table and check correct timer1 interrupt address...

0 Kudos

1,412 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by dodge55 on Sun Mar 22 09:29:30 MST 2015
It acts like the interrupt vector is not correct.  If I put a breakpoint in the bootloader Timer1 interrupt, it stops when the timer expires.  It doesn't break in the application code at the same place, but the interrupt bit is set.
0 Kudos

1,412 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by dodge55 on Sun Mar 22 09:25:09 MST 2015
I noticed that and I changed it to 0x1A006000 as well.  I had a 16 byte address at that location, for misc. settings (version, time, date, etc.).  But, I moved that to the end of the code space and moved my application code starting point to 0x1A006000.  The bootloader now transfers to the application code fine.  But, Timer1 isn't functioning correctly (used in my delay routines).  It looks like the match is happening and the interrupt bit is set, but the interrupt isn't firing.  Thus, the delay routine never ends.
0 Kudos

1,412 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by R2D2 on Sun Mar 22 09:23:28 MST 2015

Quote: dodge55
The  __disable_irq () / __enable_irq() combination hasn't worked and everything is cleared that I know of.  Actually, I am using the exact same Timer0_setup() and Timer1_setup() routines in both the bootloader and application code.



It's important to debug your code as described in link above. Is your application working correct without timer interrupt?


0 Kudos

1,412 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by mc on Sun Mar 22 09:12:00 MST 2015
Hi dodge,
I also changed your application starting address from 0x1A006010  to 0x1A006000 in my original post for correct alignment. Could you please check after modifying this address? It should work now.
0 Kudos

1,412 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by dodge55 on Sun Mar 22 08:54:57 MST 2015
The  __disable_irq () / __enable_irq() combination hasn't worked and everything is cleared that I know of.  Actually, I am using the exact same Timer0_setup() and Timer1_setup() routines in both the bootloader and application code.  No differences (two instances of same code in both bootloader and application code space).  I didn't have __enable_irq(), because I thought that setting up the Timer routines again would reverse the __disable_irq().  But, I put that in the application code, but it didn't make any difference.

Sutton
0 Kudos

1,412 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by MikeSimmonds on Sun Mar 22 02:48:01 MST 2015

Quote: dodge55
Many thanks for your help.  It almost works.  Actually, it does transfer to the user code now.  But, it hangs because my timer interrupt doesn't work.  The same Timer0 interrupt that is used in the bootloader, doesn't run in the user code.  I am resetting up Timer0 and other interrupts totally independent from the bootloader, but Timer0 doesn't run.  So, I'm trying to figure that out.

Sutton



When you resetup the timer interrupt, are you (a) clearing any pending interrupts, (b) clearing any interrupt status in
the timer, (c) actually enabling the timer interrupt in both the timer and the NVIC?

Cheers, Mike
0 Kudos

1,412 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by R2D2 on Sun Mar 22 00:27:49 MST 2015

Quote: dodge55
So, I'm trying to figure that out.



Did you __disable_irq () / __enable_irq() in your bootloader / application?
0 Kudos

1,412 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by dodge55 on Sat Mar 21 22:08:21 MST 2015
Many thanks for your help.  It almost works.  Actually, it does transfer to the user code now.  But, it hangs because my timer interrupt doesn't work.  The same Timer0 interrupt that is used in the bootloader, doesn't run in the user code.  I am resetting up Timer0 and other interrupts totally independent from the bootloader, but Timer0 doesn't run.  So, I'm trying to figure that out.

Sutton
0 Kudos

1,412 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by mc on Sat Mar 21 12:47:00 MST 2015
Hi,
As mentioned by others Cortex M is different than ARM7. Its vector table contains address not instruction and first entry is stack pointer.
I think, you will need below code in your boot loader to jump to application code which starts from 0x1A006010 . Assuming your application vector table starts from 0x1A006010 and you are using Keil tool. I modified your code and is below.

#define SYSTEMBEGIN  0x1A006000 

typedef void (*SYSTEM_APP)(void);

SYSTEM_APP system_app ;

static uint32_t JumpAddress = *(volatile uint32_t *)(SYSTEMBEGIN+4);

system_app =  (SYSTEM_APP )JumpAddress ;

//Set stack pointer
__set_MSP(*(volatile  uint32_t*)SYSTEMBEGIN);  

SCB->VTOR = SYSTEMBEGIN & 0x3FFFFF80;

system_app();


EDIT: Changed Address from 0x1A006010  to 0x1A006000
0 Kudos