Array in #define - c

I am trying to achieve something like this:
#define MACRO(x) {PORTB=0,PORTC=0,PORTD=0}
MACRO(0); //This would get replaced by PORTB=0;
MACRO(1); //PORTC=0;
MACRO(2); //PORTD=0;
I want to create a "macro array". I would pass in an index to it and it would return the right code.
Is this possible?
EDIT:
If it helps, PORTB, PORTC and PORTD are all #defines.

It can be done using the preprocessor, but it is arguably ugly.
#define MACRO_CASE0 PORTB = 0
#define MACRO_CASE1 PORTC = 0
#define MACRO_CASE2 PORTD = 0
#define MACRO(X) MACRO_CASE##X
Also have a look at the Boost.Preprocessor library. (It works for both C and C++.)
Update: After the discussion with Jonathan Leffler (see below) I feel an obligation to update the answer with an exhortation for new C programmers not to abuse the (powerful but dirty) technique shown above.
If you – as the OP requested – want to pass in an index to it and it would return the right code, then you'll need to resort to preprocessor programming. However, if all you want to do is execute different code based on some condition and want this to have no run-time overhead if the condition is a compile-time constant, then the following approach is not only much cleaner but also more flexible as it allows passing run-time values too.
/* '#include' this definition in any file where you want to use it. */
static inline void
do_the_right_thing(const int selector)
{
switch (selector)
{
case 0:
PORTB = 0;
break;
case 1:
PORTC = 0;
break;
case 2:
PORTD = 0;
break;
default:
assert(!"cannot do the right thing: invalid selector");
}
}
Now, in your code, if you write
do_the_right_thing(1); /* selector is a compile-time constant */
a decent compiler with appropriate optimizations enabled will generate no overhead compared to using a macro. However, you can also write
do_the_right_thing(rand() % 3); /* selector is a run-time expression */
and the compiler will insert some fast switching code to select the appropriate operation at run-time.

This would do the task, but it doesn't extend or generalize very gracefully:
#define MACRO(x) (((x) == 0) ? PORTB=0 : ((x) == 1) ? PORTC=0 : PORTD=0)

Related

C macro using two macros

