Search code examples
cbootloaderdfu

How can I use one function from main application and bootloader? (embedded)


First of all I need to say I develop application for embedded device based on cortex m4.

I have functions that are common for bootloader and main application. For now I compile source files 2 times once for bootloader and app. But I am running short on space for dual bank dfu and I would like to have those functions only once in ROM. Any idea how can I achieve this?

EDIT:

Using functions pointers maybe danger in some cases, check on my problems - Using pointer functions - 2 seperate applications on 1 device


Solution

  • This is only a partial answer and assumes you can jump into your bootloader from your main code using the same address space. Then, a common technique is to provide your "bootloader API" as a table of function pointers.

    Say for example you have the following functions in your bootloader:

    static int do_something(void)
    {
        return 42;
    }
    
    static int do_something_else(int arg)
    {
        return arg+5;
    }
    

    Then you would declare your API in a header like this:

    struct bootloaderApi
    {
        int (*do_something)(void);
        int (*do_something_else)(int arg);
    };
    

    In the implementation of your bootloader, you define this table in its own section:

    // this is GCC syntax, use whatever your compiler provides to specify the section
    struct bootloaderApi api __attribute__((section("API"))) = {
        do_something,
        do_something_else
    };
    

    Then when building the bootloader, make sure your section is placed at a suitable fixed address. When e.g. using the GNU linker, you could have something like this in your linker script:

    SECTIONS {
      // standard sections, e.g.:
      .text : { *(.text) }
      .data : { *(.data) } 
      .bss :  { *(.bss)  *(COMMON) }
    
      // your API table:
      .API 0x10000 : { *(.API) }
    }
    

    This now assumes your API table will be placed at 0x10000. Then you could do the following to access the API from your main code:

    struct bootloaderApi *api = (struct bootloaderApi *)0x10000;
    
    api->do_something();
    

    All of this is just a sketch to give you an idea how to do this in a sensible way. It will heavily depend on your target platform and the toolchain you're using.