arduino/Arduino — pull request #1285 by projectgus (2013-02-19 14:34:50+00:00)
Title: Digitalio performance

Last week I put together an [alternative to the digitalWriteFast library](https://github.com/projectgus/digitalIOPerformance/) for digitalRead/Write optimisations, and it got me thinking about the digitalRead/Write implementations in Arduino and opportunities for optimisation.

I read [Issue 140](http://code.google.com/p/arduino/issues/detail?id=140) on the Google project and see that it was unmerged because "the complication of providing two separate versions of the pin mapping seem like a bigger burden than the potential benefit"

This version doesn't require two copies of each pin mapping. The pin mapping macros are changed, but there's no duplication. In fact there's only 130 additional lines of code.

pinMode, digitalRead & digitalWrite will all automatically inline whenever the pin number is known at compile time.

## Statistics

### Before

In the current Arduino library I measured a digitalWrite() at approx 107 clock ticks (6.74us @ 16Mhz.) The digitalWrite function takes up 8 bytes in flash for each time it is called, plus 108 bytes for the implementation.

### After

With this change, many pins can digitalWrite() a constant value in 2 clock ticks (125ns.) The single sbi instruction takes up 2 bytes in flash.

If the pin supports PWM, the operation takes 7 clock ticks (437ns) due to setting the timer register to turn off possible PWM. Each digitalWrite() takes up 8 bytes in flash.

For some pins on the Mega, that require a read/modify/write cycle (ie no sbi support), the operation takes 17 clock ticks (~1us) and takes up 26 bytes of flash, in part due to the need to disable interrupts.

For instances where the pin is not known at compile time, the digitalWrite() function takes approx 112 clock ticks (~7us.) The digitalWrite function takes up 8 bytes in flash for each time it is called, plus 100 bytes for the implementation (ie nearly identical to the current implementation in these cases.)

## Advantages

* Transparently improves performance where possible, obsoletes libraries like digitalWriteFast.

* No duplication of pin mapping data.

* Optimised cases take up less flash space, except possibly when using some pins on the Mega (flash is more plentifully available on the Mega, though!)

* Uses inline functions almost exclusively over macros, so better type safety and error messages. :)

## Disadvantages

* Doesn't inline library functions where the pin numbers are set in the constructor and the implementation is compiled in a separate file (as per [comment #12 on Issue 140](http://code.google.com/p/arduino/issues/detail?id=140#c12).) I have some ideas about possible techniques to deal with this, but I haven't tried them out yet.

* Will break any third party board profiles that ship their own pins_arduino.h. I don't know how common this is. It would be possible to make this technique backwards compatible to older pins_arduino.h files without too much extra complexity, but I thought this might be feature-itis unless anyone feels otherwise.

Has been tested with gcc 4.7 (Linux) and gcc 4.3.2 (Windows.)

What do you think? Please let me know if there's anything else these changes need or could use. :)