Question

I'm writing firmware in C for an embedded processor. I want to have all the configuration information in one header file called config.h. This is causing problems with the ADC initialization, where simple #defines won't do the trick. Right now the code is like so:

config.h

#define NUMBER_OF_POTS  1
#define POT_1_CHANNEL  27

adc.c

#define MAKE_CSS(channel) _CSS##channel
#define CALL_MAKE_CSS(channel) MAKE_CSS(channel)

void initialize_adc() {
   CALL_MAKE_CSS(POT_1_CHANNEL);
}

What I want to do is not have to touch adc.c if I change config.h to:

#define NUMBER_OF_POTS  2
#define POT_1_CHANNEL  27
#define POT_2_CHANNEL  29

adc.c should just automatically add a second CALL_MAKE_CSS with some macro trickery.

I guess the question is: is there a trick that gives you for loop capability with a macro?

Thanks,

Steve.

Was it helpful?

Solution

I didn't test this:

// config.h

#define NUMBER_OF_POTS  2
extern int pots[];

// config.c

int pots[NUMBER_OF_POTS] = {
    27,
    29
};


// adc.c

void initialize_adc() {
    for (int i = 0; i < NUMBER_OF_POTS; i++) {
        CALL_MAKE_CSS(pots[i]);
    }
}

OTHER TIPS

You don't have to rely entirely on macros. Just define your 'magic numbers' as #defines.

For example:

In config.h:

#define NUMBER_OF_POTS 2
#define POT_1_CHANNEL  27
#define POT_2_CHANNEL  29

unsigned int PotChannelList[NUMBER_OF_POTS] = {POT_1_CHANNEL, POT_2_CHANNEL};

In adc.c:

for(i = 0; i < NUMBER_OF_CHANNELS; i++)
{
  initialize_adc(PotChannelList[i]);
}

You still define the setup in config.h and don't have to change adc.c when you add a channel. You just add it to the list. The list order also defines the order of initialization.

EDIT: Sorry about the formatting mess...

Have a look at boost.preprocessor. Although boost is usually for C++, the preprocessor metaprogramming lib works, well, just with the CPP, so it may do what you want. It provides a few datastructures (lists, tuples) and iteration macros.

Sorry, I can't give you any example if it really does what you want, or at least provides another way, because I seldom needed it, and it's too long ago.

Note Just saw Schroeder's answer. Not relying on the PP if it is not necessary is still the best option...

The C preprocessor cannot do loops. You'll either have to do the looping in C code, or if you really need to do something loop-like at compile time, you can write your own preprocessor (which can just be a simple shell script, e.g.) that generates the necessary code.

Although you can't do loops with the preprocessor, you can do unrolled loops. So if you know you're never going to have more than 4 pots you could do this;

void initialize_adc() {
  #if NUMBER_OF_POTS > 0
    CALL_MAKE_CSS(POT_1_CHANNEL);
  #endif
  #if NUMBER_OF_POTS > 1
    CALL_MAKE_CSS(POT_2_CHANNEL);
  #endif
  #if NUMBER_OF_POTS > 2
    CALL_MAKE_CSS(POT_3_CHANNEL);
  #endif
  #if NUMBER_OF_POTS > 3
    CALL_MAKE_CSS(POT_4_CHANNEL);
  #endif
}

The only benefit of this compared to other solutions here is that there is no runtime overhead at all. Extra inline code "magically" appears if and only if another channel is added, just as the questioner wanted. To extract the ugliness from within the function call (at the cost of putting it earlier in your code instead), define 4 new macros each using the same #if NUMBER_OF_POTS > x technique. Then you'd be able to go simply;

void initialize_adc() {
  INIT_CSS_1();
  INIT_CSS_2();
  INIT_CSS_3();
  INIT_CSS_4();
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top