This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

How to handle data-segments of multiple binaries persisted into flash?

Hi All.


A bit of history first.

We wish to integrate OTA in our board.

After plugging-in some logical pieces, I have figured that we will need the following architecture ::


ROM-Bootloader (constant) LOADS ===> Custom-Flash-Bootloader CALLS ===> The "main" function of Application-Binary1 or Application-Binary2

Obviously, Custom-Flash-Bootloader and Application-Binary will be flashed by us.

Also, the logic to determine which Application-Binary to call will be present in the Custom-Flash-Bootloader.

Now, obviously we will have different linker files while building the binaries for the custom-bootloader and application-binary.

In each of the linker files, the starting-flash-address will be different for the text-segment.

My question is, do the data (SRAM) segments also need to differ?

I might point out, that from the custom-bootloader, we call the "main" of application-binary by calling the code in the following-manner ::

void (*funcptr)( void );  // Set up function pointer to application
//
unsigned long funcptrAddress = *((unsigned long *)<starting-address-of-app-binary>);
funcptrAddress--;
funcptr = (void (*)())funcptrAddress;
funcptr();

Will be grateful for pointers.

Thanks and Regards,

Ajay

  • Hello Ajay

    No. Consider the custom boot loader, app1 and app2 as 3 independent programs. They all use the same SRAM and when one is running the others do not need to perform anything in the SRAM.

    Regards
    Amit
  • Hi Amit.

    Thanks for the reply.

    I had a similar thought, but the point that confuses me is when we would call the "main" of App1/App2 within the context of custom-bootloader (as per the code-snippet in my starting post in this thread).

    Wouldn't it be all in context of SRAM of custom-bootloader?

    Or the moment the "main" of App1/App2 is called, the context switches to SRAM of App1/App2 (thereby wiping all SRAM-context of custom-bootloader)?

    That would be very unlike-C, but  I am sure things are handled differently in embedded :)

    I will be grateful for clearance on this doubt.

    Thanks and Regards,

    Ajay

  • I had a similar thought, but the point that confuses me is when we would call the "main" of App1/App2 within the context of custom-bootloader (as per the code-snippet in my starting post in this thread).

    I think this is a misunderstanding. You cannot call a function (or any function) of your App2 from your App1 (custom bootloader), because you don't know where they are. The linker "once knew", but had assigned it to arbitrary addresses of his liking.

    The usual way is prepare a special linker file for your App2, to start at a segment that is updatable by the custom bootloader. And once App1 (your custom bootloader) has verified there is a valid application at this address, it just jumps to this fixed address.

    What preconditions (RAM content, initialized peripherals, clock, interrupts enabled) your App2 assume is up to you, but it must be in accordance to your bootloader. The best way is to assume nothing, and initialize everything required in App2. A common bug encountered here is the omission to de-initialize peripherals. If they had been used by App1 before, any configuration differing from the power-up default value will stick there if not set, and going to surprise you.

    Or the moment the "main" of App1/App2 is called, the context switches to SRAM of App1/App2 (thereby wiping all SRAM-context of custom-bootloader)?

    If your App2 contains the default startup code, SRAM is usually cleared. You are free to modify it, if you need.

    The notion of "context switch" is not really correct here, as this is usually associated with an OS (a third instance). App1 and App2 never run quasi-simultaneous, but always in the rigid order App1 -> App2.

  • f. m. said:
    The best way is to assume nothing, and initialize everything required in App2.

    Bravo - and SO true - assumptions (usually born of laziness) are "not" the user's friend.

    Your advice re: "preconditions" is exactly what our tests confirm to work best, robustly & avoid confusion.   And you noted the vital, "must be in accordance to user's bootloader."

    Another excellent posting - thank you, f.m.

  • Thanks a ton "f.m." and "cb1_mobile" for your precious inputs.

    I believe that the Custom-Bootloader, App1 and App2 will always have a fixed starting-address in Flash, if we keep the linker-definitions same ALWAYS? Please correct me if I am wrong.

    Kindly confirm/correct me, I will post my next level of queries/misunderstandings based on the reply to above :)

    Once again, thanks everyone for taking out the time.

    Thanks and Regards,

    Ajay

  • Hello Ajay

    The only reason I see to call functions from one App into another is to reduce the App size for common functions which may be big in size or when in numbers add up to a large size. In such a case it would rather useful to relocate such functions into a table with fixed address and let the App call the table.

    Regards
    Amit
  • No, No, No .....

    I am not at all concerned with reduced binaries-sizes, etc. Bloated binaries would work perfectly well :P

    Ok, so I guess that provided the linker-files remain the same, all 3 of Custom-Bootloader, App1, App2 will be present at the same locations in Flash; let's say at address ADD0, ADD1, ADD2 respectively.

    So, the flow would be that the ROM-Bootloader loads the Custom-bootloader.
    Then, the Custom-Bootloader would do some quick checks, and decide which of App1 (at ADD1) or App2 (at ADD2) to call.

    Let's say, it is decided that App2 (at ADD2) needs to be started.

    So, now my major concern remaining is :: How do I start executing App2 (present at ADD2 in Flash), after making the decision in Custom-Bootloader ?

    Please note that I have gone through the boot-loader doc, but somehow could-not-find/missed this particular part (how to start executing App2, present at ADD2 in Flash, after making the decision in Custom-Bootloader).

    Thanks and Regards,
    Ajay
  • Hello Ajay,

    Now the custom boot loader knows which App was updated last. This can be stored as a marker in the flash's last sector or in an EEPROM word, so that on boot up, the custom boot loader checks the predefined location to find out which App to be executed.

    Regards
    Amit
  • Exactly ...
    And how to "start executing" the App-selected-by-Custom-Bootloader?
  • I believe that the Custom-Bootloader, App1 and App2 will always have a fixed starting-address in Flash, if we keep the linker-definitions same ALWAYS? Please correct me if I am wrong.

    Not sure if I understand you correctly.

    But App1 and App2 exist simultaneously in code space (Flash). App1, the "bootloader", is located at the "default" location (usually start of Flash space), and automatically executed after power-up/reset.

    App2, in order to be updatable by the "bootloader", of course needs to be located in another Flash sector than App1, or else the bootloader would commit "suicide" during update. Conveniently choose the start address of a Flash sector. And in order to be called by App1, the start address of App2 must be fixed and implicitly known by App1.

    The actual implementation heavily depends on the individual controller (Flash layout, sections) and (since startup code and linker files are involved) the toolchain.

    Be aware that a lot of MCUs, albeit having separate Flash sections, employ only one programming (i.e. "flashing") hardware on silicon. This means, you cannot execute ANY code from Flash while erasing/writing another section. You need to relocate the actual flashing code to RAM then, making such an tandem application even more complicated ...

  • And how to "start executing" the App-selected-by-Custom-Bootloader?

    By just declaring a function pointer, assigning your "fixed App2 address" to it, and call that function.

  • Hello Ajay,

    Load the first location (SP) to the VECTTABLE and make a branch call to second location (PC) of the app selected.

    Regards
    Amit
  • Thanks f.m.

    Here my concern comes.

    By "calling' that function (from within the Custom-Bootloader), will all the SRAM-context of Custom-Bootloader be lost; and a clean, virgin SRAM-context of App-selected-by-Custom-Bootloader come into place?

    If yes, then I think I have all the pieces in place to start getting my hands dirty on this exercise.
  • Hello Ajay,

    On the zero-initialized section of SRAM in the application will be cleared by the application code. So you may still see some parts of the custom boot loader.

    Regards
    Amit
  • Thanks Amit.

    So, I guess that is fine, because all global variables are zero-initialized, and all local-variables are automatically de-allocated once outside the local-scope?
  • That depends on your startup code (usually an assembler file), where those initialisations are hosted. By default the actual sizes of the RAM segment is passed to the startup code, and everything used is initialized. The stack is usually set to the start of the reserved stack section, but nothing erased.
    The startup code is part of the project, so you can override/change it according to your needs. If your bootloader is always executed first, the RAM is always "polluted" with it's data when entering App2.
  • Thanks f.m.

    That sums it pretty well.
    Now, I can begin with the real stuff, and probably bother you guys as and when I get stuck "while doing rather than theorizing :P".

    Once again, thanks to everyone for your help and patience.

    Thanks and Regards,
    Ajay
  • Do remember "KISS!" Small, measureable steps, replace "assumptions" w/"test/verifies" - your "ride" will be shorter & sweeter...