I want to make a macro to utilize two macros
#define BUZZER_ON func_buzz(1);\
flag_buzzer_on = 1;\
#define BUZZER_OFF func_buzz(0);\
flag_buzzer_on = 0;\
#define BUZZER_TOGGLE ((flag_buzzer_on == 1) ? BUZZER_OFF : BUZZER_ON ) ;
where func_buzz is function to turn buzzer on or off depending on value passed
BUZZER ON and BUZZER OFF MACRO is working correctly
but when i use MACRO BUZZER_TOGGLE i get error
expression expected : or ) before ;
How to write MACRO BUZZER_TOGGLE
remember that in your case you can think of macro expansion simplified as text replacement although that's not quite correct as #Eric Postpischil has correcty stated in his comment.
In your case the line
BUZZER_TOGGLE;
is expanded to
((flag_buzzer_on == 1) ? func_buzz(0); flag_buzzer_on = 0; : func_buzz(1); flag_buzzer_on = 1;) ;;
(assuming the second #define BUZZER_ON in the question is a typo for BUZZER_OFF).
You can see that this is no valid statement.
You could make it valid if you defined
#define BUZZER_ON (func_buzz(1), flag_buzzer_on = 1)
and BUZZER_OFF accordingly
but maybe it's easier just to use simple functions instead of macros.

C macro parameter test at design time

I need a macro variable check at design time (preprocesor), more specific that number to fit in 24 bits.
The macro is intended to be used in a if() statement so I have no idea how to test it.
This is a ARM systick timer (24 bits) and so many time I forgot to #define the right value, especially when change the MCU clock and of course, my if() never fired and this silly mistake was hard to debug.
So in this example, there is a trick to force gcc to ERROR when PARAMETER > 24 bits ?
#define PARAMETER 20000000 // over 24 bits, should throw a error at design time
#define MyMacro(var, par) (var > par)
uint32_t variable;
if(MyMacro(variable,PARAMETER))
{
// do something
// do something WRONG because PARAMETER > 24 bits
// Actually this is working as expected, test for < is valid because
// _Static_assert() is check for TRUE condition
// But I am still trying to find a way to combine this in original macro
_Static_assert(PARAMETER < 0xFFFFFF, "Ooopss... ERROR");
}
Thanks in advance!
Unfortunately, _Static_assert is syntactically defined as a declaration, which means you can't use it directly inside of an expression.
However, _Static_assert isn't needed anyway, because you can perfectly (sans the nice compile time error reporting--but you're a programmer, you should be able to figure out a compile time failure a slightly more technical compile-time error message) emulate it with
#define static_assert_0expr(Truth) ((int)(0*sizeof(struct { int _ : (Truth)?1:-1; })))
(or an equivalent) and that you can fit in an expression (even an integer constant expression) no problem:
#define static_assert_0expr(Truth) ((int)(0*sizeof(struct { int _ : (Truth)?1:-1; })))
#define PARAMETER 20000000 // over 24 bits, should throw a error at design time
#define MyMacro(var, par) (static_assert_0expr((par)<0xffffff) + ((var) > (par)))
//or this, but this is won't preserve integer-constant expressions because of the comma:
/*#define MyMacro(var, par) (static_assert_0expr((par)<0xffffff), ((var) > (par)))*/
//alternatively: (static_assert_0expr(assertion) ? (expr) : (expr)) is the most
//general form (though it leads to larger preprocessor expansions, which may worsen debugging experience with cc -E)
#include <stdint.h>
int main()
{
static_assert_0expr(1)+1;
uint32_t variable;
if(MyMacro(variable,PARAMETER))
{
}
}
The above static_assert_0expr macro could also be implemented with _Static_assert:
#define static_assert_0expr(Truth) \
((int)(0*sizeof(struct { int _; _Static_assert(Truth,""); })))
or you could paste the body of this directly in MyMacro and customize the message (but I consider _Static_assert and its custom compile-time error message feature an unnecessary addition to C and prefer not to use it).
Well, I don't want to reply my own answer, but I think I found a solution that is working (thanks #PSkoicik) and thanks to GCC that allows statement expressions (found in this reply)
Using and returning output in C macro
So basically I could use _Static_assert() inside if() statement, with a helper macro
#define CheckParameter(val) ({bool retval = true; _Static_assert((val)< 0xFFFFFF, "Timer value too large!"); retval;})
Now my macro become
#define MyMacro(var, par) ((var > par) && CheckParameter(par))
Which should work because CheckParameter() will always return TRUE at RUNTIME but at COMPILE time, _Static_assert() will catch my error parameter.
So now I can use
if(MyMacro(variable,PARAMETER))
{
// PAREMETER will be in range
}
Hope I'm not missing something :)
If you need to check that PARAMETER is > 24 bits during compile time you can simply do this:
#define PARAMETER 20000 // over 24 bits, should throw a error at design time
...
#if PARAMETER > (1<<24)
#error PARAMETER > 24 bits
#endif
What you do here is not compile time checking but run time checking:
if(MyMacro(variable,PARAMETER))
{
// do something
// do something WRONG because PARAMETER > 24 bits
}
but what is variable doing here anyway if you just want to know if PARAMETER is > 24 bits?

Creating iterable list of register in embedded C

