0

I have some microcontroller code that uses some header files where GPIO pins are defined like this:

#define PA3 GPIO(GPIO_PORTA, 3)

Using the IDE, I can navigate to the implementation of GPIO and I find this:

#define GPIO(port, pin) ((((port)&0x7u) << 5) + ((pin)&0x1Fu))

Where pin is defined as:

const uint8_t pin

and port is an enum defined as:

enum gpio_port { GPIO_PORTA, GPIO_PORTB, GPIO_PORTC, GPIO_PORTD, GPIO_PORTE }

I would like to create an array of all the GPIO defins (PA3, PA4, etc.) that can be indexed by an integer passed over a serial port.

I tried the following:

GPIO knavePinList[] = {PA3, PA4, PA21, PB4, PHY_RESET_PIN, PD0, PD1, PD2, PD3, PD4, PD5, PD6, PD7, PD8, PD9};

But this obviously doesn't work as GPIO is not a recognized C-type, but in fact a macro. While trying to build, I receive this error message:

unknown type name 'GPIO'

Is it even possible for me to declare an array of macros? If so, how would I note the type for what I'm working with?

Thanks.

detroitwilly
  • 811
  • 3
  • 16
  • 30

3 Answers3

2

#define statements perform text replacement, they have no inherent type. As you noted, GPIO is not a valid type, it's a macro that appears to calculate pin numbers/addresses (actually GPIO is undefined, while GPIO(a,b) is the macro).

If you want to store an array of many of these, then you need to know what actual type they all evaluate to. Given that the GPIO macro returns a sum of a port and a pin value, where port is an enum, whose underlying type is int (technically, it's an implementation specific integral type - see What is the underlying type of a c++ enum?) and pin is a uint8_t, the actual type of your array values would also be an integer type - which one specifically depends on your implementation and the range of possible values.

rdowell
  • 729
  • 4
  • 15
  • Thanks for the response, my new solution is to create two arrays - one of type `enum gpio_port` and one of type `uint8_t` - and then call the `GPIO(a,b)` macro myself in the code. I've edited the question to reflect what I'm really trying to do - that is, create an array of macros, rather than an array of `#define` directives. – detroitwilly Jul 11 '18 at 16:43
1

No, you cannot create an array of macros like that.

If you want to execute a particular macro based on an input, you will need to use an if-else or switch statement. If the input is an integer, you could do something like:

switch( input )
{
  case 0: PA3; break;
  case 1: PA4; break;
  case 2: PA21; break;
  ...
 }
John Bode
  • 119,563
  • 19
  • 122
  • 198
  • sorry but that example is useless... as `PA3` (for example) expands to `GPIO(GPIO_PORTA, 3)` which instead expands to `((((GPIO_PORTA)&0x7u) << 5) + ((3)&0x1Fu))` which is a constant expression of type `int` (evaluating to the constant `3` in this case), so your `switch` will ignore the result of the case statements, giving finally nothing at all. The array as shown in the question is perfectly legal, as each macro expands to a constant expression, that can be used as initializer. The OP has not tested his example, and that's the reason he is asking here. – Luis Colorado Jul 12 '18 at 16:54
1

The array you post is perfectly legal, I think you have not tested it. Anyway, it is best to ask with a testable example, (see How to create a Minimal, Complete, and Verifiable example) but the code:

GPIO knavePinList[] = {PA3, PA4, PA21, PB4, PHY_RESET_PIN, PD0, PD1, PD2, PD3, PD4, PD5, PD6, PD7, PD8, PD9};

will produce a perfectly legally initialized array of integers, with the bitwise values of the constants you have expanded from the macros. Try to use

cpp source.c | more

to see how the array declaration is actually expanded. By the way, you have another, different problem in your code... you are using the same identifier, GPIO, to indicate the GPIO macro name, and the type of the array elements, so when the macro processor encounters it, it sees no parameters, which is not how you have #defined it, and complaints about a two parameter macro GPIO called with no parameters at all.

You have to test your code... and send 1. what you expect... and 2. what you get instead... because the error should be evident, if you had simply stopped to read it.

A solution to your problem is to rename the macro GPIO to GPIO_BITS for example... and then change all the definitions:

#define GPIO_BITS(port, pin) ((((port)&0x7u) << 5) + ((pin)&0x1Fu))

...

#define PA3 GPIO_BITS(GPIO_PORTA, 3)

so when you encounter the array definition, the type name is not tried to expand as a macro.

Luis Colorado
  • 10,974
  • 1
  • 16
  • 31
  • I had, in fact, tested my code. The error I received from my compiler was `unknown type name 'GPIO'`. I will admit that I should have posted the error message in the question, but the gist of it was expressed in "But this obviously doesn't work as `GPIO` is not a recognized C-type, but in fact a macro". Which is why I asked the question "How would I note the type of for what I'm working with?". – detroitwilly Jul 12 '18 at 20:42
  • I tried compiling with `int knavePinList[15] = {PA3, ... };`, which works. Thank you for pointing out how the macros resolve! – detroitwilly Jul 12 '18 at 21:13
  • Well, try declaring it as `int`, as probably that was the intention. With the snippet of code you have post, it's difficult to say. – Luis Colorado Jul 13 '18 at 07:32