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.

Bootloader



I know that the topic of bootloaders has been covered a number of times here before and I have found the information quite useful (thanks especially to Jens-Michael) but I have not satisfactorily found a neat way of getting the tools (CCSv4) to do what is required.

I am comfortable with the concept of the boot loader having a 'protected' flash section containing the default reset and interrupt vectors that executes code to determine if the main application requires updating at reset and jumping to the main application when action is taken (or not taken).  I also understand that the default interrupt vectors need to point to another vector table in the main application's flash space in order to cope with the changing addresses of the interrupt handlers.

So my question is how do I get CCS to accomplish this?

I had initially thought to maintain two separate CCS projects (one for the main application and one for the boot loader) and merge the two project output .txt files to initially use in programming the entire flash and extract the appropriate sections of the main project to use as the update file.  The linker command files for each project would have nicely located everything where it should.  The two downsides that I have found to this are finding a tool to automate combining the two files as a post build command and that the main project can't be debugged separately because the reset and interrupt vectors are not where they should be.  Is there a way around this?

My second thought was to compile the boot loader into an object file and link it into the appropriate section of flash during the main project's linking stage.  This would mean the complete flash image would be generated at the end of the build process of the main project and could be debugged as normal (the bootloader would run first and then jump to the main application).  But this is where my knowledge of the low level tool details start to get a bit scratchy.

- Is it possible to link in the bootloader's object file to it's own section of flash?

- And if so would having all the C run time initialisation code in the bootloader's object file clash with the main project?

- In that case would the bootloader code need to be placed in a different code section and can you do that for the entire bootloader project or would it be easier to code the bootloader in assembly to avoid the run time initialisation and place it in the correct code section?

 

Cheers

