Click here to Skip to main content
15,884,353 members
Articles / Internet of Things / Arduino

Faster and More Efficient GPIOs on Arduino Without Modifying the Sketch

Rate me:
Please Sign up or sign in to vote.
4.90/5 (15 votes)
13 Aug 2016CPOL3 min read 19.8K   309   12   10
I am presenting a new implementation of Arduino GPIO functions which are faster and more efficient than the original functions.

Introduction

Arduino comes with built-in GPIO functions which serve the purpose well. But it becomes clear that these functions are bulky and slow, after we compare their performance with other more efficient implementations. The argument that is often presented in favor of these inefficient functions is that they are primarily meant to be used by the hobbyists, which often value ease-of-use more that efficiency.

Here, I am not presenting the fastest implementation, but rather an implementation that is efficient while maintaining the same ease-of-use of the original Arduino functions.

Background

A couple of years ago while I was in university, I did a research to make Arduino libraries more efficient. Although I did succeed, but it was never used outside the laboratory. But now I have cleaned up the code, to make its use easier.

Using the Code

Using this code is fairly easy. All you have to do is copy the FastIO.h and FastIO.c to the Arduino core directory ([Arduino Folder]\hardware\arduino\avr\cores\arduino) and include the header file in your sketch.

C++
#include <FastIO.h>

How It Works

Every pin on Arduino is attached to a pin of AVR microcontroller. These pins are divided among different ports. These ports are memory mapped at different addresses inside AVR's memory. In order to manipulate these pins, we have to write to these specific memory regions.

So, how does Arduino access its pins just by using a pin number? Actually, Arduino has saved all the required information to its memory. So, when you call digitalWrite on a specific pin, Arduino software searches its memory for the required information (the address of the port to which the pin belongs, and its place on the port). Arduino software also requires some additional information about whether the pin is also attached to a timer or not, if it is then, which timer and at which place.

All this overhead makes the Arduino's built-in function very slow. My implementation tries to ease off this overhead, by making all the required information readily available to the function. So that the function could start manipulating the pins as soon as it is called instead of searching for the information.

It works by storing the information in an array of 4 bytes.

  • The first byte contains the location of the pin on a specific port.
  • The second byte contains the address of the port to which the pin belongs.
  • If the pin also has a timer attached to it, then the third byte contains the timer pins which controls the pin function.
  • The fourth byte contains the address of the timer which is attached to the pin.

In case the pin doesn't have a timer attached to it, both the third and fourth byte will be equal to zero.

At function calls, a reference to this array is passed to the function, instead of simply passing the pin number.

Benchmarks

The built-in digitalWrite function takes about 5us to change the pin state which is very slow for a microcontroller running at 16MHz (62.5ns period). My implementation makes this function 20 times faster by reducing the time to about 250ns. All this performance boost is achieved without making any changes to the sketch code, which is the main aim of this implementation.

As a bonus, the size of compiled sketch is also smaller when using my code (two kills in one shot).

Image 1

Image 2

Image 3

As you can see here, near native speeds could be achieved without making any changes to the sketch.

Limitations

Currently, this code is incompatible with the Arduino mega based boards. This is because I have reserved only one byte for the port address in the pin definition array, but in Atmega2560, some ports are located at addresses greater than 0xFF. This limitation could easily be avoided by reserving 2 bytes for port address and timer address. These changes will be made in a subsequent version once my implementation has been thoroughly tested on Atmega8/168/328P based boards.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionInteresting but have you seen this Pin
Jan Dolinay24-Feb-17 2:08
professionalJan Dolinay24-Feb-17 2:08 
AnswerRe: Interesting but have you seen this Pin
Mohiuddin Awan25-Feb-17 3:08
Mohiuddin Awan25-Feb-17 3:08 
GeneralRe: Interesting but have you seen this Pin
Jan Dolinay26-Feb-17 23:20
professionalJan Dolinay26-Feb-17 23:20 
GeneralRe: Interesting but have you seen this Pin
Mohiuddin Awan27-Feb-17 13:33
Mohiuddin Awan27-Feb-17 13:33 
GeneralRe: Interesting but have you seen this Pin
Jan Dolinay27-Feb-17 23:25
professionalJan Dolinay27-Feb-17 23:25 
GeneralDoing something similar Pin
Chad3F18-Aug-16 11:46
Chad3F18-Aug-16 11:46 
GeneralRe: Doing something similar Pin
Mohiuddin Awan19-Aug-16 2:48
Mohiuddin Awan19-Aug-16 2:48 
GeneralRe: Doing something similar Pin
Chad3F19-Aug-16 17:43
Chad3F19-Aug-16 17:43 
QuestionCareful in the future ! Pin
marcus obrien15-Aug-16 8:47
marcus obrien15-Aug-16 8:47 
AnswerRe: Careful in the future ! Pin
Mohiuddin Awan15-Aug-16 9:37
Mohiuddin Awan15-Aug-16 9:37 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.