2nd bootloader - Requiring the same interrupt in bootloader and main application

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

2nd bootloader - Requiring the same interrupt in bootloader and main application

1,535 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by sTs on Thu Sep 13 08:20:26 MST 2012
Hi,
I'm having troubles with vector table remapping on LPC1114 (Cortex-M0).
As long as I'm not using the same kind of interrupt in both the 2nd bootloader part and the actual application, all goes well. But I need the I2C_IRQHandler(void) in both (with a different implementation).

Remapping is by default like this (if you don't need i2c in the bootloader), as given by AN10995:
  void I2C_IRQHandler(void) __attribute__ (( naked ));
  void I2C_IRQHandler(void)
  {
    asm volatile("ldr r0, =0x107C");
    asm volatile("ldr r0, [r0]");
    asm volatile("mov pc, r0");
  }
And indeed, this starts the main application correctly.

However, as I need also i2c in the bootloader (but a different implementation), a thought the function should be adapted to something like this (but I can't get it to work):
  //void I2C_IRQHandler(void) __attribute__ (( naked ));
  void I2C_IRQHandler(void); //else I can't do anything else but the asm-lines in the handler
  void I2C_IRQHandler(void)
  {
    if ( valid_application_available == 0 )
    {
      asm volatile("ldr r0, =0x107C");
      asm volatile("ldr r0, [r0]");
      asm volatile("mov pc, r0");
    }
    else
    {
      i2c_from_bootloader();
    }
  }

It seems like removing the __attribute__ part from the declaration, is already enough to make things crash... (but keeping it also doesn't work :confused:)

So I'm a bit stuck here... If someone has some tips ?
0 Kudos
9 Replies

1,133 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Lea on Sat Feb 13 07:56:50 MST 2016
I try to write a secondary CAN bootloader, too
Have you found a solution for this problem?

Until now I can flash only firmware which use no interrupts.  :~
0 Kudos

1,134 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by bomba82 on Wed Jan 22 05:57:45 MST 2014
It was 2 days I was working on this and I resolved it 1 hour later than previous post.

Just for information I can say that relocation of interrupt vectors must be executed at the beginning of the final application. I already tried that and it was not working becasue I didn't disable interrupts in the bootloader. Now my jump function is like hereafter:
void Bootloader_JumpToApplication()
{
[color=#f03]__disable_irq();[/color]

//Load main stack pointer with application stack pointer initial value,
//stored at first location of application area
asm volatile("ldr r0, =0x4000");
asm volatile("ldr r0, [r0]");
asm volatile("mov sp, r0");

//Load program counter with application reset vector address, located at
//second word of application area.
asm volatile("ldr r0, =0x4004");
asm volatile("ldr r0, [r0]");
asm volatile("mov pc, r0");

//User application execution should now start and never return here....
}


The key for resolving my problems was the "__disable_irq();" instruction.
0 Kudos

1,134 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by bomba82 on Wed Jan 22 04:18:30 MST 2014
Hello,
  I am new to the forum. I started developing on a LPC11C24 about 2 months ago and I already took advantage from suggestions found on this forum. This time I can't solve my problem, so I have to ask for your help.

I am trying to implement a second booloader and I have the same problem as Almaz. Can someone suggest a solution for that?

I tried to follow AN10995, but I think it doesn't fit to my case. I need to implement a CAN bootloader and I also need the ISR for SSP, so I think that the technique of redirecting interrupts is not right for me.
I tried to remap to RAM. My code is as follows:
#define vector_in_ram((int32_t *) 0x10000000)
void Bootloader_JumpToApplication()
{
int i = 0;

__disable_irq();
// remap the interrupt vectors to the start of the code loaded in memory
int32_t *p = (int32_t *) 0x4000;
// copy the interrupt vector table on base RAM
for (i=0;i<128;i++)
{
vector_in_ram = *p;
p++;
}
LPC_SYSCON->SYSMEMREMAP = 0x1;  // remap the interrupt vectors to ram

//Load main stack pointer with application stack pointer initial value,
//stored at first location of application area
asm volatile("ldr r0, =0x4000");
asm volatile("ldr r0, [r0]");
asm volatile("mov sp, r0");

//Load program counter with application reset vector address, located at
//second word of application area.
asm volatile("ldr r0, =0x4004");
asm volatile("ldr r0, [r0]");
asm volatile("mov pc, r0");

//User application execution should now start and never return here....
}


After executing
asm volatile("mov pc, r0");
my program stops execution. If I execute the bootloader application in debug mode it stops with the message: No source available for "0x1fff10ac". I attach an image as an example.

I can't understand if my bootloader is wrong or if the binary of my application is wrong.

Please tell me if you need any other information to understand what I am doing.

0 Kudos

1,134 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Almaz on Thu Sep 27 23:47:05 MST 2012
How to be in case of using lpc11c24? In the manual for this microcontroller is written:

Quote:
On-chip
RAM from address 0x1000 0050 to 0x1000 00B8 is used by the CAN API. This address
range should not be used by the application. For applications using the on-chip CAN API,
the linker control file should be modified appropriately to prevent usage of this area for
application’s variable storage.


And I plan to use the CAN API functions (also i plan to use interrupts) both in the bootloader and working program. 
Therefore remapping can't help.
0 Kudos

1,134 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by sTs on Fri Sep 14 05:06:00 MST 2012
Thanx to all. It works now. :cool:
I've added the following code to my main application, found in another thread. Special thanx to mmoyano for the code and ArtjomGromak for the hint to move to RAM.
I have now the same interrupt (with different handler functionality) in both the 2nd bootloader and the main application.

  #define VECTOR_IN_RAM_LENGTH  47   //stackpointer not counted
  uint32_t vector_in_ram[VECTOR_IN_RAM_LENGTH] __attribute__ ((section ("vtable")));

  uint32_t *p = (uint32_t *) 0x1000;

  __disable_irq();
  // copy the interrupt vector table on base RAM
  for (i=0; i<VECTOR_IN_RAM_LENGTH; i++)
    vector_in_ram = *(p + i);
  LPC_SYSCON->SYSMEMREMAP = 0x1;
  __enable_irq();
0 Kudos

1,134 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by ArtjomGromak on Thu Sep 13 18:24:14 MST 2012

Quote: kayoda

What you are describing is 'redirecting' :)


I describe?
No, NXP described.
From User manual:

Quote:

3.5.1 [B]System memory remap[/B] register
The system memory remap register selects whether the ARM interrupt vectors are read
from the boot ROM, the flash, or the SRAM. By default, the flash memory is mapped to
address 0x0000 0000. When the MAP bits in the SYSMEMREMAP register are set to 0x0
or 0x1, the boot ROM or RAM respectively are mapped to the bottom 512 bytes of the
memory map (addresses 0x0000 0000 to 0x0000 0200).


It is remapping.



Quote: kayoda
I think in this context 'remapping' means changing vector table address via VTOR (Vector Table Offset Register) ;)



In Cortex-M0 VTOR not implemented (RZWI).
0 Kudos

1,134 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by ex-kayoda on Thu Sep 13 17:46:28 MST 2012

Quote: ArtjomGromak
It is incorrect method?



I think in this context 'remapping' means changing vector table address via VTOR (Vector Table Offset Register) ;)

What you are describing is 'redirecting' :)
0 Kudos

