Hi guys,
I am using an LPC1758 (KEIL MCB1700) with uvision 5. I am trying out an alternative to bootloading. Is it possible to flash three separate KEIL projects (HEX or otherwise) to memory.
The plan is to have 2 different applications (Blinky1 and Blinky2) at 2 different locations and have a separate application that will point to and run either of these flashed at address 0x00.
Blinky1 and Blinky2 having already been compiled to a HEX file and verified to work if flashed at address 0x00.
So for example Blinky1 will be located at 0x2000 and Blinky2 will be located at 0x4000 and the third project will run these two functions at these addresses as seen in the code below.
#include "LPC17xx.h" #define AP_ADDR 0x2000 // where the user app located #define AP_ADDR2 0x4000 // where the user app located typedef void (*FP)(void); /** run the user application from pre-specified address*/ void Run_Blink1() { FP fp; fp = (FP)AP_ADDR; (*fp)(); } void Run_Blink2() { FP fp; fp = (FP)AP_ADDR2; (*fp)(); } int main(){ while(1){ Run_Blink1(); Run_Blink2(); } }
I'm pretty new to embedded and not quite sure where to start. If this is possible how would one go about separately flashing each of these HEX files at the specified locations? The idea is that we can use IAP to update a function, sort of like a live firmware update.
Thanks in advance for any and all help, even if it's just a link to point in the right direction.
regards Nick
Actually, your third program is indeed, a bootloader - not an alternative. You can achieve your goal by either introducing a custom linker script (check your linker tab in the project settings and read the user manual for the linker) or, if your image is simple enough, use the GUI to setup the entry addresses (see the Target page for that). Don't forget to remap vector table at the beginning of the applications you introduced.
@Tamir Michael, Thanks. Yeah I initially wanted to try a super simple example (no interrupts). I tried using the target GUI page but can't seem to get anything working. So what I did was first erase the entire flash. Then for Blink1 I went to the target page and setup the "Read/Only memory address" IROM1 start:0x2000 with size 0x2000. I then then did the same for Blink2 and set start: 0x4000 and for the functionpoint(3rd project) set start to :0x00. The Startup radio button is always selected for all three projects.
All three projects where configured in linker page to use memory layout from target dialog. When flashing I ensure that I erased the entire flash and that the flash settings did not erase before flashing.
I then individually flashed all three projects separately with no results.
And it also seems depending on the order I flash that when I flash the functionpointer last I get a Cortec-M3 error, with Contents mismatch at: 0000001CH (Flash=06H Required=F6H). So it seems that the first two projects are writing something at 0x00 even thought the target is set elsewhere.
I also tried setting "Make RO sections position Independent" in the two blink projects with no change.
Any advice? Thanks again Nick
As far as I can see, your just code is incorrect. Note that Cortex devices store the inital PC and stack address in the first 8 bytes of the image to boot, which has implications for a bootloader:
__asm void jump_to_application( uint32_t address ){ LDR SP, [R0] ;Load new stack pointer address LDR R0, [R0, #4] ;Load new program counter address BX R0 }
Hi @Tamir Michael, which code is incorrect? I have seen that code in the bootloader examples but it confuses me because it receives uint32_t address but does nothing with it? Are you implying that the code you just posted should replace?:
void Run_Blink1() { FP fp; fp = (FP)AP_ADDR; (*fp)(); }
Sorry, up until now I've been working with SPI interfaces so bootloading is very new. I assumed I do not need to do any vector remapping because I'm not using interrupts but am now thinking that the startup_LPC17xx.s might need this. Not sure to what address a vector should be remapped to though?
Thanks again, really appreciate it. Nick
The first argument in the function I posted is mapped to R0. Yes, you should replace that code.
@Tamir Michael, Unfortunately no luck:( i tried replacing with your suggested code with no result. I then also had a look at the USB bootloader and my current bootloader code looks like:
#include "LPC17xx.h" #define AP_ADDR 0x4000 // where the user app located #define AP_ADDR2 0x9000 // where the user app located //typedef void (*FP)(void); /** run the user application from pre-specified address*/ __asm void boot_jump( uint32_t address ){ LDR SP, [R0] ;Load new stack pointer address LDR PC, [R0, #4] ;Load new program counter address } void Run_Blink1(void) { /* Change the Vector Table to the USER_FLASH_START in case the user application uses interrupts */ SCB->VTOR = AP_ADDR & 0x1FFFFF80; boot_jump(AP_ADDR); } void Run_Blink2(void) { /* Change the Vector Table to the USER_FLASH_START in case the user application uses interrupts */ SCB->VTOR = AP_ADDR2 & 0x1FFFFF80; boot_jump(AP_ADDR2); } int main(){ while(1){ Run_Blink1(); Run_Blink2(); } }
I am unsure if I have to change any code/ setup in the Blink projects other than the R/O memory start address?
You need to provide more information. Did you stepped through the jump code? what happens if you set a breakpoint in the startup code of application 1? Surely you understand that an application does not return, by definition: thus, you would need to do something like this:
int main() { if (some condition) Run_Blink1(); else Run_Blink2(); while (1) ; }
@Tamir Michael, Hi tbh I didn't realize I could step through the code so that was a great help. Also I had a feeling the application would not return but A) Thought that it shouldn't matter as it would go to application 1 and stay there and B) Was just curios where the PC would go after application one was done (answer nowhere interesting).
I actually got it working and it was something very simple. I was looking around in: target options->Debug->J-Link settings(or Ulink etc)->Flash Download. Under program Algorithm I changed the start address and size for application1 and application2 to match the target address settings, and then it worked.
I think the reason is because in most applications, Users use IAP to load new firmware to the flash but since I am using the keil flash tool I needed to ensure that "new" firmware didn't affect address 0x00 where the bootloader is? I will eventually get an IAP application going to write the new firmware.
I will now try the Blink applications with interrupts and see if that also works. If you think it will help I can post the full solution? Let me know if it's useful or not?