Thread: C Preprocessor concatenation

  1. #1
    Registered User
    Join Date
    Aug 2017
    Posts
    4

    Question C Preprocessor concatenation

    Hi,

    I am working on an embedded C project where I'd like to define my ports and their bits as follows:
    #define RF_SPI0_MOSI_BIT 1
    #define RF_SPI0_MOSI_PORT 3

    Now, when I set a pin (Port 3, pin 1) as an output:
    P3DIR |= 1 << 1;

    The first macro I created was :
    #define _PORT_SET_OUTPUT(port, pin) P##port##DIR |= 1 << pin

    _PORT_SET_OUTPUT(1, 3);, which works.

    It would be way easier if I give my macro only the value 'RF_SPI0_MOSI', and let the macro find out the port.

    PORT_SET_OUTPUT(RF_SPI0_MOSI);

    Where the macro will concatenate the RF_SPI0_MOSI value with '_PORT' and '_PIN'.

    I was not able to google any information about this, could anybody tell me if this is possible, and if so, help me out?

  2. #2
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,616
    You can definitely do something like

    #define PORT_SET_OUTPUT_SIMPLE PORT_SET_OUTPUT(RF_SPI0_MOSI_PORT, RF_SPI0_MOSI_BIT)

    and then the statement is generated where "PORT_SET_OUTPUT_SIMPLE;" is used.

    Personally I think this is a step too far and that the function is the simplest thing to understand.
    Last edited by whiteflags; 08-31-2017 at 02:54 AM.

  3. #3
    Registered User
    Join Date
    Aug 2017
    Posts
    4

    reply

    Quote Originally Posted by whiteflags View Post
    You can definitely do something like

    #define PORT_SET_OUTPUT_SIMPLE PORT_SET_OUTPUT(RF_SPI0_MOSI_PORT, RF_SPI0_MOSI_BIT)

    and then the statement is generated where "PORT_SET_OUTPUT_SIMPLE;" is used.

    Personally I think this is a step too far and that the function is the simplest thing to understand.
    Thanks for helping me out here.
    The macro is used for more than just port1 bit3, There are more than 100 pins I have to define, so the method you are describing is not the way I would like to use in my program.


    lets say; ..

    Code:
    #define RF_SPI0_MOSI_BIT                   1
    #define RF_SPI0_MOSI_PORT                3
    #define RF_SPI0_MISO_BIT                   2
    #define RF_SPI0_MISO_PORT                P3
    #define RF_SPI0_SCLK_BIT                   3
    #define RF_SPI0_SCLK_PORT                P3
    #define LED_RED_BIT                           0
    #define LED_RED_PORT                        P4
    
    void initIO(void)
    {
      PORT_SET_OUTPUT(RF_SPI0_MOSI);
      PORT_SET_INPUT(RF_SPI0_MISO);
      PORT_SET_OUTPUT(RF_SPI0_SCLK);
      PORT_SET_OUTPUT(LED_RED);
      PORT_SET_INPUT..
    
      etc.
    }
    We have been using this method on several other processors, but those used another structure of initializing ports. For this reason I can not use the port initialize code used on these processors, but I would like to remain the macros.

    also, the method you are describing will parse an error during preprocessing:
    PORT_SET_OUTPUT(RF_SPI0_MOSI_PORT, RF_SPI0_MOSI_BIT) -> Description Resource Path Location Type
    #20 identifier "PRF_SPI0_MOSI_PORTDIR" is undefined main.c /CC1200_Tester/src line 40 C/C++ Problem


    It currently will only work with numerical values.
    Last edited by daans; 08-31-2017 at 03:27 AM.

  4. #4
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,616
    Well do you have to set each pin individually? That seems really stupid. I can tell you that having 100+ macros for each pin is going to get unruly when you could set a whole bunch of pins at once. Your original attempt was good I would just use a mask instead.

    Code:
    #define USE_PORT(portnum) P##portnum##DIR
    #define PORT_SET_OUTPUT(port, mask) USEPORT(port) |= (mask)
    Label all of the port numbers since they are (hopefully) fewer in number and more important. Then instead of trying to label all of the pins, come up with specific integers that turn on all the pins you need to use at once. For example maybe 0xB (1011) turns on pins 0, 2, and 3. To help you come up with such integers, you ought to read this: BBC Bitesize - GCSE Computer Science - Hexadecimal and character sets - Revision 1 , especially if you are unfamiliar with hex's relationship to binary.
    Last edited by whiteflags; 08-31-2017 at 04:15 AM.

  5. #5
    Registered User
    Join Date
    Aug 2017
    Posts
    4
    Quote Originally Posted by whiteflags View Post
    Well do you have to set each pin individually? That seems really stupid. I can tell you that having 100+ macros for each pin is going to get unruly when you could set a whole bunch of pins at once. Your original attempt was good I would just use a mask instead.

    Code:
    #define USE_PORT(portnum) P##portnum##DIR
    #define PORT_SET_OUTPUT(port, mask) USEPORT(port) |= (mask)
    Label all of the port numbers since they are (hopefully) fewer in number and more important. Then instead of trying to label all of the pins, come up with specific integers that turn on all the pins you need to use at once. For example maybe 0xB (1011) turns on pins 0, 2, and 3. To help you come up with such integers, you ought to read this: BBC Bitesize - GCSE Computer Science - Hexadecimal and character sets - Revision 1 , especially if you are unfamiliar with hex's relationship to binary.
    Yes Each port Will be labeled as port and pin , this label process is executed by a script that generates the labels from a pcb design file. I Will test the method in 60 minutes, keep you up to date

  6. #6
    Registered User
    Join Date
    Aug 2017
    Posts
    4
    Quote Originally Posted by whiteflags View Post
    Well do you have to set each pin individually? That seems really stupid. I can tell you that having 100+ macros for each pin is going to get unruly when you could set a whole bunch of pins at once. Your original attempt was good I would just use a mask instead.

    Code:
    #define USE_PORT(portnum) P##portnum##DIR
    #define PORT_SET_OUTPUT(port, mask) USEPORT(port) |= (mask)
    Label all of the port numbers since they are (hopefully) fewer in number and more important. Then instead of trying to label all of the pins, come up with specific integers that turn on all the pins you need to use at once. For example maybe 0xB (1011) turns on pins 0, 2, and 3. To help you come up with such integers, you ought to read this: BBC Bitesize - GCSE Computer Science - Hexadecimal and character sets - Revision 1 , especially if you are unfamiliar with hex's relationship to binary.
    Labels are generated by a script that's initialized by an output file of the PCB layout.
    So when I would like to change the output of a pin, I would do something like this;

    PORT_SET_OUTPUT(RF_SPI_MISO);//one time, initializing
    PORT_HIGH(RF_SPI_MISO);


    I only have to write the macro's for editing the registers.

  7. #7
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,616
    also, the method you are describing will parse an error during preprocessing:
    PORT_SET_OUTPUT(RF_SPI0_MOSI_PORT, RF_SPI0_MOSI_BIT) -> Description Resource Path Location Type
    #20 identifier "PRF_SPI0_MOSI_PORTDIR" is undefined main.c /CC1200_Tester/src line 40 C/C++ Problem

    It currently will only work with numerical values.
    That was my bad. I did something incorrect, but happily the error led to the solution!

    I need to explain something to you. Ordinarily, macros are not expanded when you use them in stringification # or pasting ##:
    Code:
    #define CAT  dog
    #define FOOD hot_##CAT
    FOOD
    FOOD produces hot_CAT, not hot_dog like we want, but you can get around it. Arguments to a macro must be expanded before they are passed to another macro though, so we should be able to do what you want. One macro to expand, and one to do the pasting.

    Just to show it with the example:
    Code:
    #define CAT     dog
    #define NOEXPAND(A) hot_##A
    #define FOOD(A) NOEXPAND(A)
    FOOD(CAT)
    produces hot_dog as wanted. So we can do what you want with pasting PORT and BIT, it just takes careful control of where things expand and where they shouldn't.

    Code:
    C:\Users\jk>more macros.c
    #define PASTE_BIT(m) m##_BIT
    #define PASTE_PORT(m) m##_PORT
    
    #define USE_PORT(port) P##port##DIR
    #define PORT_SET_OUTPUT(port, pin) USE_PORT(port) |= 1 << (pin)
    
    /* you must define ports and pins at this point */
    #define RF_SPI0_MOSI_PORT 3
    #define RF_SPI0_MISO_PORT 3
    #define RF_SPI0_SCLK_PORT 3
    #define LED_RED_PORT 4
    #define RF_SPI0_MOSI_BIT 1
    #define RF_SPI0_MISO_BIT 2
    #define RF_SPI0_SCLK_BIT 3
    #define LED_RED_BIT 0
    
    PORT_SET_OUTPUT(PASTE_PORT(RF_SPI0_MOSI), PASTE_BIT(RF_SPI0_MOSI))
    PORT_SET_OUTPUT(PASTE_PORT(RF_SPI0_MISO), PASTE_BIT(RF_SPI0_MISO))
    PORT_SET_OUTPUT(PASTE_PORT(RF_SPI0_SCLK), PASTE_BIT(RF_SPI0_SCLK))
    PORT_SET_OUTPUT(PASTE_PORT(LED_RED), PASTE_BIT(LED_RED))
    
    C:\Users\jk>gcc -E macros.c
    # 1 "macros.c"
    # 1 "<built-in>"
    # 1 "<command-line>"
    # 1 "macros.c"
    # 21 "macros.c"
    P3DIR |= 1 << (1)
    P3DIR |= 1 << (2)
    P3DIR |= 1 << (3)
    P4DIR |= 1 << (0)
    So that should be good. Hopefully the explanation is clear so that you can do this yourself. I notice that in some other examples you posted you use macros that I haven't seen before, but the solution for those would be similar to this including possibly functions like USE_PORT(x) so they expand to what you want.
    Last edited by whiteflags; 08-31-2017 at 06:51 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Preprocessor concatenation
    By ardavirus in forum C Programming
    Replies: 2
    Last Post: 07-03-2011, 03:00 PM
  2. concatenation
    By valthyx in forum C Programming
    Replies: 5
    Last Post: 01-17-2010, 08:22 AM
  3. Concatenation ?
    By koolguysj in forum C Programming
    Replies: 8
    Last Post: 04-15-2005, 04:26 PM
  4. concatenation
    By rose2626 in forum C++ Programming
    Replies: 10
    Last Post: 04-25-2003, 01:27 PM
  5. concatenation
    By F*SH in forum C++ Programming
    Replies: 34
    Last Post: 11-13-2002, 06:47 PM

Tags for this Thread