3

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

Michał
  • 691
  • 1
  • 5
  • 22
  • 1
    Through a function pointer initialized from a constant value (address) you get from a map-file your compiler generates, assuming you have contiguous address space and no access restrictions in either way... –  Aug 02 '17 at 11:37
  • 1
    A typical scenario is that the bootloader provides some "library" and exposes a table of function pointers at some fixed address for that purpose, so you don't have to recompile the main code (and changing all function addresses) after every change of the bootloader. The fixed address can be achieved by putting this table in its own segment and using a linker script to correctly place this segment in the resulting binary. –  Aug 02 '17 at 11:43
  • A software interrupt is a common means of accessing functions in boot code. It is not then necessary for the main program to know where the functions are. Commonly, a function number is pushed/whatever in a fixed manner so that the boot code can always retrieve it and switch to the desired function. – Martin James Aug 02 '17 at 12:50
  • @Martin James Common? Any examples except PC BIOS – 0___________ Aug 02 '17 at 12:52
  • @PeterJ umm.. ARM7? Linux Kernel on Intel, (80h)? – Martin James Aug 02 '17 at 13:00
  • ARM7 do not have a bootloader. It a prehistoric family as well. – 0___________ Aug 02 '17 at 13:06
  • OK, I'll admit a software interrupt is not specifically for interfacing with boot code, but it's a common method for communicating between two code units whose locations are not known to each other, eg. boot and main. – Martin James Aug 02 '17 at 13:07
  • @PeterJ ARM9 and Cortex don't have an interrupt controller and/or a software interrupt call? – Martin James Aug 02 '17 at 13:08
  • ARM9 - another prehistoric family. Cortex - see my answer - there is an example bootloader call function. Cortex devices have the interrupt controller but before calling it it has to be disabled. – 0___________ Aug 02 '17 at 13:12
  • @Martin James ARM9 family of uC, as I remember doos not have built in bootloader. One has to programmed by the user. – 0___________ Aug 02 '17 at 13:18
  • Can I ask why you do not want to use thrbuilt in bootloader? – 0___________ Aug 02 '17 at 14:06

3 Answers3

5

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.

  • 1
    I know there is no simple answer. But this solution is what I was thinking about, I just was not sure how exactly should it be implemented. By the way: we used wrong compilation flags casing to link unused functions. Fixing it saved about 25% of used space.. Lesson learned. – Michał Aug 03 '17 at 09:15
1

A software interrupt is a common means of accessing functions in boot code. It is not then necessary for the main program to know where the functions are. Commonly, a function number is pushed/whatever in a fixed manner so that the boot code can always retrieve it and switch to the desired function.

Such a mechanism does not need any specially located interface area that is fixed and know to both boot and main, or any linking between the main and boot code.

The exact mechanism/s are architecture-dependent.

Martin James
  • 24,453
  • 3
  • 36
  • 60
0

Two possible scenarios:

  1. Built in bootloader. In all Cortex cores I know. Here is an example code to invoke the bootloader from the application.

    #define SYSFLASH 0x1FFFD800
    
    void __attribute__((noreturn)) StartBootLoader(void) {
    
        void (*BootLoad)(void) = (void (*)(void))(SYSFLASH + 4);
    
        HAL_RCC_DeInit();  // Only the example foe HAL. PLL has to switched off, peripheral clocks as well 
        HAL_DeInit();      // All interrupts have to be disabled. 
                       // if HAL not used uC should be restored to the power-on state
    
        SysTick -> CTRL = 0;
        SysTick -> LOAD = 0;
        SysTick -> VAL = 0;
    
        __set_PRIMASK(1);
    
        __set_MSP(*(uint32_t *)SYSFLASH);
        BootLoad();
        while(1);
    }
    
  2. Custom bootloader - any scenario possible

0___________
  • 60,014
  • 4
  • 34
  • 74
  • Isn't this just issuing a reboot? The second option seems more to be what the OP wants, and maybe you could elaborate on it with a more concrete example than in my answer, because you seem to know the target platform. –  Aug 02 '17 at 13:44
  • No - it enters the built in bootloader. – 0___________ Aug 02 '17 at 13:46
  • That's what I mean, so it's a warm-start or whatever the bootloader provides, but OP wants to share his function between *his* bootloader and application code. –  Aug 02 '17 at 13:47
  • So he needs to write his own one. Probably I have misunderstood his question – 0___________ Aug 02 '17 at 13:49
  • His question might admittedly already be *too broad* ... but whatever hides behind your "second option" seems to be what he's interested in ;) (that's why I tried to sketch a solution **without** knowing Cortex myself, and I thought you might be able to write a better one) –  Aug 02 '17 at 13:51
  • Writing own bootloader is not an easy task and I afraid if it is possible to cover this topic in the simple answer on the forum. In this case question is I agree too broad. BTW how did you format my code. I was trying but the attribute part was all the time bold – 0___________ Aug 02 '17 at 13:53
  • inside a list, you have to put *another* 4 spaces for each indentation level of the list in front of each code line :) –  Aug 02 '17 at 14:00
  • @Felix Palmen Thanks :) – 0___________ Aug 02 '17 at 15:19