Search code examples
microcontrolleravratmelsam

How does one call a function from it's memory address in AVR C?


I am writing a function:

void callFunctionAt(uint32_t address){
  //There is a void at address, how do I run it?
}

This is in Atmel Studio's C++. If previous questions are to be believed, the simple answer is to write the line "address();". This cannot be correct. Without changing the header of this function, how would one call the function located at the address given?

The answer should be system-agnostic for all micro controllers which support standard c++ compilation.


Solution

  • The common way to do this is to give the argument the correct type. Then you can call it right away:

    void callFunctionAt(void (*address)()) {
      address();
    }
    

    However, since you wrote "Without changing the header of this function [...]", you need to cast the unsigned integer to a function pointer:

    void callFunctionAt(uint32_t address) {
      void (*f)() = reinterpret_cast<void (*f)()>(address);
      f();
    }
    

    But this is not safe and not portabel because it assumes that the uint32_t can be casted into a function pointer. And this needs not to be true: "[...] system-agnostic for all micro controllers [...]". Function pointers can have other widths than 32 bits. Pointers in general might consist of more than the pure address, for example include a selector for memory spaces, depending on the system's architecture.


    If you got the address from a linker script, you might have declared it like this:

    extern const uint32_t ext_func;
    

    And like to use it so:

    callFunctionAt(ext_func);
    

    But you can change the declaration into:

    extern void ext_func();
    

    And call it directly or indirectly:

    ext_func();
    
    callFunctionAt(&ext_func);
    

    The definition in the linker can stay as it is, because the linker knows nothing about types.