I have been programming with python java and c++, which all have list objects predefined. I'm now working on a microcontroller in C embedded, but objects such as lists and functions such as printf simply don't exist.
What I am trying to do is the following. I have multiple registers which I attach to defines. I want to put all my defines in a list I can access.
#include <stdlib.h>
#include <stdio.h>
#include <xc.h>
#define KP_ROW1 LATBbits.LATB0
#define KP_ROW2 LATBbits.LATB1
#define KP_ROW3 LATBbits.LATB2
#define KP_ROW4 LATBbits.LATB3
#define KP_COL1 LATBbits.LATB4
#define KP_COL2 LATBbits.LATB5
#define KP_COL3 LATBbits.LATB6
#define KP_COL4 LATBbits.LATB7
KP_ROW = [KP_ROW1, KP_ROW2, KP_ROW3, KP_ROW4]; //error on this line
KP_COL = [KP_COL1, KP_COL2, KP_COL3, KP_COL4]; //error
for(int i=0;i<4;i++)
{
if (KP_COL[i] == 1){return 1;}
}
Since I have no previous experience in C embedded, I assumed that google could help me, but it seems that all the solutions I find need the good understanding of struct and the fabrication of really complex functions.
The reasons for this is that I will have maybe 100 pins and I don,t want to make "if" statements for each, I want to iterate throughout a list. I'm using a PIC18F with the XC8 compiler.
I'm asking for advice. How would you do it? Is there a faster, simpler way than making your own list class?
It's quite hard to understand what is desired here. I understand that you wish to read the values of 100 register in your program. You have to know their addresses. Then, you can create a series of macros:
#define REG1 0xabcd
#define REG2 0x1234
...
or whichever addresses. Then, create more macros to access the values directly:
#define REG1_VAL (*(volatile uint8_t *) REG1)
#define REG2_VAL (*(volatile uint8_t *) REG2)
...
Then you can write assignments such as REG1_VAL = 1 or tests such as REG1_VAL == 1. Otherwise, you can create macros that access their values through their addresses:
#define READ(reg) (*(volatile uint8_t *) reg)
Usage of the above to obtain a register value is then:
READ(REG1);
You could then allocate an array of 100 elements:
volatile uint8_t regs[100] = {REG1, REG2, ..., REG100};
and iterate through that array:
for (i = 0; i < 100; i ++) {
if (READ(regs[i]) == 1) {
...
}
}
Hope this helps you!
Note: These macros would need fine tuning to avoid subtle errors, but I hope they are still useful to illustrate what I mean.
I found the answer!
It was not working because I was trying to get the adress of the bit instead of the register.... my bad. It should rather be:
#define KP_ROW LATB
And then add some bitmasks to write the pins I want.
Sorry for this beginner's error!

How to separate #defined arguments in C

