Search code examples
cavr-gcc

how to include several lines of C code in one line of source code (AVR-GCC)


Is there a way to add an identifier that the compiler would replace with multiple lines of code?

I read up on macros and inline functions but am getting no where.

I need to write an Interrupt Service Routine and not call any functions for speed. Trouble is I have several cases where I need to use a function so currently I just repeat all several lines in many places.

for example:

void ISR()
{
  int a = 1;
  int b = 2;
  int c = 3;

// do some stuff here ...

  int a = 1;
  int b = 2;
  int c = 3;

// do more stuff here ...


  int a = 1;
  int b = 2;
  int c = 3;
}

The function is many pages and I need the code to be more readable.


Solution

  • You are correct - it is recommended that you not place function calls in an ISR. It's not that you cannot do it, but it can be a memory burden depending on the type of call. The primary reason is for timing. ISRs should be quick in and out. You shouldn't be doing a lot of extended work inside them.

    That said, here's how you can actually use inline functions.

    // In main.c
    #include static_defs.h
    //...
    void ISR() {
        inline_func();
        // ...
        inline_func();
    }
    
    // In static_defs.h
    static inline void inline_func(void) __attribute__((always_inline));
    
    // ... Further down in file
    
    static inline void inline_func(void) {
        // do stuff
    }
    

    The compiler will basically just paste the "do stuff" code into the ISR multiple times, but as I said before, if it's a complex function, it's probably not a good idea to do it multiple times in a single ISR, inlined or not. It might be better to set a flag of some sort and do it in your main loop so that other interrupts can do their job, too. Then, you can use a normal function to save program memory space. That depends on what you are really doing and when/why it needs done.

    If you are actually setting variables and returning values, that's fine too, although, setting multiple variables would be done by passing/returning a structure or using a pointer to a structure that describes all of the relevant variables.


    If you'd prefer to use macros (I wouldn't, because function-like macros should be avoided), here's an example of that:

    #define RESET_VARS() do { \
         a = 1; \
         b = 2; \
         c = 3; \
      while (0)
    
    //...
    
    void ISR() {
       uint8_t a=1, b=2, c=3;
       RESET_VARS();
       // ...
       RESET_VARS();
    }
    

    Also, you said it was a hypothetical, but it's recommended to use the bit-width typedefs found in <stdint.h> (automatically included when you include <io.h> such as uint8_t rather than int. On an 8-bit MCU with AVR-GCC, an int is a 16-bit signed variable, which will require (at least) 2 clock cycles for every operation that would have taken one with an 8-bit variable.