How to manipulate whole ports with Arduino

Arduino port manipulation is the “close to the metal” way of reading and writing bit.

In this tutorial we take a look at how it’s done.

Port manipulation?

It is undeniable that the ease of access and usage of the Arduino library is a key factor in its success. More specifically, you have access to functions such as pinMode and digitalRead / digitalWrite which makes it incredibly easy to control individual pins.

Under the hood though, it is not how a micro-controller works. You cannot control an individual bit. Instead, you have to read and write and entire “port”. On a 8 bit micro-controller, this means reading and writing a port of 8 bits. Port control is buried deep in the Arduino documentation so let’s review how it works here with some simple examples.

The Atmega328 pinout

If you look at a typical Arduino Uno pinout, you will notice that some pins are labelled “PB0” or “PD1”. These are the 8 bit ports that are part of the Atmega328 chip powering the Uno.

Arduino Uno pinout
Arduino Uno pinout

Straight from the documentation, you can read for instance:

Port D (PD7:0)
Port D is an 8-bit bi-directional I/O port with internal pull-up resistors (selected for each bit). The Port D output buffers have symmetrical drive characteristics with both high sink and source capability. As inputs, Port D pins that are externally pulled low will source current if the pull-up resistors are activated.
Side note: As a matter of fact, ALL Arduinos running the Atmega328 will behave exactly the same. That means the Arduino Uno, Arduino Nano, Arduino Mini & Pro Mini are pretty much the exact same product, in different form factors.

Controlling the port

Controlling the port with Arduino is really easy. There are two registers you need to know about:
  • DDRx (e.g. DDRD for port D) is the register that controls if pins are input or output. (0=input, 1=output)
  • PORTx (e.g. PORTD for port D) reads or write the bits.

For example:

is equivalent on an Arduino Uno to:

INPUT_PULLUP using port manipulation

“pinMode” in Arduino lets you select INPUT, OUTPUT, or INPUT_PULLUP. Since writing the DDR port only allows you to select input or output, there’s a trick to activating INPUT_PULLUP mode on a pin: you must set it to input, then write a high value to it. So instructions like:

…will set the whole port D as input pullups. In fact, this is very similar to the first revisions of the Arduino library where you had to do “pinMode(x, INPUT)” then “digitalWrite(x, HIGH)” to activate INPUT_PULLUP mode.

What are the benefits of direct port manipulation?

Direct port manipulation has several advantages:

  • You are closer to the metal: pinMode, digitalRead and digitalWrite perform underlying port manipulations.
  • You can write or read data simultaneously. Using digitalWrite for a pin then for another introduces a delay that is completely absurd when reading or writing parallel data. It might even creates some issues in very timing sensitive devices.
  • Code is smaller. Because you don’t introduce the additional layer of traditional Arduino functions, resulting code can be smaller.

Of course, the drawback is that the code becomes less readable in some cases. A mix of port manipulation and traditional Arduino function calls might be the key to a good program.

 

Example of usage:


Illuminating the LEDs like in the video above would mean a lot of code to be written with Arduino functions. Port manipulation makes this task incredibly compact code wise. See below the code for this example:

 

Conclusion

If your project needs to manipulate serial to parallel or parallel to serial ICs, BCD decoders, or any other ICs that needs to read or write data on more than a bit; using direct port manipulation is often beneficial.

For readability’s sake, do not overlook the good old Arduino bit manipulation functions though, as they are good enough for most usage.

Leave a comment

Your email address will not be published. Required fields are marked *

css.php