Quantcast
Channel: SK Pang Electronics Ltd » Arduino
Viewing all articles
Browse latest Browse all 9

Faster IO on the Arduino

$
0
0

This article will show you how to control the Arduino IO pins faster, a lot faster.

We all know we can use the digitalWrite() command to set an IO pin high or low. Before we do any mods lets do some measurement to see how long it takes.

With a simple sketch to output a square wave on digital pin 2.

int outPin = 2; // Use digital pin 2 as output
void setup()
{
  pinMode(outPin, OUTPUT);      // sets the digital pin as output
}

void loop()
{
  digitalWrite(outPin, HIGH);   // sets output high
  digitalWrite(outPin, LOW);    // sets output low
}

To measure the time it takes to set the output pin high then low,  we’re going to use a Saleae Logic Analyzer.

Output waveform of Digital pin 2 using digitalWrite().

The captured waveform shows a width of 3.8333us that is the time it takes for output pin to go from low to high to low. This might sound fast but its not.

So what does digitalWrite() do? Lets take a look at this function. We need to find it first. It is stored in the wiring_digital.c file, part of the core files. On a Mac this file is located at

/Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/cores/arduino

For Windows the path will be different.

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);

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

As you can see, its doing a lot before writing to the port like checking the pin number is valid, check the PWM and turning it off if needed. All these takes time.

To speed up the IO we can do a low level port write instead.

From the Arduino schematic or Pin Mapping we can see digital pin 2 is really PD2 on the Atmega328 chip. That is Port D bit 2. We can set PD2 high by directly writing to Port D like this:

PORTD = B00000100;   // Set bit 2 high

The trouble with the above is that it will set all the other bits low. What happens if some of the other bits are high and you want to leave them alone? To solve this you need to read the current state of Port D, change bit 2 to high and write it back to Port D.

This can be done by:

unsigned char old_value;
old_value  = PORTD;
PORTD = old_value | B00000100; // The | is a bitwise OR

Both above lines can be combined into a single line without the use of another variable.

PORTD |= B00000100; // Set bit 2 high

To set the pin low we need to use the bitwise AND and invert the mask.

PORTD &= B11111011; // Set bit 2 low

The bit mask B00000100 is a right pain to type and it is subject to error. We can reduce this typing and error by using bit shift (<<) like:

PORTD |= 1<<2; // Set bit 2 high

The above will product B00000100 (0×04) at compile time.

To clear the bit we need to invert the mask.

PORTD &= ~(1<<2); // Set bit 2 low

The number 2 should really be in a #define to make thing clearer. So all together now :

#define PD2 2
int outPin = 2;                 // Use digital pin 2 as output

void setup()
{
  pinMode(outPin, OUTPUT);      // sets the digital pin as output
}

void loop()
{

  PORTD |= 1<<PD2;       // sets output bit 2 high
  PORTD &= ~(1<<PD2);    // sets output bit 2 low
}

Another capture from the Logic Analyzer.

Output waveform of Digital pin 2 using low level PORTD command.

The pulse width is now 0.1250us compare to the previous of 3.8333us  a big time reduction.

Q : When would you use this faster IO?

A : Anywhere where you need extra faster IO like in robotic applications. Inside an ISR (interrupt service routine) where you need execute the code and exit as quick as possible so the main routine can run. This method also uses less memory.

Q : What are the dis-advantage of this faster IO method?

A : There are no error checking. You can easily write to the wrong pin. It can be more difficult to debug.


Viewing all articles
Browse latest Browse all 9

Trending Articles