translating pins to ports

I’m writing a class as part of a library. To increase speed and timing accuracy I would like to interact with the ports directly, rather than using Arduino functions.

The class constructor takes the ‘Arduino pins’ as arguments, which would then need to be translated to port and pin numbers. Since these functions should already exist within Arduino, would I be able to use those?

Inside pins_arduino.h I found the following, although I’m unfamiliar with the syntax used:

const uint8_t PROGMEM digital_pin_to_port_PGM[] = {
 	PD, /* 0 */
@@ -152,6 +250,10 @@ const uint8_t PROGMEM digital_pin_to_port_PGM[] = {

const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = {
 	_BV(0), /* 0, port D */
@@ -175,6 +277,14 @@ const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = {

Could I use these to get the right port and mask? If yes, how? If not, could you suggest some other way?

this is what I normally use

Macros to translate...

Usage examples...

There are two ways to go about this and you will need to decide which way you want to go.

1) translate all the information at compile time which will generate AVR bit set/clr instructions. This yields the smallest fastest code but it requires that all the information pin # and data value be constant and known at compile time. This means that the sketch cannot define the pins in a constructor and configuration must be done using some other means. For a library it usually means that it must have its own config file for the pin information.

2) translate the information runtime once and then use it directly instead of calling digitalWrite()/digitalRead(). This can be done in a portable manor (will work on AVR, pic32, and ARM), and while not as fast as bit set/clr instructions, it will be much faster than digitalWrite()/digitalRead() particularly on AVR processors. It comes with a caveat that you must mask interrupts when altering the port register to avoid port corruption. To do this you use these functions:

port_addr = portOutputRegister(digitalPinToPort(pin#));
port_mask =  digitalPinToBitMask(pin#);

Then you can twiddle the bits directly:

*port_addr |= port_mask; // set bit
*port_addr &= ~port_mask; // set bit

But remember, interrupts must be masked when you do this to avoid port corruption. To get portability the data type for port_addr and port_mask will be different for different processors. I haven't looked at the ARM registers but for AVR and pic32 you can use this:

#if defined (__AVR__)
typedef uint8_t fio_bit;
typedef volatile uint8_t *fio_register;
#elif defined(__PIC32MX__)
typedef uint32_t fio_bit;
typedef volatile uint32_t *fio_register;

Then define port_addr as a fio_register and port_bit as a fio_bit

If you want to have smarter code for the pic32, (which is not portable to other MPUs) the pic32 parts have bit set/clr registers that could be use that work even better than the AVR bit set/clr instructions since for this mode of operation bit set/clr instructions can't be used and the pic bit set/clr registers can atomically set/clr bits and don't require that interrupts be masked like the AVR.

--- bill

Excellent! Thanks guys.

Have a great Christmas.