How to jump to a Specific Address on Flash?

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

I have been able to write a custom bootloader. I can write my data to address 0x0000 in Flash and jump to it. But I want to write 2 applications to the Flash. For this, I first tried to write the same application to the 0x0200 instead of 0x0000. I have been able to write it there successfully. But I can not jump there. I am also getting a compiler warning to that address. Below is the code snippet for application1. It is working successfully. I write 2 page to flash which is my test application1. Then I jump to it.

 

void PMIC_SetVectorLocationToBoot( void )
{
    uint8_t temp = PMIC.CTRL | PMIC_IVSEL_bm;
    CCP = CCP_IOREG_gc;
    PMIC.CTRL = temp;
}

void PMIC_SetVectorLocationToApplication( void )
{
    //Set interrupt vector location to application section of flash
    uint8_t temp = PMIC.CTRL & ~PMIC_IVSEL_bm;
    CCP = CCP_IOREG_gc;
    PMIC.CTRL = temp;
}

void (*gotoappsection1)(void) = 0x0000;				//start address of application1. Starts from 0

int main()
{
    const __flash unsigned char * addr;

    addr = (void *)0;

    for(i = 0; i<128; i++)
    {
    nvm_flash_load_word_to_buffer(i*2, WORD_Array[i]);
    }

    nvm_flash_erase_app_page((uint16_t )addr);

    nvm_flash_split_write_app_page((uint16_t )addr);
    nvm_wait_until_ready();

    nvm_flash_flush_buffer();

    addr = (void *)256;

    for(i = 128; i<256; i++)
    {
    nvm_flash_load_word_to_buffer(i*2-256, WORD_Array[i]);
    }

    nvm_flash_erase_app_page((uint16_t )addr);

    nvm_flash_split_write_app_page((uint16_t )addr);

    nvm_wait_until_ready();

    PMIC_SetVectorLocationToApplication();
    EIND = 0x00;
    gotoappsection1();

}

For the second application, I only changed the flash address to be written and the jump address to be jumped. I write the app2 from byte 512 (0x0200) and then jump to address 512(0x02000). But I am getting a warning in the second function pointer. This is the warning:

 

void (*gotoappsection2)(void) = 0x0200;

 

initialization makes pointer from integer without a cast 

 

I don't get this warning for the first function pointer ( void (*gotoappsection2)(void) = 0x0000; ) 

 

Below is the second code snippet for app2.

void PMIC_SetVectorLocationToBoot( void )
{
    uint8_t temp = PMIC.CTRL | PMIC_IVSEL_bm;
    CCP = CCP_IOREG_gc;
    PMIC.CTRL = temp;
}

void PMIC_SetVectorLocationToApplication( void )
{
    //Set interrupt vector location to application section of flash
    uint8_t temp = PMIC.CTRL & ~PMIC_IVSEL_bm;
    CCP = CCP_IOREG_gc;
    PMIC.CTRL = temp;
}

void (*gotoappsection2)(void) = 0x0200;				//start address of application2. Starts from byte 512(0x0200)

int main()
{
    const __flash unsigned char * addr;

    addr = (void *)512;

    for(i = 0; i<128; i++)
    {
    nvm_flash_load_word_to_buffer(i*2, WORD_Array[i]);
    }

    nvm_flash_erase_app_page((uint16_t )addr);

    nvm_flash_split_write_app_page((uint16_t )addr);
    nvm_wait_until_ready();

    nvm_flash_flush_buffer();

    addr = (void *)768;

    for(i = 128; i<256; i++)
    {
    nvm_flash_load_word_to_buffer(i*2-256, WORD_Array[i]);
    }

    nvm_flash_erase_app_page((uint16_t )addr);

    nvm_flash_split_write_app_page((uint16_t )addr);

    nvm_wait_until_ready();

    PMIC_SetVectorLocationToApplication();
    EIND = 0x00;
    gotoappsection2();

}

