I have written several libraries with optimized I/O for software SPI and I2C. Here is what I would like in fast digital read/write for this type of application.
The behavior of digitalRead/digitalWrite should not be modified to provide fast read/write. Fast read/write should be a separate facility.
Fast digital read/write should not clear PWM since this increases the execution time by five cycles on a PWM pin. Fast write will then executes in two cycles (more on some Mega pins) when both arguments are constant. A stopAnalogWrite() function should be added.
Fast digital read/write should fail at compile time if the pin number is not a constant or is too large. This will prevent unexpected behavior at execute time.
Here is an example include file for the 168/328 that shows how this can be implemented with static inline functions and a static const array. The array is always eliminated by compiler optimization.
It is easy to extend this idea to the Mega and other Arduino-like boards.
#ifndef DigitalFast_h
#define DigitalFast_h
#include <avr/io.h>
struct pin_map_t {
volatile uint8_t* ddr;
volatile uint8_t* pin;
volatile uint8_t* port;
uint8_t bit;
};
static const pin_map_t pinMap[] = {
{&DDRD, &PIND, &PORTD, 0}, // D0 0
{&DDRD, &PIND, &PORTD, 1}, // D1 1
{&DDRD, &PIND, &PORTD, 2}, // D2 2
{&DDRD, &PIND, &PORTD, 3}, // D3 3
{&DDRD, &PIND, &PORTD, 4}, // D4 4
{&DDRD, &PIND, &PORTD, 5}, // D5 5
{&DDRD, &PIND, &PORTD, 6}, // D6 6
{&DDRD, &PIND, &PORTD, 7}, // D7 7
{&DDRB, &PINB, &PORTB, 0}, // B0 8
{&DDRB, &PINB, &PORTB, 1}, // B1 9
{&DDRB, &PINB, &PORTB, 2}, // B2 10
{&DDRB, &PINB, &PORTB, 3}, // B3 11
{&DDRB, &PINB, &PORTB, 4}, // B4 12
{&DDRB, &PINB, &PORTB, 5}, // B5 13
{&DDRC, &PINC, &PORTC, 0}, // C0 14
{&DDRC, &PINC, &PORTC, 1}, // C1 15
{&DDRC, &PINC, &PORTC, 2}, // C2 16
{&DDRC, &PINC, &PORTC, 3}, // C3 17
{&DDRC, &PINC, &PORTC, 4}, // C4 18
{&DDRC, &PINC, &PORTC, 5} // C5 19
};
static const uint8_t pinCount = sizeof(pinMap)/sizeof(pin_map_t);
static inline uint8_t badPinNumber(void)
__attribute__((error("Pin number is too large or not a constant")));
static inline __attribute__((always_inline))
uint8_t digitalReadFast(uint8_t pin) {
if (__builtin_constant_p(pin) && pin < pinCount) {
return (*pinMap[pin].pin >> pinMap[pin].bit) & 1;
} else {
return badPinNumber();
}
}
static inline __attribute__((always_inline))
void digitalWriteFast(uint8_t pin, uint8_t value) {
if (__builtin_constant_p(pin) && pin < pinCount) {
if (value) {
*pinMap[pin].port |= 1 << pinMap[pin].bit;
} else {
*pinMap[pin].port &= ~(1 << pinMap[pin].bit);
}
} else {
badPinNumber();
}
}
#endif // DigitalFast_h