How to return definition argument - c

I have this definition
#define LED_CLOCK_PIN (DDRD, PORTD, PD6)
I want to write two more definitions, in order to get PORTD and PD6 values, something like this
#define GET_PORT(_PORT_) /*some magic goes here*/
#define GET_PIN(_PIN_) /*some magic goes here*/
uint8_t port = GET_PORT(LED_CLOCK_PIN);
uint8_t pin = GET_PIN(LED_CLOCK_PIN);
Is it possible?

Do you mean something like:
#define LED_CLOCK_PIN (DDRD, PORTD, PD6)
#define SND(A, B, C) B
#define GET_PORT(X) SND X
uint8_t port = GET_PORT(LED_CLOCK_PIN);
gcc -E processes it to uint8_t port = PORTD;. I'm not sure if this is fully portable and guaranteed by standard.

If you were permitted to change you first define to:
#define LED_CLOCK_PIN DDRD, PORTD, PD6
then with C99 you can do (not tested):
#define GET_PORT(x) (((int[]){x})[1])

Is there a reason you would want to parameterize the port instead of accessing it directly by name? That is, instead of
#define GET_PORT
Would it make more sense to have something like
#define GET_PORT_D (port.D)
#define LED_CLOCK_PIN 0x10 //Bit 5 of the port.D register, for example
#define GET_LED_CLOCK_PIN ( (port.D & LED_CLOCK_PIN) >> 4)
This way, there is no ambiguity to what you're doing with the port, so it improves readability. Second, the likelihood that you are changing what LED_CLOCK_PIN actually means (since it accesses hardware) is probably pretty low, so again why not make the code unambiguous.

Related

How to define a macro of two tokens in Cpp

In my Arduinoc (cpp) code, I have these macros that set/clear bit y of register x:
#define SET(x,y) x |= (1 << y)
#define CLEAR(x,y) x &= ~(1<< y)
In several places I then use:
CLEAR(PORTB,7)
or
SET(PORTB,7)
I would like to define a macro to be PORTB,7 so it only appear once, in a header file, not all over my code. (I show only one example, but I have several conbinations of PORTx,N in my code).
I tried:
#define CLOCK PORTB,7
#define CLOCK_HIGH SET(CLOCK)
but it then fails to build with:
error: macro "SET" requires 2 arguments, but only 1 given CLOCK_HIGH; delay(DELAY); CLOCK_LOW; delay(DELAY);
Is there a way to achieve that?
You must first expand the macro inside. Ie. do another pass. Your code may look like this:
#define SET(x,y) do{ (x) |= (1u << (y)); }while(0)
#define CLEAR(x,y) do{ (x) &= ~(1u << (y)); }while(0)
#define HIGH(a) SET(a) // another empty pass, just forward
// the `a` is expanded and the second `SET` takes two arguments
// or better, but not fully compliant:
// #define HIGH(...) SET(__VA_ARGS__)
#define CLOCK PORTB, 7
#define CLOCK_HIGH() HIGH(CLOCK)
int main() {
int PORTB;
CLOCK_HIGH();
}
As a good measure research about macro pitfalls and research good practices when writing macros..

Why does avr-gcc tell me about missing argument while expanding my [fancy] macro?

