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 m328def.inc 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 ?

ALSO: http://www.atmel.com/webdoc/avrassembler/avrassembler.wb_directives.html

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 : http://tigcc.ticalc.org/doc/gnuasm.html#SEC86

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 <avr/io.h> ' ? 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."
#endif

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


#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

etc...


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 _SFR_IO8 function. But actually, it is not a function, it is a directive.

As shown in

http://garretlab.web.fc2.com/en/arduino/inside/avr/sfr_defs.h/_SFR_IO8.html

Abstract

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 _SFR_IO8() 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().

Note:

The use of io_addr + __SFR_OFFSET makes more sense when you see this link http://www.protostack.com/blog/2010/12/avr-memory-architecture/

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 ) 
           <---- (AKA THIS IS THE SPECIAL FUNCTION REGISTER!)
 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)


  • http://gcc.gnu.org/wiki/avr-gcc

  • http://stackoverflow.com/questions/23457389/avr-assembler-define-vs-equ-is-it-the-same

  • http://www.atmel.com/Images/doc1022.pdf - AVR Assembler User Guide (By Atmel)

  • http://www.atmel.com/Images/avr_3_04.pdf