Adam

  • Are there any reasons for not writing the bootloader and the main application in the same project?  My preference would probably be just a single project...

  • Correct me if I'm wrong but if you have both the bootloader and the main application in the same project the two will be dependent on each other and not be truly fail-safe.

    The bootloader code needs to be the first thing to run after reset, so for it to be in the same project it would be in the 'main' function.  This could be located in the 'protected' flash area and never erased but then there is a problem with the C run time initialisation.  It would be dependent on the rest of the main application and if it was located in the 'protected' flash area and never erased would be incorrect when the main application code changes.  Alternatively it could be located in the main application's flash area but would be susceptible to not being able to boot the device if there was a failure between erasing the main application and writing the new one.

    You could probably get around this by modifying the C run time initialisation but I see that as being more complicated than fiddling with the tools.

    Cheers

    Adam

  • Adam Koch said:
    - Is it possible to link in the bootloader's object file to it's own section of flash?

    Yes. However, if both projects are based on C and you combine both projects, you'll either end up with two main functions and two startup sequences (which will cause unresolvable linker conflicts) or you have to join the code, which will make the startup code of the bootloader dependant on the main project code, which requires rewriting the bootloader with each main project change.

    The only way to go if you want a single project is to make the bootloader an assembler (sub-)project. Here you'll have no startup code and no need to have a main function.
    You can start with a separate bootloader C project and use the generated assembly code s a starting point.

    Later, you can either include the bootloader as binary data in your project, or you add the assembly code. Either way (and if you adjusted the linker file properly), the bootloader will always be the same and always end up in the correct location. So you can compile it with every project, and either rewrite it if you do a JTAG update, or let it ignore its own part when you're updating using the bootloader.

  • I wrote a custom bootloader a few years ago.  It was combined with the main application in a single project, both written in C without any major complications.  I suppose it depends on compiler and tools but in my mind it was much easier to have a single project than the approach you are proposing...but maybe it's just down to personal preference!  :-)

  • The problem with such a combined project is that project and bootloader share the same variable pool and init code. So if th eproject changes, part of the bootloader (or at least the bootloaders prerequisite) changes, so the bootloader has to be replaced too.
    The key element of the above approach is that the bootloader remains unchanged and static, no matter what happens with the application, so it doe snot need to be erased ever, even for a small moment. This cannot be done in a joined C project.

  • Interesting discussion. Are we talking talking about code between the reset vector and main()? I would arbitrariliy called that boot/init code. That should be one project with two targets, debug and release. Release would contain the extra code that the IDE might be initializing for you in a debug session. No way to recover if the flash programming goes bad.

    To me, a boot loader is something disitnctly separate and can live independent of what it is loading. The bootloader is your last defense to "unbrick" your board. Two projects would make more sense here. The term is "loader" is somewhat of a misnomer here as the MSP430 code tends to runs in place in flash. Other architectures favour execution in RAM aka loaded into RAM.

    Yeah, I know. Just a lot semantics.

     

  • Jens-Michael Gross said:
    The problem with such a combined project is that project and bootloader share the same variable pool and init code. So if th eproject changes, part of the bootloader (or at least the bootloaders prerequisite) changes, so the bootloader has to be replaced too.

    Unfortunately I have moved companies since I wrote my bootloader a few years ago so I don't have access to the code anymore.  I think I wrote the bootloader so that it didn't require variable intialisation etc.  By using some of the IAR advanced pragmas and build settings and throwing in a couple of inline asm("...") commands it all seemed to work ok.  We changed the main application code considerably over the following months and updated units with the bootloader quite happily.

    Perhaps I have misunderstood or missed something critical here - I seem to be the only person who thinks it is possible to do it this way.

  • chris_m said:
    I seem to be the only person who thinks it is possible to do it this way.

    It is posible, yet it isn't easy, as you can do much wrong here. And it is not the most efficient way.
    It is possible under the following conditions:

    1) the BSL needs to be executed before teh C startup code
    2) the BSL needs to init the stack for itself by itself, ains the startup code hasn't run
    3) the BSL main funciton may not use any local variables (as the stack isn't initialized at function start)
    4) the BSL may not rely on any pre-initialized global variables (as the C startup code hasn't initialized them)
    5) the BSL may not use any library code or main applicaiton function, even if this means double implementation of the same code.

    Then it is doable. With every change of the main project, the linker willput the BSLs global variables to anothe rlocation, but since all the non-BSL variables are unused and not initialized when the BSL runs, the BSL may as well use outdated locations. Any location will fit fine. The BSL itself is always at the same location and has control over the interrupt table, so it doesn't need to be updated.

    The drawback is that the variables used by the BSL block space that is not available for the main application, even if all BSL variables are freed then. Including buffers etc. That's what I meant with 'not the most efficient way'.
    If the BSL only uses pointers into the ram area, then things are fine. All the ram is free to use before the C startup code has run. Unless the application has some semi-permanent storage spaces (which are not cleared if a reset happens). But this also applies to a two-project BSL approach.

    Oh, last but not least: beware of compiler optimization. It might make all efforts void.

  • Thanks for the information, I suspected there would be problems with linking two C projects.

    For anyone else who is interested I have used an assembly project for the bootloader.  In the CCS workspace you have two projects, one assembly only project (as specified by the new project template), and an ordinary C project.  To include the bootloader code into the main C project you can modify the linker script to include the path to the object files that are generated from your assembly project.

    You can use the following post as a guide for relocating the interrupt vectors.  You just need to add the section for your bootloader code and make sure that you point the real reset vector to the start of that section.

    The only thing I haven't worked out with CCS is how to stop the bootloader assembly project from linking short of using a custom makefile.

  • Thanks Adam, that is a useful reference.  Why do you also want to prevent linking the bootloader?  In the manage build options you could create an extra configuration (e.g. Debug, Release, and Release-NoB).

     

     

    JMG:

    Jens-Michael Gross said:

    It is possible under the following conditions:

    1) the BSL needs to be executed before teh C startup code
    2) the BSL needs to init the stack for itself by itself, ains the startup code hasn't run
    3) the BSL main funciton may not use any local variables (as the stack isn't initialized at function start)
    4) the BSL may not rely on any pre-initialized global variables (as the C startup code hasn't initialized them)
    5) the BSL may not use any library code or main applicaiton function, even if this means double implementation of the same code.

    I handled setting up the stack using inline asm("...").  I don't remember needing any pre-initialised globals.  I think I may have used a couple of local vars but initialised them when I needed them - after setting up the stack pointer - rather than at declaration.

     

    Jens-Michael Gross said:
    The drawback is that the variables used by the BSL block space that is not available for the main application

    Interesting point.  As you say I suppose it depends on how you structure and implement it.

     

    Thanks for explaining your concerns - if I ever have to write another bootloader I'll probably go for the linked-in assembly project route (depending on specific requirements of course).

     

    Jens-Michael Gross said:
    Oh, last but not least: beware of compiler optimization. It might make all efforts void.

    Of course!  Sadly this applies to all (non-assembly) projects regardless of whether they include a bootloader but that's a topic for another day... :-)

  • chris_m said:
    Thanks Adam, that is a useful reference.  Why do you also want to prevent linking the bootloader?  In the manage build options you could create an extra configuration (e.g. Debug, Release, and Release-NoB).

    I wanted to disable the linker in the assembly project because all I need from that project is to compile the assembly files into object files.  Those objects files are linked in later during the main C project's linker stage.

    It doesn't hurt to run the linker on the assembly project because I am not using the output of the linker but it just throws up some warnings.  I just prefer not having sort through a list of irrelevant warnings to check if something is actually wrong.

**Attention** This is a public forum