Design Tip: Sharing Code Between Bootloader and Application

If you use a bootloader to update your application, you may want to avoid duplicating code that's used by both programs and thus save yourself some space in Flash - this is certainly possible, but not trivial.

To share code between two (or more) co-resident programs, you have several options but they all boil down to: in some manner the location of each shared function must be made known to all the programs that want to use it.


Option 1: Fixed-location functions

application
padding
shared function 1
...
shared function N
bootloader
interrupt vectors

(Adjust as necessary for "bootloader at top of memory" configuration, or if your chip mandates a different interrupt vector layout)

Each shared function will need to have a chunk of Program Memory address space reserved for its exclusive use. If it ever grows beyond that space, problems can occur. If you have more than one shared function, you must either reserve extra space for each of them to accommodate potential growth, or be prepared to re-link any applications when any of the shared functions changes.

You can tie the functions to specific addresses by using the '#pragma psect' mechanism (more detail about this in the tutorial chapter of your compiler manual) for each function. If you do this, you must be careful that you leave sufficient space for each function. Alternately you could let the compiler allocate addresses for the functions and then extract them from the MAP file afterward.

These fixed addresses then need to be used by your application when it calls these functions - several methods are possible but the simplest uses an assembler file defining the entry points, which is assembled and linked with your application. Remember, if you recompile the bootloader, you will almost certainly have to regenerate this list of fixed addresses and relink your application.


Option 2: Fixed-location jump table

application
padding
shared function 1
...
shared function N
jump table
bootloader
interrupt vectors

You should be familiar with this method already - it's precisely what is used by the hardware on many platforms for the reset and interrupt vectors. For each function you want to share, while the real function sits at some compiler-assigned address, an explicit "JUMP" instruction (whose target is the function in question) is located at a well-known address.

With this approach, while the total amount of reserved space is still a limiting factor, you have a little more freedom to modify individual functions without needing to re-link your applications because there is an extra layer of indirection.

Here you tie the jump table to a specific base address, or obtain its address from the MAP file, and don't worry about the locations of the shared functions at all (other than to ensure they do not exceed the space reserved for them). Your application still needs to link to the jump-table addresses somwhow, and the assembler file of address definitions suggested for Option 1 is still the simplest, although here its contents are not dependent on the actual locations of your functions but merely that of the jump table itself.

Other than Program Memory usage, you must also be careful to ensure that the application and shared functions avoid overlapping one another's statically-allocated RAM usage - any RAM used by the shared functions (or bootloader) needs to be excluded from that used by the compiler to allocate space for the application's data. Possible expansion of the required space as a result of "shared library" growth must also be taken into account.

Like a bootloader, the actual code to implement this "shared library" will be specific to a chip architecture at least (and possibly an individual chip) and will also have an impact on the design of the application that is going to use that library.


 

This technique could also be the beginnings of a co-operative operating system where one of the shared functions is actually the "yield CPU/switch tasks" mechanism, and each of several applications (tasks) could be separately compiled to occupy distinct memory locations.

   

 

June 2005.