Why I can jump to 0x0000 but can not do it to 0x0200 ? And why the compiler does not warn me for function pointer with 0x0000 but warns me with 0x0200?

 

This topic has a solution.
Last Edited: Tue. May 31, 2016 - 01:19 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just a concept to think about: Use a goto command, skip the function pointer stuff completely. Search "c goto"

 

 

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

Someguy22 wrote:

Just a concept to think about: Use a goto command, skip the function pointer stuff completely. Search "c goto"

 

 

 

I should search it, thanks. But I saw the function pointers in many bootloader projects. So I wanted to use it. In fact, they all were using it to jump to 0x0000 which already works for me too. Did you mean something like this? :

void *address = 0x10080000;
...
goto *address;

Just because I am getting the same warning for this statement too.

 

Last Edited: Mon. May 16, 2016 - 01:34 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I tried to add an assembly file and do the jump in there. I have been able to write it like this:

 

/*
 * jumpto.s
 *
 * Created: 16.05.2016 16:37:32
 *  Author: Onlab003
 */ 

#include <avr/io.h>
#include "gas.h"

PUBLIC_FUNCTION(jumptoapp1)

    jumptoapp1:

        jmp 0x0000


END_FUNC(jumptoapp1)

PUBLIC_FUNCTION(jumptoapp2)

    jumptoapp2:

        jmp 0x0200


END_FUNC(jumptoapp2)

 

 

But again, it works with 0x0000 but does not work with 0x02000.

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

Are you getting your 0x2000 and 0x4000's mixed up perhaps? Remember that the destination in a Jump is a word address.

 

Also silly question but why 0x2000 anyway? This is posted in the Xmega forum (Xmega have separate boot flash). To have code at 0x2000 (assuming you mean a byte address) would imply an 8K device. Is it really?

 

Did you mean 0x20000? (4 0's not three 0's)

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

In my bootloader I use:

    asm volatile("jmp 0x0000");    // Jump to Application

In my applications, to jump back to the bootloader, I use:

	asm volatile("jmp 0x1FC00")

David (aka frog_jr)

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

clawson wrote:

Are you getting your 0x2000 and 0x4000's mixed up perhaps? Remember that the destination in a Jump is a word address.

 

Also silly question but why 0x2000 anyway? This is posted in the Xmega forum (Xmega have separate boot flash). To have code at 0x2000 (assuming you mean a byte address) would imply an 8K device. Is it really?

 

Did you mean 0x20000? (4 0's not three 0's)

 

You may be right. I forgot that we need to use the word address for jump. Gonna try it now. 

 

For the second question, I only wanted to see whether I can write 2 application to flash and jump to both of them. My test applications were about 400 bytes. So I used the first 512 bytes for the first application and the second 512 byte for the second application. But yeah, I better use it from the middle of the flash.

 

Can I ask you that, is there any other works to be able to contain 2 applications in the flash? For example, do I need to add the flash section for app2 in the linker settings of app1? I actually don't even add the bootloader section in the linker settings of the application. Do you think would it be a problem? Or can make a restriction in the applications by telling them there is another application in the middle of the Flash to let it know its own size?

 

I just added 

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

in my mMiscellaneous tab in my bootloader application settings. There is nothing in the normal application settings like 

-Wl,--section-start=.text=0x0000
-Wl,--section-start=.BOOTLOADER=0x8000

It just locates the application to 0x0000 as default.

 

 

Edit: I tried to use the word address but it didn't again either. Can it be about Setting the vector locations? Because I don't actually know what does those 2 function do internally. Do I have to have separate functions for 2 separate applications?

Last Edited: Mon. May 16, 2016 - 02:19 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

abdullahcinar wrote:
For the second question, I only wanted to see whether I can write 2 application to flash and jump to both of them. My test applications were about 400 bytes. So I used the first 512 bytes for the first application and the second 512 byte for the second application. But yeah, I better use it from the middle of the flash.