I'm working on an embedded project and I have all the ports and pins defined like this:
#define SENSOR_1 gpioPortA,15
Is there a way to extract just the integer without creating a new #define?
So far I used a typedef and assigned the pin value from the #define like so:
typedef struct
{
GPIO_Port_TypeDef port;
uint8_t pin;
}sensor_t;
sensor_t sensor1 = {SENSOR_1};
/* Now sensor1.pin is the pin value */
but I want to pass the pin to a switch case and I can only use constant values for that and I'd rather avoid using an if statement.
Is there a way to pass the pin to a switch case without a new #define?
Short answer is no.
You could however use sensor1.pin when needed but not in case of switch statement as switch does not support variables there. In this case use if-else statement.
Or do it like this:
#define SENSOR_1_PIN 10
#define SENSOR_1 my_port,SENSOR_1_PIN
and then in switch you use SENSOR_1_PIN in case part.
switch (condition) {
case SENSOR_1_PIN:
//Do stuff
break;
//....
}
Just to remind again as it was posted in first comment on your question. Doing that is very dangerous.
Most proper way would be to do it like this:
#define SENSOR_1_PORT GPIOB
#define SENSOR_1_PIN 15
//If structure order changes here, you may lead to wrong data interpretation
sensor_t sensor1 = {SENSOR_1_PORT, SENSOR_1_PIN};
If you are C99 compliant, you may do it even more safer like this:
//If structure order changes here, your data are still properly assigned to fields
sensor_t sensor1 = {.port = SENSOR_1_PORT, .pin = SENSOR_1_PIN};
You can define a macro to extract the value from your definition.
#define GET_SECOND(x, y) y
#define PIN_VALUE(x) GET_SECOND(x)
switch (pin) {
case PIN_VALUE(SENSOR_1):
/* ... */
break;
}
PIN_VALUE must allow SENSOR_1 to be expanded via helper macro so that the second part can be extracted.
The proper solution at this point is to re-design the definitions into something that makes more sense, or alternatively create new constants.
As a last resort, if you are stuck with these macros, you can parse them in the following way:
#include <stdio.h>
#include <stdint.h>
typedef int GPIO_Port_TypeDef; // whatever type this happens to be
typedef struct
{
GPIO_Port_TypeDef port;
uint8_t pin;
}sensor_t;
#define GET_FIELD(field,...) (sensor_t){__VA_ARGS__}.field
#define SENSOR_1 gpioPortA,15
int main (void)
{
int gpioPortA = 1;
printf("%d %d", GET_FIELD(port, SENSOR_1), GET_FIELD(pin, SENSOR_1));
}
The type-generic version would be:
#define GET_FIELD(type, field, ...) (type){__VA_ARGS__}.field
...
printf("%d %d", GET_FIELD(sensor_t, port, SENSOR_1), GET_FIELD(sensor_t, pin, SENSOR_1));
This scales variably no matter how many fields there are. This is however not recommended practice. Macros in general, and variadic macros in particular, should be avoided.
As for how to use run-time variables in case - you can't. Use an if-else if statement instead.
What about inserting a define inside a define ? Instead of directly adding 15, you could make a define holding 15 and insert it elsewhere.
E.g:
#define SENSORVAL 15
#define SENSOR_1 gpioPortA,SENSORVAL
typedef struct
{
GPIO_Port_TypeDef port;
uint8_t pin;
}sensor_t;
sensor_t sensor1 = {SENSOR_1};
/* Now sensor1.pin is the pin value */

C macros: Conditional code based on parameter value?

Is there a cleaner/simpler way to do this?
The below works OK, but I think it's ugly - I'd like a solution that doesn't need a separate #define for every possible invalid value passed as "port".
#define _port_A_config_digital(mask) // do nothing; this port is always digital
#define _port_B_config_digital(mask) AD1PCFGSET = (mask)
#define _port_C_config_digital(mask)
#define _port_D_config_digital(mask)
#define _port_E_config_digital(mask)
#define _port_F_config_digital(mask)
#define _port_G_config_digital(mask)
#define _port_H_config_digital(mask)
#define _port_I_config_digital(mask)
#define _port_J_config_digital(mask)
#define _port_K_config_digital(mask)
#define ConfigDigitalBits(port, mask) _port_##port##_config_digital(mask)
If "port" is anything other than B, I want a null statement.
I'd like to get rid of all the #defines other than the one that does something.
I want to do this because on this MCU all ports other than B are always digital and there's nothing to be done.
But calling ConfigDigitalBits() ought to be a valid thing to do for any port.
You could do something like
#define CONFIG_DIGITAL_BITS(PORT, MASK) \
do { if (PORT == 'B') AD1PCFGSET = (MASK); } while (0)
and trust (or check by reading the assembly) your compiler to evaluate the if condition at compile-time. That is,
CONFIG_DIGITAL_BITS('B', 0x42);
would generate code for only
AD1PCFGSET = 0x42;
and
CONFIG_DIGITAL_BITS('A', 0x42);
would generate no code at all.
The proposed code above has the problem that it ignores errors. For example,
CONFIG_DIGITAL_BITS('Z', 0x42);
would happily compile although there is no port Z. You could assert on this but this will only catch the error at run-time.
Once you got to this, consider getting rid of the macro at whole and use an inline function instead that will also permit constant propagation.
inline void
config_digital_bits(const char port, const unsigned mask)
{
assert(port >= 'A' && port <= 'K');
if (port == 'B')
AD1PCFGSET = mask;
}

Resources