Understanding More About AVR Programming
posts avrThis 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