But 512 bytes is neither 0x20000 nor 0x2000. It is 0x200. So you were probably jumping 16 times too far.

abdullahcinar wrote:
Can I ask you that, is there any other works to be able to contain 2 applications in the flash?

I wouldn't recommend it except to have the flash divide in THREE not two. You hold app1 at 0x2000 (say), you hold app2 at 0x4000 (say) then when you want to run one of them you SPM the whole thing (using bootloader code) from their holding place to 0x0000 and enter it there. If you don't do this you are going to have one hell of a job when it comes to interrupt vector table entries. You might be OK if these are very simple MCU programs with no interrupts used.

 

I've never really seen the appeal of 2 programs in a micro anyway. Why not just have a very high-level main() that does:

int main(void) {
    general_setup();
    // make app1 or app 2 choice
    if app1 {
        app1();
    }
    else {
        app2();
    }
}

Where app1() and app2() are effectively the whole main() of each application respectively.

 

But perhaps take a step back from all this and say what it is you are trying to achieve. It's pretty unusual to program a micro so it's an alarm clock on days of the week with an "r" in them and a hydraulic pump controller on the other days of the week. So why this desire to have two programs in one micro anyway? What is your overall design goal here?

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

clawson wrote:

abdullahcinar wrote:
For the second question, I only wanted to see whether I can write 2 application to flash and jump to both of them. My test applications were about 400 bytes. So I used the first 512 bytes for the first application and the second 512 byte for the second application. But yeah, I better use it from the middle of the flash.

But 512 bytes is neither 0x20000 nor 0x2000. It is 0x200. So you were probably jumping 16 times too far.

abdullahcinar wrote:
Can I ask you that, is there any other works to be able to contain 2 applications in the flash?

I wouldn't recommend it except to have the flash divide in THREE not two. You hold app1 at 0x2000 (say), you hold app2 at 0x4000 (say) then when you want to run one of them you SPM the whole thing (using bootloader code) from their holding place to 0x0000 and enter it there. If you don't do this you are going to have one hell of a job when it comes to interrupt vector table entries. You might be OK if these are very simple MCU programs with no interrupts used.

 

I've never really seen the appeal of 2 programs in a micro anyway. Why not just have a very high-level main() that does:

int main(void) {
    general_setup();
    // make app1 or app 2 choice
    if app1 {
        app1();
    }
    else {
        app2();
    }
}

Where app1() and app2() are effectively the whole main() of each application respectively.

 

But perhaps take a step back from all this and say what it is you are trying to achieve. It's pretty unusual to program a micro so it's an alarm clock on days of the week with an "r" in them and a hydraulic pump controller on the other days of the week. So why this desire to have two programs in one micro anyway? What is your overall design goal here?

Ups, I had a misspell there. It is 0x0200. I changed it to 0x0100 but it didn't work either.

Sorry, I didnt explain my general purpose well. I will not actually run 2 application in the micro. I want to have a backup section to prevent data loss in bootloading. If bootloading fails in the middle of the operation and if the device can not connect to the gsm, it will be in an unknown state because it will not have its app section. So I wanted to have 2 sections and use one of them as a backup for the previous application before firmware update. Would you think this is a good way? I already have host pcbboard, so i can not use am external memory.

I am using the examples for the vector locations. I actually dont know what does the SetVectorLocationtoApplication function do internally. Yes, I will use interrupts in my application. So what do I need to do the for interrupt vectors? Can you give me some sources to research about setting interrupt vectors?

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

I found this table in the datasheet:

 

Can we say that the interrupt vector table is written starting from the 0x0000 in Flash? I know that I can select the vector table to be placed in the Bootloader Section or in the Application Section. But what do we mean by application section? Does it have to be placed in the same section for each program? Or does it have to be placed in 0x0000 always?(excluding bootloader vector table) 

 

