Introduction: Arduino Is Slow - and How to Fix It!

About: Check out razorconcepts.net for some projects.
Arduino is slow? What? This instructable will show just how slow a part of Arduino is, and how to fix it.
 
It’s true – more specifically, Arduino’s digitalWrite command takes a considerable amount of time. If you are just switching on a LED once or something, you won’t be able to notice it. However, I realized how slow it was while I was trying to use a TLC5947 PWM driver. That requires the microcontroller to shift in 288 bytes each time! Each byte required about 12 digitalWrites, for a total of 3456 digitalWrites each time I wanted to shift in new data to the TLC5947.
 
How long did that take? 30 seconds of just digitalWrite!
 
But there is a solution – using “true c” style commands, or what the AVR GCC (GNU C Compiler) uses. The brains behind Arduinos are ATMega168s or ATMega328s. The AVR community typically uses “true c” commands to program these chips, using AVR Studio 4. The advantage of using these “true c” commands is that it does exactly what you tell it to do.
 
But before we get in to these commands, we must get familiar with port and pin definitions in the next step!

(If you predict you will like this instructable, feel free to vote for the Arduino contest!)

Step 1: The Truth About Pins

Arduino users know that the pins are labeled as digital 0-13 and analog 0-5. The makers behind Arduino used this for simplicity. The actual ATMega chip’s pins are labeled differently, however. Each pin has an assigned letter and number. The numbers range from 0-7. For example, pins can be A0-A8, B0-B8, and so on. All of the AVR 8-bit pins are labeled this way.
 
To help you clarify which digital/analog pin corresponds to which AVR pin, see the chart below.
 
My Seeeduino has a LED built in on digial pin 13. So, looking at the chart, its real pin would be B5.
 
Next I will show you what the actual C command is.

Step 2: A and B Watch Out, C Is Here

Now it is time for the “true c” style statements! The thing is, there are quite a few of them and they all do the same thing. It gets confusing, but basically it boils down to changing a port register in some way.
 
There are many right ways to do it, but here is the way that I found to be the simplest. To turn a port high, use this command:
PORT{letter} |= _BV(P{letter}{number});
 
To turn a port low, use this command:
PORT{letter} &= ~_BV(P{letter}{number});
 
Replace {letter} and {number} with the corresponding pin letter and number. For example, for pin B5 with the LED, turning it high and then low would be:
PORTB |= _BV(PB5);
PORTB &= ~_BV(PB5);
 
Note that | can be found to the left of the backspace key, on the same key of the backslash.

So, basically, you can replace the entire digitalWrite() command with the above to get a faster response!
 
But how much faster is it, really? It is time for an experiment!

Step 3: Exspearimintation

In this experiment, I sought to find out how long it took the digitalWrite() command to execute 1000 times, and then how long it took the “true c” style command to execute 1000 times. The code is fairly simple, and shown below:
 
void setup()
{
 Serial.begin(9600);
}
void loop()
{
 int initial = 0;
 int final = 0;
 initial = micros();
 for(int i = 0; i < 500; i++)
 {
    digitalWrite(13,HIGH);
    digitalWrite(13,LOW);
 }
 final = micros();
 Serial.print("Time for digitalWrite(): ");
 Serial.print(final-initial);
 Serial.println("");
 initial = micros();
 for(int i = 0; i < 500; i++)
 {
    PORTB |= _BV(PB5);
    PORTB &= ~_BV(PB5);
 
 }
 final = micros();
 Serial.print("Time for true c command: ");
 Serial.print(final-initial);
 while(1);
}
 
 
Feel free to try this out yourself. Here are the results I got:
(Seeeduino with ATMega168)
Time for digitalWrite(): 3804
Time for true c command: 348
 
So each style turned on the pin 500 times and turned it back off 500 times. digitalWrite() took 3804 microseconds, while the true c commands took just 348 microseconds. The true c commands are 10 times faster than the digitalWrite()!

Try out this experiment for yourself, all you need is an arduino and a computer.

Step 4: Overview

Now you know that digitalWrite() takes significantly more time to execute than true c style commands. If you want to use arduino and time is important, I would highly recommend you use these true C style commands in lieu of digitalWrite(). While digitalWrite() is more convenient to change pins with, it takes 10 times longer!

I have attached a little cheat sheet below, print it out so it is handy whenever you need it.
 
I hope you have gotten something useful from this.
 
Vote for the Arduino contest! Thanks!

Step 5: Going Further

Are you the type of person who wants to know how everything works?

Basically, what happens when you tell a pin to go high or low is that you modify a 8-bit register. (Remember how the pins go from A0-A7, B0-B7? 8 pins per letter, so those 8 pins are toggled by that one register). A register holds 8 bits (Each bit can be 0 or 1).

When you execute the command to put a pin high, the appropriate bit in the register is set to 0. (1 would be low).

Having 8 pins toggled by one register can also have its advantages, mainly that you can toggle any of the 8 pins nearly simultaneously.

For example, if I wanted to turn pins C0 through C6 high and C7 low, the command would be:
PORTC = 0b10000000;

Note how the first pin number coming after the "b" is pin 7, and it goes down from there until pin 0.

0b10000000 is an 8-bit binary number, you can convert it to hex for a cleaner look. Doing it manually is a pain (but useful knowledge), an easier method would be to google "0b10000000 to hex", which results in "0x80".
PORTC = 0x80;

For further reading, see here:
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=37871
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1230286016
(thanks gmoon and westfw for the links)