How to map pins to parallel port registers (for library code)

Hello.

I have a couple of questions about Arduino pin-to-port mapping, and preprocessor capabilities.

Background:

I am developing a hardware-related library and would like to allow the user (sketch-writer) to specify from 2 to 5 (or maybe 2 to 6) consecutive pin numbers for the hardware connection (by specifying the minimum pin number, and the maximum pin number), but they must be in the same parallel I/O port register (for the speed afforded by parallel port manipulations instead of “bit-at-a-time” manipulations, and also because reading inputs from the device must be atomic, which means that the “bit-at-a-time” reads may not work if changes occur while reading.)

For example, say the user/sketch-writer specifies the following:

#define HWDEVICE_MIN_PIN 8
#define HWDEVICE_MAX_PIN 10

(where HWDEVICE is the name of the hardware library - which, BTW, is NOT “HWDevice” ;).

This would mean that the user/sketch-writer would connect a 3-pin device to pins 8, 9 and 10.

I want to check. at compile-time, that the consecutive pin numbers defined by the user/sketch-writer are in the same port register (to be able to use the PORTx, DDRx and PINx registers), and issue a preprocessor #error directive if the consecutive pin numbers are not all in the same parallel I/O port.

(It would be nice to be able to specify the minimum-pin and maximum-pin as parameters in the class library’s constructor, but I strongly believe that would prevent the ability to check, at compile-time, that the consecutive pins defined would be in the same port register.)

Question 1:

Is/are there any built-in Arduino macro(s) that map an Arduino pin number to its corresponding parallel port registers, and bit position (or bit mask) within that port register (depending, of course, on the Arduino board declared for the sketch build)? If such macros are available, where might I find documentation describing them?

I am looking for something like (inside my library’s header file):

#define HWDEVICE_PORT  PIN_TO_PORTREG_MAP(HWDEVICE_MIN_PIN)
#define HWDEVICE_DDR   PIN_TO_DDRREG_MAP(HWDEVICE_MIN_PIN)
#define HWDEVICE_PIN   PIN_TO_PINREG_MAP(HWDEVICE_MIN_PIN)

QUESTION 2:

Does the preprocessor provide for any means of forward referencing of macro definitions? For example, suppose the sketch has the following, for the UNO board:

#include <HwDeviceLib.h>

#define HWDEVICE_MIN_PIN 6
#define HWDEVICE_MAX_PIN 9

Is there any possible way for the HwDevice.h header to issue a compile-time error directive (because pins 6 and 7 are in different port registers than pins 8 and 9, for the UNO)?

If not, then the library will require the user to place the “constant” macros before the #include directive:

#define HWDEVICE_MIN_PIN 6
#define HWDEVICE_NUM_PIN 4

#include <HwDeviceLib.h>

which may “look funny” to a beginner sketch-writer.

So, in any case, the error checking would (I hope) look something like:

#if (HWDEVICE_PORT != PIN_TO_PORTREG_MAP(HWDEVICE_MAX_PIN))
    #error "The device pins must all be in the same AVR parallel I/O port register."
#endif

So is any of the above possible?

Thanks and best regards,
Ed.

The macro you're looking for is digitalPinToPort(pinNumber).

II don't know about the error checking code. It might be easier to have the user pass those pin numbers into the library somehow (is it a class where we can use a constructor) and let all the magic happen in the library instead of using #define in the .ino.

Thank you for your reply, Delta_G.

Since I want the error checking to be at compile time (i.e. build time), I do not believe I could pass the pin number limits as parameters to my class constructor, as that would force the error checking to be at run time.

Thank you for pointing out the digitalPinToPort macro. I just looked into it and see that it it invokes a call to pgm_read_byte from the progmem library. I strongly suspect that would be a run-time call and that the result would not be available to the preprocessor at build time. But if the array, digital_pin_to_port_PGM, is publicly available, perhaps I could use that to convert the pin numbers to the PB, PC, PD, etc. entities for use in the #if directive condition at build time (for the build-time error checking). Something to try out.

Also I still do not see how to use digitalPinToPort to read the PINx register at run-time. But there must be a way to do this as, I suspect, that the resident Arduino code must be doing something like that in the digitalRead function. Some more research required on my part, it seems. :)

Thanks again, Ed.

Woops. Come to think of it, I cannot convert pin numbers to PB, PC, etc. at build time. Again, that would involve a program memory read and I am quite sure that the AVR needs to execute run time instructions to read data from program flash. Dang that Harvard Architcture. :(

Hmm, I think to do this you'd have to extend pins_arduino.h with macro logic that encodes the progmem tables.

This may be a case of diminishing returns - if you need to be that close to the hardware, just ifdef on the particular processor(s).