Wednesday, May 15, 2013

Teensy Basics 5: Port Manipulation

Overview
This article assumes that you have read Teensy Basics 1 and Teensy Basics 2 and Teensy Basics 3 and Teensy Basics 4.

Port manipulation with the Teensy allows the code to read, write and set the direction of up to 8 digital pins at once using low-level instructions. Port manipulation is useful for optimising code and for instantaneously setting multiple pins or receiving data from multiple digital pins.

Considering the Teensy Pinout
To understand port manipulation, an understanding of binary notation is useful.

Binary notation represents numbers with either a 0 or a 1 per digit. With microcontrollers, it is sometimes very useful to think in terms of binary notation for specific tasks:
- Interfacing with groups of pins
- Dealing with certain kinds of maths (bitwise operators)

Each additional bit that we can use to represent a given number increases the range of numbers that we can represent, as follows:

1 bit = 2^1 = 0 – 1 = X
2 bits = 2^2 = 0 – 3 = XX
3 bits = 2^3 = 0 – 7 = XXX
4 bits = 2^4 = 0 – 15 = XXXX
5 bits = 2^5 = 0 – 31 = XXXXX
6 bits = 2 ^6 = 0 – 63 = XXXXXX
7 bits = 2^ 7 = 0 – 127 = XXXXXXX
8 bits = 2^8 = 0 – 255 = XXXXXXXX

Binary notation can be used in Teensy / Arduino by using the prefix 'B'.

e.g. B11111111 = 255
e.g. B00001111 = 15
e.g. B00000111 = 7
e.g. B10011010 = 154
e.g. B01111111 = 127

Port manipulation refers to dealing with groups of pins at once. Port manipulation allows the program to read or write groups of digital pins simultaneously without needing to using multiple digitalWrite() or digitalRead() commands.

The Teensy has a number of ports, namely PORTB, PORTD, PORTC and PORTF. Each port is made up of up to eight pins. Every input or output on the Teensy is part of a port.

Normally - when addressing individual digital pins in the Arduino IDE - it is sufficient to think about Teensy as having a pinout as follows:

However, we can also consider the Teensy in terms of ports, as follows:
Every input / output pin is labelled as P something, e.g. PB0, PB1, PB2 etc. This literally means "Port B, pin 0", "Port B, pin 1" etc.

In order to manipulate these ports i.e. these groups of pins, there are specialized functions.

The three port manipulation commands are:
PORTx – “replacement” for digitalWrite()
DDRx – “replacement” for pinMode()

PORTx sets the pins of that port to either HIGH (1) or LOW (0) in binary. It is a replacement of using digitalWrite() eight times in a row

e.g.
PORTD = B11111111; // == 255
PORTD = B00000000;  // == 0

PINx reads the value of the the PORT pins in binary. It is a replacement of using digitalRead() eight times in a row

e.g.
if(PIND == B00000000) {
// do something if no pins are HIGH
}

DDRx sets the direction (input or output) using a binary number. It is a replacement of using pinMode() eight times in a row. A "1" in that bit position will set that pin as an output. A "0" in that bit position will set that pin as an input.

e.g.
DDRD = B11111111;
// all pins of PORTD as outputs!
DDRD = B00000000;
// all pins of PORTD as inputs!

Conclusions
Although there are often times when standard digitalWrite and digitalRead can be used, there are times when using port manipulation is extremely useful. Keep this in mind when programming for Teensy and Arduino!