I'm developing code for Atmel, which defines consistent register names to program port pins. For instance:
PORTC is traditionally used to set (high or low) any pin on port C
PINC is used to read the state of a particular pin on port C
DDRC is used to read/write the direction (0=input, 1=output) of any pin on port C
So I found some code — which I fully understand — that defines a PIN macro like this:
#define LED_PIN C,7
Then the following macros (restricted to the use case I'm talking about here):
#define _BV(bit) (1 << bit)
...
#define _SET(type, name, bit) type ## name |= _BV(bit)
#define _CLEAR(type, name, bit) type ## name &= ~ _BV(bit)
#define _TEST(type, name, bit) ( type ## name & _BV(bit) )
...
#define OUTPUT(pin) _SET(DDR, pin)
#define INPUT(pin) _CLEAR(DDR, pin)
...
#define HIGH(pin) _SET(PORT, pin)
#define LOW(pin) _CLEAR(PORT, pin)
So I can write a function main() as follows:
main() {
OUTPUT(LED_PIN);
HIGH(LED_PIN);
}
While it is very convenient and prevents from defining three macros (e.g. PINC7, PORTC7 and DDRC7) for just one LED, my main concern about this is that is imposes to also redefine AVR macros to account for that kind of notation, bearing in mind AVR macros use SFR registers as arguments (from sfr_defs.h):
#define bit_is_set(sfr, bit) (_SFR_BYTE(sfr) & _BV(bit))
Also, AVR defines macros to convert from [what I'd call] bare registry names to actual memory-mapped special-function register names (sfr) for avr-gcc:
#define _SFR_BYTE(sfr) _MMIO_BYTE(_SFR_ADDR(sfr))
and _SFR_ADDR() adds an offset 0 or 20 according to the target Atmel CPU. So in order to enhance compatibility with those AVR library functions, which take an SFR register plus an optional argument, I decided to rewrite the initial code and tried the following:
#define _SFR_BIT(type, name, bit) type ## name, bit
#define _PORT(pin) _SFR_BIT(PORT, pin)
#define _PIN(pin) _SFR_BIT(PIN, pin)
#define _DDR(pin) _SFR_BIT(DDR, pin)
#define set_bit(sfr, bit) _SFR_BYTE(sfr) |= _BV(bit)
#define set_output(pin) set_bit(_PIN(pin))
but then I face a compiler error message as soon as I write something like this in function main():
set_output(LED_PIN);
main.cpp:72:19: error: macro "set_bit" requires 2 arguments, but only 1 given
I get the same error if I try this, too:
#define set_output(pin) set_bit(_SFR_BIT(DDR, pin))
Why is that macro OUTPUT(), which passes only two out of of three arguments to _SET() compiles fine and my macro doesn't?
As Jens Gustedt pointed to, the generic explanation lies in the order of which the compiler resolves macros.
To transform an arbitrary number of arguments to be passed to a function with a fixed number of arguments using a macro, the function name can be made an argument to the macro:
#define EXPAND(f, ...) f(__VA_ARGS__)
#define _SFR_BIT(type, name, bit) type ## name, bit
...
#define set_bit(sfr, bit) _SFR_BYTE(sfr) |= _BV(bit)
...
#define set_output(pin) EXPAND(set_bit, _SFR_BIT(PIN, pin))
How many and which arguments are passed to the function (first argument) is resolved without any "argument missing" compiler error.
A refined version:
#define _SFR_X(f, type, name, bit) f(type ## name, bit)
...
#define set_bit(sfr, bit) _SFR_BYTE(sfr) |= _BV(bit)
...
#define set_output(pin) _SFR_X(set_bit, PIN, pin)
DISCLAIMER
The code is not yet in production. The code may be ugly, of course. It's mostly some base work under construction. Hence not yet finalized.
The decomposition of the arguments for set_bit into several takes place before the _SFR_BIT macro is expandend. So when it then sees the comma that resulted from the expansion of the latter, it is already too late.
A common trick is to expand the argument once more
#define set_bit0(...) set_bit(__VA_ARGS__)
#define set_output(pin) set_bit0(_PIN(pin))
Here _PIN(pin) is expanded and passt to set_bit0. When passing the arguments from set_bit0 to set_bit it sees the already expandend sequence, including the comma.

Can a preprocessor function be used to define multiple preprocessor macros?

Is it possible to create a preprocessor function that will cause multiple other preoprocessor macros to be defined?
I'm working in a micro controller framework that requires a few macros to be made in order for a generic interrupt handler to function:
<MODULE_NAME>_IRQ_PIN //ex: PORTB_PIN(0)
<MODULE_NAME>_IRQ_IN_REGISTER //ex: GPIO_PBIN
<MODULE_NAME>_IRQ_NUMBER //ex: GPIO_IRQA
<MODULE_NAME>_IRQ_INTCFG_REG //ex: GPIO_INTCFGA
I am trying to make this process more generic and easier from an implementation standpoint. There are about ten of these macros that need to be defined, but their definitions can all be derived when given 1) the port name 2) the pin number and 3) the IRQ name. I am hoping then to create a pre-processor function that will result in the generation of all of these macros. Something like:
#define MAKE_INTERRUPT_MACROS(module, port, pin, irq_num) \
#define module##_IRQ_pin PORT##port##_PIN(##pin##) \
#define module##_IRQ_IN_REGISTER GPIO_P##port##IN \
#define module##_IRQ_NUMBER GPIO_IRQ##irq_num \
#define module##_IRQ_INTCFG_REG GPIO_INTCFG##irq_num
Is there a legal way to get the proprocessor to do something like the above, where a single preprocessor function causes the generation of multiple other macros based on the parameters passed to the function?
I think this classical scheme may solve your problem. This is a simple and clear way:
#ifdef CPU_X
#define IRQ_PIN 0
#define IRQ_IN_REGISTER 3
#define IRQ_NUMBER 11
#define IRQ_INTCFG_REG 12
#endif
#ifdef CPU_YY
#define IRQ_PIN PORTB_PIN(1)
#define IRQ_IN_REGISTER GPIO_PBIN(6)
#define IRQ_NUMBER GPIO_IRQA(9)
#define IRQ_INTCFG_REG GPIO_INTCFGA(0xA)
#endif
#ifdef CPU_KK
/* .
. Another CPU
.
*/
#endif
#ifdef CPU_K2
/* .
. Another CPU
.
*/
#endif
You may compile the code specifying the CPU using -D CPU_xx and the problem shoudl be solved!
I assume you might have some other macros (E.G.: GPIO_IRQA(9)), and in CPU_YY I've used it, but It might be used also for the other CPUs.
If you can use C++ rather than C, look at using classes, one per CPU type, and simply use constants and interfaces in the class. Then, you don't even care that they are different, simply use the same names to access them (the differentiation is done based upon the class being instantiated.
If you really and truly must use C (such as writing a device driver), you can use the approach device driver writers use (all flavors of *nix, VxWorks, PSOS, QNX, and most of the old DEC OSs use this approach, don't know about Windows): Simply build a structure containing the values and any functions you may need to manipulate the hardware (or anything else, for that matter). Create one instance of this structure per hardware (or in your case, module) type. Then indirect through the structure.
Example:
struct module_wrapper {
const char *module_name;
int irq_pin;
int irq_register;
int irq_number;
int irq_intcfg_reg;
int (*init_fcn)(void);
int (*reg_access)(int register_number);
int (*open)(void);
int (*close)(void);
int (*read)(char *dst_buffer, int len);
int (*write)(const char *src_buffer, int len);
};
module_wrapper portB = { /* initialize here */ };
module_wrapper gpio = { /* initialize here */ };
printf("GPIO pin %d\n", gpio.irq_pin);
Obviously, modify as desired. You can also replace the constant variables with functions that return the values.
You can't define other macros with a macro, but you achieve something similar by doing it kind of in a totally opposite way.
You could autogenerate a file which has the following block for each possible module:
#ifdef <MODULE>_IRQ_DATA
#define <MODULE>_IRQ_pin CALL(GET_IRQ_PIN, <MODULE>_IRQ_DATA)
#define <MODULE>_IRQ_IN_REGISTER CALL(GET_IRQ_IN_REGISTER, <MODULE>_IRQ_DATA)
#define <MODULE>_IRQ_NUMBER CALL(GET_IRQ_NUMBER, <MODULE>_IRQ_DATA)
#define <MODULE>_IRQ_INTCFG_REG CALL(GET_IRQ_INTCFG_REG, <MODULE>_IRQ_DATA)
#endif
And then have:
#define CALL(MACRO, ...) MACRO(__VA_ARGS__)
#define GET_IRQ_PIN(port, pin, irq_num) PORT##port##_PIN(pin)
#define GET_IRQ_IN_REGISTER(port, pin, irq_num) GPIO_P##port##IN
#define GET_IRQ_NUMBER(port, pin, irq_num) GPIO_IRQ##irq_num
#define GET_IRQ_INTCFG_REG(port, pin, irq_num) GPIO_INTCFG##irq_num
(Depending on how the defines are used, you can possibly get rid of the #ifdef-#endif -pairs, eg. if all of them must/can always be defined)
Then actually defining the needed values could be done with just:
#define <MODULE>_IRQ_DATA B,0,A

C-Macros produces unexpected behavior

I'm trying to make my header file easily changeable with macros. I'm debugging my code and it seems these MACROS are not doing what they are supposed to. Can someone tell me how I achieve the following effect? LED_ID_AMS etc.
#define LED_NUMBER (2)
#define LED_ID_X (0)
#define LED_ID_Y (1)
#define LED_PIN_X (0)
#define LED_PIN_Y (3)
#define LED_PORT_X (PORTE)
#define LED_PORT_Y (PORTG)
#define LED_DD_X (DDRE)
#define LED_DD_Y (DDRG)
#define LED_PORT(LED_ID_X) (LED_PORT_X)
#define LED_PORT(LED_ID_Y) (LED_PORT_Y)
#define LED_PIN(LED_ID_X) (LED_PIN_X)
#define LED_PIN(LED_ID_Y) (LED_PIN_Y)
#define LED_DD(LED_ID_X) (LED_DD_X)
#define LED_DD(LED_ID_Y) (LED_DD_Y)
What am I trying to achieve?
I'm trying to make it so I can loop through the port init like so:
for(i=0;i<LED_NUMBER;i++){
/* set data direction to output*/
LED_DD(i)|=((0x01)<<LED_PIN(i));
/* turn on led */
LED_PORT(i)|=((0x01)<<LED_PIN(i));
}
You will regret using too many macros later. Actually, you're regretting it already, as they don't work and, being macros, they are very difficult to debug.
Just a few points:
your LED_PIN(i) expressions are always expanding to 0
your LED_PORT(i) expressions are always expanding to PORTE whatever that may be
For instance LED_PIN(LED_ID_X) expands to LED_PIN_X. Note, macro parameter LED_ID_X is not used at all. Instead, LED_PIN_X simply expands to 0.
This should scream warnings at you, as e.g. LED_PORT(SOME_ARG) has several definitions. And in LED_PORT(LED_ID_X) the LED_ID_X is just a dummy argument, with absolutely no relation to your constant LED_ID_X.
You can make your code equally readable by using a constant array, perhaps used from macros like you try to do here.
Unless there are a massive number of LED_ID_<foo>, this is at best a minor simplification. Don't do that. If there is a lot of code futzing around with those is mostly the same way, it might make sense to define a macro that iterates some action over each of them, i.e.:
#define FROB_LEDS \\
action(LED_ID_X); \\
action(LED_ID_Y); \\
action(LED_ID_Z);
and define action(X) locally as a macro to do the action on LED X, FROB them, and undefine action again. Quite ugly, true.
You'll have to add at least one of:
arrays
inline functions
more complicated macros
And it also seems to me that dereferencing of hardware addresses will be required.
For example, using macros, you can define:
#define LED_PORT(i) *(uint16_t *)( \
(i) == LED_ID_X ? LED_PORT_X : \
(i) == LED_ID_Y ? LED_PORT_Y : \
etc)
where:
#define LED_ID_X (0)
#define LED_ID_Y (1)
#define LED_PORT_X (PORTE)
#define LED_PORT_Y (PORTG)
#define PORTE (0x11112222U) // example only
#define PORTG (0x33334444U) // example only
Here uint16_t is only a guess: I'm assuming 16-bit ports in a 32-bit address space.
Or, using arrays and C99's designated initializers:
const uint32_t LED_PORT[] = {
[LED_ID_X] = LED_PORT_X,
[LED_ID_Y] = LED_PORT_Y
};
#define LED_PORT(i) (*(uint16_t *)LED_PORT[i])
And of course, without C99 you can use just:
const uint32_t LED_PORT[] = {LED_PORT_X, LED_PORT_Y};
which assumes that LED_ID_X is 0, etc.

Advanced Preprocesor Tokenization in C

I'm having problem building C macro for my PIC. It's the same for other C-based system's, so non-PIC C experts are also more than welcome.
Lets assume that I have defined my LED_1 pin :
#define LED_1 A1 //A1 as output for LED_1
So if I want to light a LED I would write:
PORTAbits.RA1 = 1;
And if I would like to do it using my LED_1 definition I have to add two more macros:
#define change_PORT_(var) PORTAbits.R##var
#define change_PORT(var) change_PORT_(var
And to use it:
change_PORT(LED_1) = 1;
And it works like a charm. But the problem is that in definitions above I have
PORT A bits.##var
So what if I want to change PORTB values? I would have to build separate macros for PORTs A and B. But it's not even close to be a robust solution.
And I came up with an idea which, I don't know why, doesnt work.
#define LED_1 A1
#define LED_2 B1
#define __A1 A //This would be defined for all PORTA's pins such as A2,A3,A4 etc
#define __B1 B
#define ___change_PORT(var,var2) PORT##var2 bits.R##var
#define __change_PORT(var,var2) ___change_PORT(var,var2)
#define _change_PORT(var) __change_PORT(var,__##var) // creating e.g. __A1
#define change_PORT(var) _change_PORT(var)
And when I try to run this:
change_PORT(LED_1);
The compiler changes __##var to ___A1 but it never changes __A1 to A so this MACRO doesn't work as it supposed to.
I spent a lot of time trying to fix it so I'd appreciate any help :)
EDIT::
I might have found a solution to my problem:
(LAT is just another register name, but it works same as PORT, so this name-change is irrelevant)
#define ___PORTchange(var,var2) PORT##var2##bits.R##var
#define __PORTchange(var,var2) ___PORTchange(var,var2)
#define CHANGE_TO_PORT_NAME(var) ___##var
#define _PORTchange(var) __PORTchange(var,CHANGE_TO_PORT_NAME(var))
#define PORTchange(var) _PORTchange(var)
but I get a compiler error:
100: PORTAbits.RA0 = 1;
^ (374) missing basic type; int assumed (warning)
^ (983) storage class redeclared
^ (984) type redeclared
^ (239) identifier "PORTAbits" redefined (from line 3900)
^ (314) ";" expected
So no it does substitute it correctly but I get a compiler warning telling me that I redefine PORTAbits which I cannot understand. I just wanted preprocessor to change PORTchange(var) to PORTxbits.Rvar where x is A or B. But instead it seems that I'm redeclaring something.
I don't get it.
If I preprocess (tried with several gcc versions and sun cc)
#define LED_1 A1
#define LED_2 B1
#define __A1 AX
#define __B1 BX
#define ___change_PORT(var,var2) PORT##var2##bits.R##var
#define __change_PORT(var,var2) ___change_PORT(var,var2)
#define _change_PORT(var) __change_PORT(var,__##var)
#define change_PORT(var) _change_PORT(var)
change_PORT(LED_1);
change_PORT(LED_2);
I get
PORTAXbits.RA1;
PORTBXbits.RB1;
which is apparently what you are wanting. A bug in your compiler?

Resources