Arduino Fast Digital Reads and Writes

2018-09-22 03:47:06 +0000 - Written by Carl Burks

If you have used an Arduino for a project you might not have had a need for speed. If you need to squeeze the power of the Arduino you might have to go a little deeper than the Arduino standard functions digitalRead and digitalWrite will get you.

Consider the following:

void setup()
pinMode(13, OUTPUT);          // sets the digital pin 13 as output

void loop()
digitalWrite(13, HIGH);       // sets the digital pin 13 on
digitalWrite(13, LOW);        // sets the digital pin 13 off

This sets a pin on and then off, it works, but if you hook up a scope and measure the speed it takes a while and if you have to set multiple pins you will take even longer. To fix this you need to understand what is happening under the covers. Finding your Arduino install location then looking for wiring_digital.c will get you started on the source. On mine it was in “hardware\arduino\avr\cores\arduino” and then I was able to find:

void digitalWrite(uint8_t pin, uint8_t val)
    uint8_t timer = digitalPinToTimer(pin);
    uint8_t bit = digitalPinToBitMask(pin);
    uint8_t port = digitalPinToPort(pin);
    volatile uint8_t *out;

    if (port == NOT_A_PIN) return;

    // If the pin that support PWM output, we need to turn it off
    // before doing a digital write.
    if (timer != NOT_ON_TIMER) turnOffPWM(timer);

    out = portOutputRegister(port);

    uint8_t oldSREG = SREG;

    if (val == LOW) {
        *out &= ~bit;
    } else {
        *out |= bit;

    SREG = oldSREG;

That is a lot of code and several function calls. You are sacrificing a fair bit of speed for safety and convenience. “digitalPinToPort” is the magic that picks out the actual board’s register you are manipulating.

If you know which board you are using you can get the datasheet for the chip.

Once you have the datasheet you look at the pin out configurations. Hint the number you want isn’t necessarily the pin Arduino has printed on the headers of your board. It will probably start with “P” then A,B,C,D then a number and look something like “PD2”

These are different for different boards so the digital_wiring.c abstracts that away.

Peeling back the abstraction layers gets you a little closer to the metal.

You can write a byte to the PORTD which will manipulate a bunch of pins or you can control a single pin with bitmasks. Look at the end of the “digitalWrite” to get an idea.

This is all well and good, but what about reading?

Serial.println(PIND, HEX);

Unless you really need these tricks it is probably a better to the standard functions, because they work with the boards without meddling.

On a slightly unrelated note,

I’ve been looking at

which lets you send a TV signal from your Arduino. If I do anything with it I’ll post some pictures.