Fast pin switching in Arduino

I’ve been playing around with my Arduino Uno and Arduino Mega for the last few weeks, but I didn’t think I had discovered anything interesting enough to post about. In the last day or so, though, I was interested in finding out just how fast one could switch an Arduino digital pin on and off.

binary comment

The Uno’s ATmega328P processor is driven by a 16Mhz processor, so one might hope to get a 16Mhz signal out of a pin. But you need several processor instructions to create the signal: one to bring the pin HIGH, one to bring the pin LOW, and then one to jump back to the beginning of the loop. Per the data sheet, those each require two clock cycles. So, 6 instructions, meaning ~2.7 Mhz is a more reasonable expectation.

Implementing this code with the digitalWrite C function, what I got in the end was only a measly 150 Khz. Turns out that the digitalWrite function call is incredible slow. But fortunately, with the ATmega328P, you can simple write the HIGH or LOW directly to the IO register, which gets you back down to your 6 instructions. You’ve get to spend some time looking at the Atmel data sheet and the Uno pin diagram (or ask the helpful folks at #arduino IRC channel) to figure out how to do that. This is for digital pin 2:

void setup() { 
  pinMode(2, OUTPUT);
  digitalWrite(2, HIGH);
  delay(2);
  noInterrupts();
}

void loop() {
  start:
  PORTD |= (1<<PD2);
  PORTD &= ~(1<<PD2);
  goto start;
}

Note that I called the noInterrupts procedure. noInterrupts suspends processor interrupts, which normally do various things in the background like keeping your microsecond counter running. They introduce some randomness and delay that I didn’t want here.

The above code produced about 2.7 Mhz on the oscilloscope, as expected.

binary comment

Notice there is some lack of symmetry in the signal, since the pin stays low while doing the loop jump. It occurred to me afterwards that maybe a better way to do this, while saving a few more clock cycles, would be to just bit-toggling that register bit instead, but I haven’t had a chance to explore that idea yet.