Chapter 2

Note: The program i wrote is for ATMEGA8515 and there is not much difference in other AVRs except some has extra features.


Before programming AVR, first you need to know few important programming tips and AVR registers.
CODE:
.include "8515def.inc"

This include the definition file for ATmega8515, so that we can directly address the registers with their names.
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.
LDI R16,$35
is a valid statement.
You can move values from one register to other by using
MOV R15,R16

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
CODE:
.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:
CODE:
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 them.
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 that
purpose.
5. If you plan to have access to single bits within certain registers (e.g. for testing flags), use R16 to
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..
CODE:
.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 registers.
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 are there.
for example..
writing to port
CODE:
.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
CODE:
.def input = R17
LDI input, $00
OUT DDRA,input
IN input, PINA



We are finished with the basics of AVR, lets try programming with simplest program. Blinking an LED!
CODE:
.include "8515def.inc" ;Include file

RJMP MAIN ;Reset vector

MAIN:
ldi R16,low(RAMEND) ;Load stack with
out SPL,R16 ;RAMEND - highest value
ldi R16,high(RAMEND) ;of internal SRAM
out SPH,R16
SBI DDRA,0 ;Make PORTA Pin 0 as o/p

DO:
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
LOOP1:
SER R17 ;Make R17 as $FF
LOOP:
DEC R17 ;Decrement R17
BRNE LOOP ;Jump if not zero
DEC R16 ;Decrement R16
BRNE LOOP1 ;Jump if not zero
RET ;Return

No comments:

Post a Comment