0

Microcontroller has many pins, every defined like

const Leg PA29 { PIOA, BIT(29) };   // struct Pin is already taken
// ... about 120 more: 4 port x 32 pin

I wrote a simple define to make alias in shorter form

#define P(Port,PinN)  \
    const Leg P##Port##PinN { PIO##Port, BIT(PinN) }

Using it as

P(D,2);  //produces PD2 with { PIOD, BIT(2) }

Nice.
Now I need-wont call P 120+ times for 4 ports with 32 pins in each. I would like to see something like

FOR_EACH( X in A,B,C,D ) \
  FOR_EACH( i in 0..31 ) \
    P(X,i);

Please do not suggest TCL, python etc. to generate C++ code.
I found an answer, but it is to complicated to understand how to use it in my case.

The main idea is to avoid 120 rows with copy-paste. All 120+ pins should be defined in about 10 lines.

upd. How BIT is defined:

///@param n is value from 0 to number of bits in unsigned value
template<typename UnsignedIntegerT=unsigned>
constexpr UnsignedIntegerT BIT(UnsignedIntegerT n){ return 1<<n; }

upd2. Minimal example

///////////////////
// Vendor provides something like:
///////////////////

struct Pio
{
    unsigned reg1;
    unsigned reg2;
    unsigned reg3;
    //...
    unsigned regN;
};


// values not from datasheet but from lantern
#define PIOA  ((Pio*)0xAABB6789)
#define PIOB  ((Pio*)0xAABB2569)
#define PIOC  ((Pio*)0xAABB2566)
#define PIOD  ((Pio*)0xAABB2323)
//...



/////////////
// Kyb's code
/////////////

class Leg 
{
public:
    Pio *pio;
    unsigned pinN;
//methods...
};


///@param n is value from 0 to number of bits in unsigned value
template<typename UnsignedIntegerT=unsigned>
constexpr UnsignedIntegerT BIT(UnsignedIntegerT n){ return 1u<<n; }


//////////////
// Now need to define 120+ pins-legs

// like this
const Leg PA29 { PIOA, BIT(29) };

// or with shortener alias

/// Alias to shortly produce leg definition
/// Example: `P(A,2)` will define `PA2` with proper PIO and bit.
#define P(Port,PinN)  \
        const Leg P##Port##PinN { PIO##Port, BIT<unsigned>(PinN) }

//P(D,4);  //produces PD4
//P(C,3);
kyb
  • 7,233
  • 5
  • 52
  • 105

3 Answers3

5

You didn't post a truly minimal example. So this is a guess at best. But if you are using C++14, and your types are constexpr constructible, then it seems to me you should do away with the preprocessor as much as possible, and just use variable templates:

enum port {A, B, C, D};

template<port>
struct PIO_ID;
template<> struct PIO_ID<A>{ static constexpr auto value = PIOA; };
template<> struct PIO_ID<B>{ static constexpr auto value = PIOB; };
template<> struct PIO_ID<C>{ static constexpr auto value = PIOC; };
template<> struct PIO_ID<D>{ static constexpr auto value = PIOD; };

template<port P>
constexpr auto PIO = PIO_ID<P>::value;

template<port PORT, int PIN_NUM>
constexpr Leg P{ PIO<PORT> , BIT(PIN_NUM) };

And that's it. Now you can refer to those constants as P<A, 0>, and so forth.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • That's *much* nicer than my answer. (I'll leave my answer up, because it is different, and might be a solution for someone else with a similar problem). – Martin Bonner supports Monica Oct 24 '17 at 11:49
  • Thank you for the answer. I have updated Q with minimal example. – kyb Oct 24 '17 at 12:08
  • My worst problem when I tied to use `constexpr` with vendor's definitions was **reinterpret_cast from integer to pointer**. May be I will define own`PIOx` – kyb Oct 24 '17 at 12:27
  • C++ denies to initialize constexpr pointer from integer value. So there is no way. – kyb Oct 24 '17 at 12:50
2

Do you really need const Leg PA29 (and presumably refer to PA29 elsewhere)?

If you were prepared to write PA[29] and PA was of a type that had a suitable operator [], then you would just have PA, PB, PC, and PD to define (and I probably wouldn't even use a preprocessor define for that).

Alternatively, the Boost Preprocessor library offers loops.

0

Solution with Boost preprocessor library:

#include "Pio.hpp"  // Has Leg and BIT definitions
#include "boost/preprocessor.hpp"  //#include "boost/preprocessor/iteration"


/// Alias to shortly produce leg definition
/// The P(A,2) will define PA2 with proper PIO and bit.
#define P(Port,PinN)  \
        const Leg P##Port##PinN { PIO##Port, BIT<unsigned>(PinN) }


#define PA(n)  P(A,n)
#define PB(n)  P(B,n)
#define PC(n)  P(C,n)
#define PD(n)  P(D,n)


#define BOOST_PP_LOCAL_MACRO(n)   PA(n);
#define BOOST_PP_LOCAL_LIMITS     (0, 31)
#include BOOST_PP_LOCAL_ITERATE()  //??=include BOOST_PP_LOCAL_ITERATE()  //-Wtrigraphs

#define BOOST_PP_LOCAL_MACRO(n)   PB(n);
#define BOOST_PP_LOCAL_LIMITS     (0, 31)
#include BOOST_PP_LOCAL_ITERATE()

#define BOOST_PP_LOCAL_MACRO(n)   PC(n);
#define BOOST_PP_LOCAL_LIMITS     (0, 31)
#include BOOST_PP_LOCAL_ITERATE()

#define BOOST_PP_LOCAL_MACRO(n)   PD(n);
#define BOOST_PP_LOCAL_LIMITS     (0, 31)
#include BOOST_PP_LOCAL_ITERATE()

This works nice. But with on little inconvenience: IDEs will underline PA5 and others as unresolved symbol.

kyb
  • 7,233
  • 5
  • 52
  • 105