AVR Learning – Original from http://8051projects.net
This include the definition file for ATmega8515, so that we can directly address the registers with
All AVRs have 32 general purpose registers from R0 - R32.
R0-R15 registers have certain restrictions of use, i.e. they are not allowed to load immediate value.
e.g. LDI R15, $35
the above statement will give you an error, saying "Invalid Register"
Where as registers from R16-R32 can be used for this purpose i.e.
is a valid statement.
You can move values from one register to other by using
Not only the registers from R0 to R15 has restriction on LDI but also other commands where the use of
R0-R16 is not allowed. usually all commands having immediate operands are not allowed.
For the ease of programming, you can also give names to the register like
.def myregister = R16
There are some special registers like X,Y and Z for 16-Bit operations. They are used to read and write
to XRAM. They are also used for reading from program memory like reading from a lookup table (we
will discuss about them when we use them). These special registers are actually combination of two 8-
bit General purpose registers. i.e. X is actually R26:R27, Y is R28:R29 and Z is R30:R31.
The lower byte of the 16-bit-adress is located in the lower register, the higher byte in the upper register.
Both parts have their own names, e.g. the higher byte of Z is named as ZH (R31) and the lower Byte is
ZL (R30). Similarly for X (XL and XH) and for Y (YL and YH). These names are defined in the
standard header file for the chips (which we include while writing program). Dividing these 16-bit-
pointer-names into two different bytes is done like follows:
LDI YH,HIGH(LABEL) ; Set the MSB
LDI YL,LOW(LABEL) ; Set the LSB
where LABEL is address for any lookup table or any memory location.
Some important notes for using registers
1. Define names for registers with the .DEF directive, never use them with their direct name Rx.
This helps you making better use of registers and you will never confuse yourself while using
2. If you need pointer access reserve R26 to R31 for that purpose.
3. 16-bit-counter are best located R25:R24.
4. If you need to read from the program memory, e.g. fixed tables, reserve Z (R31:R30) and R0 for
5. If you plan to have access to single bits within certain registers (e.g. for testing flags), use R16
R23 for that purpose
Now coming to ports, The information about a specific port of a certain type of AVR can be easily
obtained in the AVR Datasheet. Port names are defined in the include file of the CPU..
if you don't have an include file then you can define yourself as..
.equ PORTA = $1B ;incase of ATmega8515
So if you are not able to find an include file you can use the .EQU directive to define ports and other
Making port as i/p or o/p is purely dependent on data direction register called DDRx (DDRA for port A
etc.) The DDxn bit in the DDRx Register selects the direction of this pin. If DDxn is written
logic one, Pxn is configured as an output pin. If DDxn is written logic zero, Pxn is configured
as an input pin.
for writing and reading data to Ports, PORTx registers are there. and to read from ports PINx registers
writing to port
.def output = R16
LDI output, $FF
OUT DDRA, output ; making as o/p
LDI output, $00
OUT PORTA, output ; clear all PORTA pins
Reading from port
.def input = R17
LDI input, $00
IN input, PINA
We are finished with the basics of AVR, lets try programming with simplest program. Blinking an
.include "8515def.inc" ;Include file
RJMP MAIN ;Reset vector
ldi R16,low(RAMEND) ;Load stack with
out SPL,R16 ;RAMEND - highest value
ldi R16,high(RAMEND) ;of internal SRAM
SBI DDRA,0 ;Make PORTA Pin 0 as o/p
SBI PORTA,0 ;Set Pin 0 of PORTA
RCALL DELAY ;Wait for some time
CBI PORTA,0 ;Cleare Pin 0 of PORTA
RCALL DELAY ;Wait for some time
RJMP DO ;Forever loop!
DELAY: ;The delay routine
LDI R16,$20 ;Load some delay value
SER R17 ;Make R17 as $FF
DEC R17 ;Decrement R17
BRNE LOOP ;Jump if not zero
DEC R16 ;Decrement R16
BRNE LOOP1 ;Jump if not zero