Assembly Programming

Writing your first assembly program in AVR Studio 5

Open a new design project in AVR Studio 5 by selecting File>New>Project to bring up the following dialogue window

New project dialogue

Under installed templates choose AVR Assembler, enter a name for your project e.g. HelloWorld and click OK. The device selector window shown below will appear.

Device selector

Select the device that matches your hardware and press OK. For the Arduino UNO this is the ATmega328P and for the Arduino MEGA 2560 this is the ATmega2560 which is the device selected here.

This will now create your project and open a blank HelloWorld.asm file in the editor. Paste the following Hello World assembly code into the editor. This code causes the LED attached to pin 13 of the Arduino board to blink at about 1Hz.


/*
 * AssemblyBlink.asm
 *
 * Simple program to blink the LED attached to pin13 of the Arduino MEGA board
 * Created: 03/11/2011 08:32:28
 * Author: Benn Thomsen
 */

.nolist
.include "m2560def.inc" ; Assembly include statement
.list
 rjmp main ;Ensure that operation starts at the main label after reset
main:
 ldi r16,0xFF ; Load Immediate. This sets r16 = 0xFF (255)
 out DDRB,r16 ; Set the pin direction register B as outputs
 ldi r16,0x00 ; Load Immediate. This sets r16 = 0x00 (0)

loop: ; This is a label to jump back to
 com r16 ; Invert all the bits in r16 (one's complement)
 out PORTB,r16 ; set all B pins to current state. PORTB is where our favorite flashing pin is (pin 13)!
; Waiting for a specified time:
; The Arduino MEGA is clocked at 16MHz, which means that we have to wait
; 16 million cycles between flips. Different instructions take different
; amounts of clock cycles to complete, so we have to count the cycles
; to get an accurate wait time. We're going to use a combination of an inner
; and outer counter using a word (16 bits) and a byte (8 bits), respectively
; to count the number of cycles, since just a single byte or word .

; Counting cycles:
; Below you'll see a couple instructions with numbers in their comments.
; The numbers represent how many clock cycles the instruction takes.
; You can find all of these cycle amounts in the atmega2560 datasheet.
; 1/2 means it can take either one or two cycles depending on the flag
; state. For these branch instructions (BRNE), they take one cycle if
; the condition is false, and two cycles if it's true. We'll only care
; about the two cycle case, since that will be happening 99% of the time.
; Also, we will ignore the outside loop's cycles as these only occur once
; per overflow of the inner couter

; The Arduino is clocked at 16MHz, or 16000000 cycles per second.
; The inner loop takes 4 cycles to complete one loop, since SBIW
; takes 2 cycles and BRNE will (usually) take 2 cycles. It takes two cycles
; to jump to the label. This means that we need to find an X < 256 and
; Y < 65536 so that X*Y*4 = 16000000. E.g. X=100 and Y=40000
; The outer loop runs 100 times, and the inner runs 40000 times per outer
; loop. This gives us about 1 second per flip!

ldi r17,100 ; r17 is our outer loop counter
outer:
 ; ZH and ZL are a word pseudo-register. It's actually a combination
 ; of r31 and r30, giving us 16 bits to use for SBIW.
 ; The HIGH and LOW macros just give us the high and low bits of a
 ; number.

ldi ZH,HIGH(40000) ; 1 cycle
 ldi ZL,LOW(40000) ; 1 cycle

inner:
 ; These next two instructions SuBtract Immediate from Word and
 ; BRanch if Not Equal. One is subtracted from the Z psuedo
 ; register (which begins with ZL, the low bits), and then, if we haven't
 ; reached 0, go back to the inner label. Otherwise we keep on going with
 ; the check for the outer loop!

sbiw ZL,1 ;2 cycle
 brne inner ;1 or 2 cycles
 ;Inner Loop (4 cycles)

; The following instructions DECrement and BRanch if Not Equal. BRNE
 ; works exactly the same as above. DEC is shorthand for subtract one
 ; from this register.

dec r17 ;1 cycle
 brne outer ;1 or 2 cycles

; Finally we've reached the end of the delay loop. Relative JuMP just brings
 ; us back to the label listed.

rjmp loop

Assembling the code

Press the Build Solution button in the build toolbar (Or press F7). The assembly code will now be assembled and you should get the following message in the Output pane

Build succeeded.
===== Build: 1 succeeded or up-to-date, 0 failed, 0 skipped ======

Simulating the code

Once the code is built you can simulate it by choosing Debug>Start debugging and break. You will need to select AVR simulator in a dialog box that appears. The contents of the registers can be seen in the IO View Pane that then appears. You can use Step into (F11) to step through the code line by line.

You might like to change the inner and outer counter values to 4 and 2 respectively for the simulation. You should make sure that the program runs through the inner and outer loops the correct number of times and that the bits in PORTB are set and cleared appropriately.

1 thought on “Assembly Programming

  1. Pingback: Atmel Studio 6.1 | nekenyu

Leave a comment