AVR ASSEMBLER CRASH COURSE.




So you wanna learn avr assembly?

What we will do here is make an avr flash leds, and understand the program that makes it happen.
The source we will be working with is here, it flashes leds on port B of a atmega32.

Basic steps to avr software:
Then we will break down the code



Make code
  This step is easy cause I did it for ya.
  download it

I also have a much better formed avr 'skel' that I use to write up my own avr programs,
you can download that too.


Compile code
  Linux:
      G AVR ASM:
           From command line, type:
              gavrasm test1.asm
           it should generate the files:

             

 Windows:
jkkhkh



Upload code
    Bsd:
avrdude:

    Linux:
avrdude:

you need a config file, it will tell avrdude how to access whatever type of programmer you have.
   !!!???!!!

From command line, type:
avrdude -p m32 -e -U flash:w:flash-test1.hex

* the m32 is for atmega32
atmega32
m32
atmega16 m16
atmega8 m8
tiny13
t13


   Windows:
 Avrdude:




Breaking down the code:

The code:

;***** Specify Device
.include "m32def.inc"

.def tempport =r16
.def count1 =r17 ; and logic instructions
.def count2 =r18
.def count3 =r19
;******************************************************************
.cseg ;CODE segment
.org 0x0000
rjmp init ; origin

.org 0x012A
init:
ldi r16,high(RAMEND)
out SPH,r16
ldi r16,low(RAMEND)
out SPL,r16
cli
ldi tempport,$FF
out DDRB,tempport ; set portb pin 2 as output
ser tempport
out PORTB,tempport ; set portb pin 2 level high

start:
ldi tempport,$00 ; set tempport bit 0 low
out PORTB,tempport ; write to port

rcall wait ; do the wait thing

ldi tempport,$FF ; set tempport bit to high
out PORTB,tempport ; write to port

rcall wait ; do the wait thing

rjmp start ; go back and do it all over again


; ----------------------------
; wait subroutine
; ----------------------------
wait:
ldi count1,5 ; load count1 with decimal 200

d1:
ldi count2,200 ; load count2 with decimal 200

d2:
ldi count3,200

d3:
dec count3
brne d3
dec count2 ; decrement count2
brne d2 ; loop if not zero
dec count1 ; decrement count1 if count2 is zero
brne d1 ; do inside loop again if count2 nz
ret
; ----------------------------



Description:
generated from the contents of the irc log: http://eds.dyndns.org:81/~ircjunk/irclogs/html/%23robotics-19-01-2005.html

First , we need to tell the compiler What device to compile for. This will define things like the value of named things like PORTB.
Lines that start with ; are comments, for making notes about what your code is doing.

;***** Specify Device
.include "m32def.inc"

r0 through r32 are memory locations, scratch space. Think of it as a place you can put a number.

.def tempport =r16
.def count1 =r17 ; and logic instructions
.def count2 =r18
.def count3 =r19

I
gnore from init to start, it sets up the processor, if its properly written in never really changes anyhow. This is not done right, we will just ignore that for now..

;******************************************************************
.cseg ;CODE segment
.org 0x0000
rjmp init ; origin

.org 0x012A
init:
ldi r16,high(RAMEND)
out SPH,r16
ldi r16,low(RAMEND)
out SPL,r16
cli

This bit sets all the port B pins to output

ldi tempport,$FF
out DDRB,tempport ; set portb pin 2 as output

This bit sets all the bits of port B to be high (5V)

ser tempport
out PORTB,tempport ; set portb pin 2 level high

This is where the good stuff starts....

start:

ldi tempport,$00 ; set tempport bit 0 low
ok, so that puts the number into the 'scratch space'
 
puts the number $00 (in hexidecimal) into tempport.
 
The $ means its hex
.


out PORTB,tempport ; write to port

it takes the number from tempport puts it in PORTB
that affects all outputs on PORTB which is 8 of em.
so all leds are off now.
$00 = (binary) 00000000


rcall wait ; do the wait thing
this is a program flow change thing. So is like
1 second wait is defined elsewhere. The program
remembers where it is, and goes to the wait 'label'
scroll down, see the "wait:" ( thats you, reader)


ldi tempport,$FF ; set tempport bit to high

sets
tempport to FF. FF hex is 255 decimal
255 in binary is 11111111


