This is just a note for me to recall on how or what really happens in coding an AVR program:

ATMEL STUDIO 6 Observation

x= register letter (e.g. DDRA DDRB etc... )

DDRx :~ Data Direction Register (read/write)
    : Defines if pin is output=1 or input=0

PORTx :~ Pin Output Mode Register (read/write)
    : If input then
       - pullup=1 floating=0
    : If output then
       - high=1 low=0

PINx :~ Pin INput register (read only)
    : sense @ pin: 1=highIn 0=lowIn

How are port registers location defined? e.g. What does PORTD refer to?

In atmel studio 6 in this location:

C:\Program Files (x86)\Atmel\Atmel Toolchain\AVR Assembler\Native\2.1.1175\avrassembler\include

You have an entry in file like:

.equ    PORTD   = 0x0b
.equ    DDRD    = 0x0a
.equ    PIND    = 0x09
.equ    PORTC   = 0x08
.equ    DDRC    = 0x07
.equ    PINC    = 0x06
.equ    PORTB   = 0x05
.equ    DDRB    = 0x04
.equ    PINB    = 0x03

Which defines the IO register pointers in AVR memory.

What the hell is .equ ?


Assembler Directives

All assembler directives have names that begin with a period (`.'). The rest of the name is letters, usually in lower case.

.equ symbol = expression

The EQU directive assigns a value to a label. This label can then be used in later expressions. A label assigned to a value by the EQU directive is a constant and can not be changed or redefined.

Very similar to #define, but can only be defined once.

Seems to be similar to :

But I think the AVR assembler is a modified version of GCC to accept .equ symbol = expression instead/inaddition? to .equ symbol, expression (Maybe someone can clarify this?)

API :~ application programming interfaces define interfaces between program

ABI :~ application binary interface (ABI) is the interface between two program modules

included in avr/io.h ?

Btw Whats in ' #include ' ? Ans: The compiler and the IDE will include in this location, the officially atmel recognized definition e.g."avr/iom328p.h - definitions for ATmega328P"

/* $Id: iom328p.h 2444 2014-08-11 22:10:47Z joerg_wunsch $ */

/* avr/iom328p.h - definitions for ATmega328P. */

/* This file should only be included from <avr/io.h>, never directly. */

#ifndef _AVR_IO_H_
#  error "Include <avr/io.h> instead of this file."

#ifndef _AVR_IOXXX_H_
#  define _AVR_IOXXX_H_ "iom328p.h"
#  error "Attempt to include more than one <avr/ioXXX.h> file."

#ifndef _AVR_IOM328P_H_
#define _AVR_IOM328P_H_ 1

/* Registers and associated bit numbers */

#define PINB _SFR_IO8(0x03)
#define PINB0 0
#define PINB1 1
#define PINB2 2
#define PINB3 3
#define PINB4 4
#define PINB5 5
#define PINB6 6
#define PINB7 7

#define DDRB _SFR_IO8(0x04)
#define DDB0 0
#define DDB1 1
#define DDB2 2
#define DDB3 3


Arduino Observation

I see the above is probbly just for AVR Studio with their AVR Assembler.

For arduino, their source code is a bit different in terms of how it references ports in a chip, using AVR-GCC.

e.g. You find that in:

C:\Program Files (x86)\Arduino\hardware\tools\avr\avr\include\avr

They would define a memmory mapped register as:

#ifndef _AVR_ATmega32U6_H_
#define _AVR_ATmega32U6_H_ 1

/* Registers and associated bit numbers. */

#define PINA _SFR_IO8(0x00)
#define PINA0 0
#define PINA1 1
#define PINA2 2
#define PINA3 3
#define PINA4 4
#define PINA5 5
#define PINA6 6
#define PINA7 7

#define DDRA _SFR_IO8(0x01)
#define DDA0 0
#define DDA1 1
#define DDA2 2
#define DDA3 3
#define DDA4 4
#define DDA5 5
#define DDA6 6
#define DDA7 7

using this cryptic SFRIO8 function. But actually, it is not a function, it is a directive.

As shown in


The _SFR_IO8() converts the I/O address to the memory address. It is a macro that returns a byte of data at an address of io_addr + __SFR_OFFSET.

Source Code

The SFRIO8() is defined in hardware/tools/avr/avr/include/avr/sfr_defs.h as below.

#define _SFR_IO8(io_addr) _MMIO_BYTE((io_addr) + __SFR_OFFSET)
#define __SFR_OFFSET 0x20
Adding __SFR_OFFSET to io_addr, then calls _MMIO_BYTE().


The use of io_addr + __SFR_OFFSET makes more sense when you see this link

The memmory stucture of AVR is like this

# FLASH (16 Bits wide) (start at 0x000, ends at FLASHEND )
 * Application 
  - Flash section ( Read while Write )
  - Optional Flash Section (No Read while Write)
 * Optional Bootloader

# Ram (8bit wide)
 0x0000 : 32 General Purpose Registers
 0x0020 : 64 I/O Registers ( THIS IS WHAT __SFR_OFFSET refers to ) 
 0x0060 : 160 Extended I/O Registers
 0x0100 : Internal Ram (Accessable for variables etc...)
 RAMEND : End of internal Ram
 RAMEND+1: External RAM
 0xFFFF : Max memmory address.

# EEPROM ( 8 bit wide) ( start at 0x000, ends at EEPROMEND )

So that should give you an idea, of what exactly is going on... At least for AVR-GCC (and AVR Assembler too)



  • - AVR Assembler User Guide (By Atmel)