Alright, so if yes; can I still use 2 app section instead of 2 section like this:

 

The running application always must be in the address 0x0000. So before downloading the new firmware, move the current application to the second half of the flash as a backup. Then download and write the new firmware to the 0x0000. Jump to 0x0000.

 

But what I don't understand is, does the interrupt vector vary according to the application? I mean if my new firmware uses completely different interrupts, do I need to do further works before downloading the new firmware to 0x0000 ? Or, do each firmware contain its own vector table starting from its app section address? Is just writing new firmware to the 0x0000 and selecting the vector table for application enough for me? Because the application in the second half of the flash will never be executed from there, it is just for backup. If my bootloading fails and device can not connect to gsm, it can try moving the backup application to 0x0000 and running from there again.

Last Edited: Tue. May 17, 2016 - 06:54 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

abdullahcinar wrote:
Sorry, I didnt explain my general purpose well. I will not actually run 2 application in the micro. I want to have a backup section to prevent data loss in bootloading. If bootloading fails in the middle of the operation and if the device can not connect to the gsm, it will be in an unknown state because it will not have its app section. So I wanted to have 2 sections and use one of them as a backup for the previous application before firmware update. Would you think this is a good way? I already have host pcbboard, so i can not use am external memory.

Yes THAT is a good solution. But it's not what you have been talking about here. Perhaps this is just a test of the SPM but what you have been talking about is actually trying to run that second code image "out of place". On the whole (apart from bootloaders in fact!) all AVR programs are built to run at 0x0000. When they are at 0x0000 they should work just fine. While you should be able to jump into a non-interrupt, very simple code at some address other than 0x0000 then as soon as it does something absolute (like a CALL or a JMP with a fixed target address) then it may not work if it was originally built to locate at 0x0000. Say, for example, that the "CALL main" that actually starts your C code was originally at location 0x003C and it makes a CALL 0x006E to enter main(). Then if you now locate that code to 0x2000 the CALL itself will be at 0x203C but it will still be the same "CALL 0x006E" that was built originally. Nothing will have changed it to be the "CALL 0x206E" that it now needs to be.

 

This is about absolute versus relative (also known as "PIC - Positiion Independent Code"). If you can build code that only uses relative branches and calls (and even references to inbuilt strings and data tables) then it won't contain a fixed, absolute address and you should be able to place it anywhere then jump into it and it should work. But as soon as the code contains any absolute reference like the fixed target address in a CALL or JMP or a fixed data table address loaded into Z before an LPM or whatever then that code can only run at the address it was built for.

 

What you might try is for the code you plan to place at 0x200 actually build it in the first place with -Wl,-section-start=.text=0x200 which should ensure all the CALL/JMP and so on are relative to a 0x200 base address. If you now SPM the code to 0x200 and jump to it then it *should* work.

 

But this is a bad strategy because while you can arrange for all those CALL/JMP/LPMs and so on to target the right addresses the one thing you cannot change in an AVR is the location  of the interrupt vector table. Apart from the 4 options for position in the bootloader (IVSEL etc) for "normal" AVR programs htere is simply one fixed address for the IVT and that is immediately after the power-on restart jump at 0x0000.

 

As you never really intend to run the "second copy" (but only hold it there to later be SPMd down to 0) then forget all this side-track about relocating code/IVT and running the image. It's all irrelevant for your final solution. You will never actually run the "new download" where you hold it. You will always SPM it to 0 (where it was built to run) before you run it so you don't need to worry about the vectors or abs/pic code and such things.

abdullahcinar wrote:
The running application always must be in the address 0x0000. So before downloading the new firmware, move the current application to the second half of the flash as a backup. Then download and write the new firmware to the 0x0000. Jump to 0x0000.

If that's what you do then everything WILL be fine as I say - no need to worry about any of this - it's only because you are trying to run code in "the wrong place" right now.