1,132 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by ArtjomGromak on Thu Sep 13 14:30:13 MST 2012

Quote: sTs
, as given by AN10995:
  void I2C_IRQHandler(void) __attribute__ (( naked ));
  void I2C_IRQHandler(void)
  {
    asm volatile("ldr r0, =0x107C");
    asm volatile("ldr r0, [r0]");
    asm volatile("mov pc, r0");
  }



Why you don't use remapping of vector table in RAM?
My code:
Bootloader.
uint8_t volatile TickWas;
uint32_t volatile Timeout;
uint32_t volatile EnableStartApplication;
void SysTick_Handler(void)
{
TickWas=1;
if (++Timeout>1000)
EnableStartApplication=1;

}
typedef void (*ISRPtr) (void);
void main()
{

SysTick_Config(48000);
BootRxTx();// new firmware receive and programming
if (EnableStartApplication) {// 
uint32_t crc;
uint32_t version_crc;

crc=GetFlashCRC();// get application crc
version_crc=*(uint32_t *)0x1000;// read crc from address 0x1000
if (crc==version_crc) {
__disable_irq();
// load application MSP 
__set_MSP(*(uint32_t *)0x1004);
// start application Reset_Handler 
ISRPtr application_reset_handler=(ISRPtr)(*(uint32_t *)0x1008);
application_reset_handler();
}
else
NVIC_SystemReset();// reset if application sum fail
}
}

