Search code examples
c++cmacrosarduinometaprogramming

C/C++ macro to repeat code


is there any way to repeat a C code N times with a macro? Also N is a macro.
For example if I have this macros:

#define N 5  
#define COODE "nop\n\t"
#define REPEAT [...]

When I call repeat the preprocessor writes CODE N times, so

 __asm__(REPEAT);

would became

__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");

I have an Arduino that have to wait for an exact (and small, about 10-15) number of clock. Each "nop" (no operation) takes exactly 1 clock cycle to be executed, and it does nothing. I can't just do a cycle, because each cycle is executed in more than one operation (initialize the counter, increment the counter, check if reached end), so instead of writing manually "nop\n\t" I'd like to have a macro. This way I can also simply change N to modify the program without rewriting it.

Thank you in advance


Solution

  • If you want to do it without including a whole library or using define, you can use a simple recursive template:

    //By Christopher Andrews, released under MIT licence.
    
    template< unsigned N > struct Nops{
      static void generate() __attribute__((always_inline)){
        __asm__ volatile ("nop");
        Nops< N - 1 >::generate();
      }
    };
    template<> struct Nops<0>{ static inline void generate(){} };
    
    void setup() {
      Nops<10>::generate();
    }
    
    void loop(){}
    

    This will generate the exact number of nop's required.

    0000010a setup:
    10a: 00 00 nop
    10c: 00 00 nop
    10e: 00 00 nop
    110: 00 00 nop
    112: 00 00 nop
    114: 00 00 nop
    116: 00 00 nop
    118: 00 00 nop
    11a: 00 00 nop
    11c: 00 00 nop
    11e: 08 95 ret

    I have used this method in a TFT driver for Arduino.

    EDIT:

    There is another way to easily do this on an AVR compiled with avr-gcc. I'm assuming this may not be available on older toolchains.

    In order to delay execution for a specific number of cycles, GCC implements

    void __builtin_avr_delay_cycles (unsigned long ticks) ticks is the number of ticks to delay execution. Note that this built-in does not take into account the effect of interrupts which might increase delay time. ticks must be a compile time integer constant; delays with a variable number of cycles are not supported

    From here: https://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/AVR-Built_002din-Functions.html