out PORTB,tempport ; write to port
set PORTB to $FF. More specifically the value of the
 tempport memory location. So all leds turn on
.


rcall wait ; do the wait thing
then it waits again

rjmp start ; go back and do it all over again
then goes to start




; ----------------------------
; wait subroutine
; ----------------------------

the foo: things are labels, marked program locations

wait:
ldi count1,5 ; load count1 with decimal 200
ldi loads a number directly into the location
decimal 5


d1:
d1: is another label

ldi count2,200 ; load count2 with decimal 200
count2 memory location loaded with decimal 200

d2:
ldi count3,200

d3:
dec count3

look up the instruction tell me what you think. Its
 like a strange alien language, that the little guys
 decided to encypt just or the fun of it. Take the
 current number and reduce it by 1
. S
o, after that,
 the value of count3 is
199


brne d3
keep a bookmark on the dec command. What does this
 instruction say it does? What is the long name of
 the instruction?
 "Branch if not Equal"
 and it knows if "its equal" by checking Z

Keep your hand on that page, flip back to the Dec page.
Ok, there are a set of 'flags' in the controller. They
are used to pass status information between instructions.
 Most instructions change the status flags based on
 what they did. See the "Status Register and Boolean Formula:"
 on the dec command? The diagram under it shows you all
 the processors status flags. The ones that the dec
 can change have the arrows in them. Under that is the
 description of what the rules are that dec uses to set
 them
you looking for the rule for the Z flag. The Z
 flag will take one of two different states based on the
 result of the dec command. So, your looking at the table
 of with all the flags on it...

Try to stop the flags waving in your head.
They are all true/flase flags.
Just up or down, no waving :)
up = true = set
down = false = clear = unset

Set if the result is $00; Cleared otherwise.

So... if the result of dec is 0, it will set the Z flag.
Otherwise the z flag will be clear

"Branch if Zero flag clear" <-- should be.
 brne will only go do d3: if the Z flag is clear

 So, where does brne go if dec didn't result in 0?
 It branches if the dec was not equal (zero), meaning
 the zero flag is clear

"Tests the Zero Flag (Z) and branches relatively to PC if Z is cleared."
edited...
Tests the Zero Flag (Z) and branches if Z is cleared.
Tests the Zero Flag and branches if Z is cleared.
there english!

lets say the dec commands result is NOT equal to zero
What does brne do? Where does the 'program pointer' go?
The options are d3: or the next instruction.

The result of the dec is not zero, so is the Z flag set or clear?
lets say its 199, it would be clear.
"Tests the Zero Flag and branches if Z is cleared."
So what does it do?,
the dec's result was 199, the Z flag is clear.
The brne tests the Z flag, and decides to branch based on that.
A'branch' is a 'jump' out of the normal downward flow.
it will 'branch' to d3.

ok, so, lets say the result of the dec IS 0
whats brne going to do?
mm, now it has to work
dec WILL SET THE Z FLAG
brne dosn't modify the flags
it does not go to d3
it allows the program pointer to keep going down
'along' "down the page"

shall we go over that one more time, a small example perhapps?

1 ldi count3, 3
2 d3:
3 dec count3
4 brne d3


ok, first line, what does it do
load 3 to count3

second line?
label "d3"

third line, with current values, tell me what happens
it take 1 away from 3 leaving 2 , Z is clear

fourth line, with current values, tell me what happens

what is brne looking at?
the value of Z
what IS the value of Z?

clear still
so what does it do?
loops ('branches')
to d3

so when it loops, what is the next instruction it does?
it does dec again
so count3 becomes 1
Z is still clear
...
then does d3 again
count1 becomes 0

oh no the hard bit
Z flag is set
and brne does not branch
so the program goes on
and and then it is done.

ok, lets skip down a bit


dec count2 ; decrement count2
brne d2 ; loop if not zero
dec count1 ; decrement count1 if count2 is zero
brne d1 ; do inside loop again if count2 nz


ret
look up 'ret' what does it do?
 subroutine return
  remember how I said that then the processor went to
  "wait", it remembered where it was?

  well now it does a subroutine return,
to the instruction
  after what got it "there"
  remember what instruction got us to wait?
  rcall wait
  whats the next instruction?
  ldi tempport,$FF
  so it goes there (you too, reader)


; ----------------------------