Application.
uint8_t volatile TickWas;
void SysTick_Handler(void)
{
TickWas=1;
SystemTimerMs++;
}

#define LPC11XX_VECTOR_QTY 47
typedef void (*ISRPtr) (void);
struct TLPC11xxVectorTable {
    ISRPtr StackPtr;
    ISRPtr ResetISR;
    ISRPtr Reserved0[9];
    ISRPtr SvcISR;
    ISRPtr Reserved1[2];
    ISRPtr PendSvcISR;
    ISRPtr SysTickISR;
    /* Device interrupt vectors */
    ISRPtr WakeUpISR[13];
    ISRPtr Reserved2;
    ISRPtr Ssp1ISR;
    ISRPtr I2cISR;
    ISRPtr Timer16_0_ISR;
    ISRPtr Timer16_1_ISR;
    ISRPtr Timer32_0_ISR;
    ISRPtr Timer32_1_ISR;
    ISRPtr Ssp0ISR;
    ISRPtr UART_ISR;
    ISRPtr Reserved3[2];
    ISRPtr ADC_ISR;
    ISRPtr Wdt_ISR;
    ISRPtr Bod_ISR;
    ISRPtr Reserved4;
    ISRPtr EINT3_ISR;
    ISRPtr EINT2_ISR;
    ISRPtr EINT1_ISR;
    ISRPtr EINT0_ISR;
};
TLPC11xxVectorTable IsrTable __attribute__ ((__section__(".IntVecTable")));
void main ()
{
ISRPtr *isr_ptr=&IsrTable.ResetISR;
for (i=0; i<(LPC11XX_VECTOR_QTY); i++)
*isr_ptr++=Default_Handler;

uint32_t *dest=(uint32_t *)&IsrTable;
const uint32_t *src=(const uint32_t *)APPLICATION_START_ADDRESS;
for (i=0; i<LPC11XX_VECTOR_QTY; i++)
*dest++=*src++;

IsrTable.SysTickISR=SysTick_Handler;
SysTick_Config(48000);
mhile (1) {}
}


It is incorrect method?
0 Kudos

1,132 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by ex-kayoda on Thu Sep 13 08:47:03 MST 2012

Quote: sts
so i'm a bit stuck here... If someone has some tips ?



an10995:


Quote:

3.1 handling interrupts
when an application is developed, the contents of the interrupt vector table are created at build time. The vector table is then placed in memory at a fixed location (known to the processor) when the application is programmed into the flash.
On the lpc1100 the vector table is located in the same area of flash memory as the secondary bootloader. The secondary bootloader is designed to be permanently resident in flash memory and therefore it is not possible to update the contents of the vector table every time a new application is downloaded.
[COLOR=red]the cortex-m3 core allows the vector table to be remapped; however this is not the case with the cortex-m0.[/COLOR] because of this,[COLOR=red] the secondary bootloader has been designed to redirect the processor to the handler[/COLOR] listed in a vector table located in the application area of flash memory, see fig 4.

0 Kudos