Arduino macros to get port register names from Arduino pin number at build time?

Hello.

I hope I am asking my questions here in the correct forum. Please let me know if this needs to be somewhere else.

I am developing a device driver library where a contiguous number of pins for the device is defined by the sketch author, by specifying the minimum and maximum Arduino pin numbers to which the device is connected.

I would like to check AT BUILD TIME (or pre-processor time) that the sketch author is adhering to a number of rules about the minimum and maximum Arduino pin numbers, and fail the build (with a #error pre-processor directive) if not. (For example, the minimum has to be less than the maximum, and the total number of pins must be between 2 and 6, inclusive).

Therefore, my library header file ("MyDeviceLib.h" for example) requires the sketch author to #define two constants before #including it. Something like:

#define MYDEVICE_MIN_PIN  2
#define MYDEVICE_MAX_PIN  5

#include "MyDeviceLib.h"

Then, in the MyDeviceLib.h header file, pre-processor directives (conditionals, etc.) will test to ensure that the minimum and maximum Arduino pin numbers do not break the rules for the library. I have most of these checks working (the build will fail if these two parameters break some of my rules; for example if MIN is greater than or equal to MAX).

For now, at least, I want to limit this library for use with 8-bit ATmega and ATtiny processors - not for SAM (ARM) processors, ESP8266 processors, etc. (I only have UNO, Nano, Digispark, and "bare naked" ATtiny85 chips to test with. I DO have a couple of ESP-01's to play with, but I have not written sketches for those yet and, anyway, only a couple of port pins are available on the '01. I have some ESP-12's on order.)

Question 1: How do I check to ensure the sketch is being built for 8-bit ATmega/ATtiny devices? How would I change this if I eventually want to include other processors?

(Although, I am not sure I could get other processors to work with my device driver - I may have to do a total re-write for bigger processors like ARM based, etc.)

One of the rules is that the maximum and minimum Arduino pin numbers (and of course, all pins in between) must be on the same processor I/O port register. (Because the library functions will be performing manipulations on parallel data bits that are read from or written to the external device.)

Question 2: How do I check (at build time) to ensure that the specified (#define'd) minimum and maximum Arduino pin numbers are in the same processor port register? Does the Arduino IDE define some macros to easily get (at build time) the AVR port register name, for any given Arduino pin number?

As a very "rough-and-dirty" method for question number 2, I am masking off the three LS bits of the Arduino pin numbers (clearing those 3 bits to 0 in each number), and checking that the results (pin numbers with 3 LSBs set to 0) are the same. For example, if the minimum pin number is less than 8 and the maximum is greater than or equal to 8, then I spit out a pre-processor #warning directive:

//TODO: Somehow check to ensure that MYDEVICE_MIN_PIN and MYDEVICE_MAX_PIN are in the same
//      I/O port.  Issue an error message, if not.
//      Following is a VERY ROUGH check which probably does not work with some
//      boards.
#if ((MYDEVICE_MIN_PIN) & ~7) != ((MYDEVICE_MAX_PIN) & ~7)
  #warning Specified minimum and maximum pin numbers appear to be on different ports.
  #warning All MyDevice pins must be on the same port for this library to work correctly.
#endif

This is making an assumption (probably incorrect) that Arduino pin numbers (for ATmega and ATtiny boards) are always in groups of 8, and that each group of 8 is associated with one specific port. (And, yes, I do realise that some Arduino boards have devices where port C only has 5 bits available.) So it would be best for my purposes to try to get the port register letter for a given Arduino pin number, hopefully by using already-defined macros in the Arduino IDE for whatever device the sketch is being built.

So, the following is what I have for now on build-time checking of these Arduino pin parameters:

/*
    MyDeviceLib.h
*/

#ifndef _MYDEVICE_LIB_HEADER_INCLUDED
#define _MYDEVICE_LIB_HEADER_INCLUDED


// LAW ENFORCEMENT ;-)


// TODO: Check to ensure the build is for 8-bit ATmega/ATtiny device (How do I do this?)


#if !(defined(MYDEVICE_MIN_PIN) && defined(MYDEVICE_MAX_PIN))
  #error I need something to work with, here.  Please define BOTH of MYDEVICE_MIN_PIN and MYDEVICE_MAX_PIN before includin MyDeviceLib.h
#endif

#if (MYDEVICE_MIN_PIN) < 0
  #error Stop being so negative!  I just cannot handle negative pin numbers!
#endif

#if (MYDEVICE_MIN_PIN) >= (MYDEVICE_MAX_PIN)
  // This also ensures that 2 is the minimum number of pins.
  #error MYDEVICE_MIN_PIN must be STRICTLY less than MYDEVICE_MAX_PIN.
#endif

#if (MYDEVICE_MAX_PIN) > (5 + (MYDEVICE_MIN_PIN))
  #error Hey! I am no Superman! I can only handle up to 6 pins, max.
#endif

//TODO: Somehow check to ensure that MYDEVICE_MIN_PIN and MYDEVICE_MAX_PIN are in the same
//      I/O port.  Issue an error message, if not.
//      FOllowing is a VERY ROUGH check which probably does not work with some
//      boards.
#if ((MYDEVICE_MIN_PIN) & ~7) != ((MYDEVICE_MAX_PIN) & ~7)
  #warning Specified minimum and maximum pin numbers appear to be on different ports.
  #warning All MyDevice pins must be on the same port for this library to work correctly.
#endif

// End of "LAW ENFORCEMENT" ;-)


/*
    ... PUT LIBRARY GLOBAL DEFININTIONS, PROTOTYPES, ETC. HERE
*/

#endif // _MYDEVICE_LIB_HEADER_INCLUDED

Thanks for any help with this.

Best regards,
"DuinoSoar"

See pins_arduino.h hardware/arduino/avr/variants/
/standard/pins_arduino.h for UNO and other ATmega168 and ATmega328P processors.
/eightanaloginputs/pins_arduino.h for the nano and other arduinos with the 32-pin ATmega328P
etc

Thank you, John.

I had a look a the pin_arduino.h files that you mentioned, for the various boards, and it looks like I am WAY off the mark for what I wanted to do.

My goal was to use parallel I/O processing to save on time and space (especially for boards/processors with smaller memory, like Digispark and ATtiny85 chips). But my natural and logical assumption was that contiguous Arduino pin numbers actually meant something sensible for the port names and pin numbers on the processor devices. But, then I had a look at the pin_arduino.h files for boards like the mega and leonardo.

On those boards, not only can the Arduino pin numbers be out of order with respect to the processor port pin bits, but Arduino pin numbers can be on different ports, even in within a range of other pin numbers that are on the same port.

For example, if the sketch author using my device driver defines, say, Arduino pin 2 as the minimum and Arduino pin 5 as maximum (so the device is using 4 pins), I need to read them so that pin 2 is the LS bit and pin 5 is the MS bit. But if I understand correctly the comments in the definition of the digital_pin_to_port_PGM array, Arduino pins 2,3 and 5 are on port E, but Arduino pin 4 is on port G !!!. And, even then, Arduino pin 5's bit position in port E is LESS than the bit positions of Arduino pins 2 and 3!! What a mess!

I guess the designers were more concerned about circuit board traces between the processor chip and the Arduino pin numbering on the header pins, than they were about defining pin numbers to be logically in the same order as bits in the various processor ports.

This is VERY disappointing, because it means that I will have to read and write one bit at a time in software loops, and process collected byte information, instead of reading/writing the ports in parallel.

Another disappointment is that the port/pin mapping is defined as a constant array in memory. I believe this means that the pre-processor cannot determine which port an Arduino pin number is in during pre-processing time (so that the #error directive can stop the build if they are on different ports).

So I guess I will have to get loopy (or, at least, more loopy than I already am. ; ).

Thanks and best regards,
DuinoSoar