abdullahcinar wrote:
But what I don't understand is, does the interrupt vector vary according to the application? I mean if my new firmware uses completely different interrupts, do I need to do further works before downloading the new firmware to 0x0000 ? Or, do each firmware contain its own vector table starting from its app section address? Is just writing new firmware to the 0x0000 and selecting the vector table for application enough for me? Because the application in the second half of the flash will never be executed from there, it is just for backup. If my bootloading fails and device can not connect to gsm, it can try moving the backup application to 0x0000 and running from there again.

Unless you go out of your way to stop it happening every AVR C program you build will have a full IVT on the front. Because programs (apart from bootloaders) are built to locate to 0x0000 this means that 0x0000 will, itself, have a "JUMP start" and then it will always be followed by a complete IVT in which (by default) all the entries have a "JMP bad_interrupt" (might be RJMPs for small micros). You get this table whether you use interrupts or not. But as soon as you put:

ISR(ADC_vect) {
    // code
}

Then one of those JMPs in the IVT will be changed to a JMP to this code. Most AVR programs do use interrupts in some way - so on the whole, to work correctly, they need to locate at 0x0000 so the JMP from the IVT will reach the correct place. Also the IVT itself is just part of the whole .text anyway so if you use -Wl,-section-start=.text=0x2000 (say) then you will have an IVT located just above 0x2000 which is completely pointless as the AVR will never jump via it.

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

clawson wrote:

 

 

Thank you for such clear answer! I can know understand how should I build the main operation better.

 

What you might try is for the code you plan to place at 0x200 actually build it in the first place with -Wl,-section-start=.text=0x200 which should ensure all the CALL/JMP and so on are relative to a 0x200 base address. If you now SPM the code to 0x200 and jump to it then it *should* work.

And this is a good idea to get it work in my test, I can give it a try. But as you suggested in your answer,which is clear enough to understand the way, I will run the new application always at 0x0000. My test applications were not using any interrupts, but I will be using interrupts in further works. And even if I don't use interrupts, I better do the work as you suggested -run the current application always from 0x0000.

 

Can I ask you this?:

 

Should I add this

-Wl,--section-start=.text=0x0000
-Wl,--section-start=.backup=0x2000
-Wl,--section-start=.BOOTLOADER=0x8000

to the linker settings of my normal applications? In order to have a backup in the middle of my 32K Flash, if I add the backup section command to 0x2000(byte address), does it help to let the micro know there is another section in the middle of the flash. Maybe it may prevent some unwanted access or something? Or should I just add .text=0x8000 to the bootloader application and nothing for the normal applications?

 

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

abdullahcinar wrote:
to the linker settings of my normal applications?

Only you know what ".bootloader" and ".backup" are so I cannot help with those but as for:

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

there is no point in doing that. You use -section-start's to either over-ride or add to what the default linker script will be doing anyway. By default it already positions .text at 0x0000 so there would be no point in passing that as a command too.

abdullahcinar wrote:
Or should I just add .text=0x8000 to the bootloader application and nothing for the normal applications?

Almost definitely that! (assuming 0x8000 is the right address for the BLS in this chip - I assume it must be a 32K device?).

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

clawson wrote:

abdullahcinar wrote:

to the linker settings of my normal applications?

 

Only you know what ".bootloader" and ".backup" are so I cannot help with those but as for:

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

there is no point in doing that. You use -section-start's to either over-ride or add to what the default linker script will be doing anyway. By default it already positions .text at 0x0000 so there would be no point in passing that as a command too.

abdullahcinar wrote:

Or should I just add .text=0x8000 to the bootloader application and nothing for the normal applications?

 

Almost definitely that! (assuming 0x8000 is the right address for the BLS in this chip - I assume it must be a 32K device?).

Yes, it is a 32K device. So then I have my all questions answered to move foward.

Thank you so much for your clear answers!

Last Edited: Tue. May 17, 2016 - 10:42 AM