■ FIGURE 3. PORT, PIN, and DDR memory map.
The data memory space is shown in Figure 2 and
consists of the 32 lowest bytes used for general-purpose
processor working registers, then the next 64 bytes used
as I/O registers, followed by 160 bytes of extended I/O
registers, and then finally beginning at address 0x0100
(decimal 256), the SRAM. The digital I/O is mapped into
the 64-byte registers section as shown in Figure 3.
Digital I/O is Based on Registers
These digital I/O registers are eight-bit bytes. Any bit
within that byte (which to the outside world is an I/O pin)
can be individually addressed without affecting any other
bit/pin in the byte/port. This is an important concept since
it allows us to have one port pin set as an input and
another set as an output, with the ability to change either
without affecting the other.
So, how does this work? Figure 4 provides some
visual clues. Each port has three registers associated with
it. A data direction register, DDRx, will — as the name
suggests — set the direction of the port to input or output.
There’s a PORTx register you use to write data to that is
then output on the port pins. A very poorly named register,
PINx, lets you input data from the port pins. Why do I say
it is poorly named? Because it is a full eight-bit byte-sized
representation of the port input and isn’t restricted to a
single pin as the name may imply. They might have named
these with out and in — POUTx and PINx — to be less
confusing, but folks would laugh at POUT and still confuse
PIN with pin. Maybe PORTOUTx and PORTINx would
have been clearer (but who wants to type that much).
This is one of those weird things that you just have to
get used to and memorize — that you write to the eight
bits as PORTx and you read the eight bits as PINx. If you
want to actually look at any one pin of a port, then
depending on whether you are reading or writing (based
on the DDRx setting for the pin), you have to use the
bitwise operators to do that single pin reading and writing.
Since this invariably bites novices, let me repeat: You
write eight-bit output to PORTx and you read eight-bit
input from PINx.
Now, memorize this: Writing a 1 to a DDRx bit sets the
port pin for that bit to output. Writing a 0 to a DDRx bit sets
the port pin for that bit to input. So, 1 = output; 0 = input.
Avrlibc Input Output Header Files
Among the many goodies supplied by avrlibc is a
header file that allows you to use convenient #define
constants for the registers and bits associated with the
ports and pins. The Arduino-like simplification that we
learned last month in Workshop 39 provides a layer of
code that is great for doing ‘simple.’ If you want to get a
little deeper with real C, then having the io.h constants
helps keep things sort of simple without having to get
right down to the actual register names.
When you compile a file in AVRStudio, you first select
the AVR device in the projects options as shown in
Figures 5 and 6 where we select the atmega328p. This
selection is used by AVRStudio to generate a makefile that
is used by the version of gcc supplied by WinAVR to
■ FIGURE 4. Port I/O module.
November 2011 49