I’ve been experimenting with Arduino for quite a while and have had a lot of fun using it. Arduino is an open-source hardware platform which has become very popular with digital-artists, hardware-hackers and people interested in finding ways to make computing more physical.
While the Arduino IDE is suitable for most tasks, there are times when more granular control over the way that the ATMega microprocessor executes instructions is useful. This is where an understanding of Atmel’s assembly language comes in handy.
To be honest, I initially thought that assembly language would involve concepts that my brain would have a lot of difficulty comprehending. Luckily (for me) the process turned out to be far simpler than I initially imagined, and I was able to start using Atmel Assembly last night. I decided to post my experiences here in case it helps anyone else (and to cement the info in my own mind). Thanks go to a guy called eadthem on #freenode irc for help and guidance.

ATmega8 Microprocessor
AVR Studio
One of the great things about the ATmega chip (which is the family of microprocessor chips at the heart of the Arduino platform) is the range of free development tools which it’s parent company Atmel provides. In this case, I used an IDE called AVR Studio 3.5 (http://www.atmel.com/dyn/products/tools_card.asp?tool_id=2724)
As I run linux, I needed to use wine to run AVR Studio. There wasn’t any problem doing so. Wine decompresses to a folder in the fake ‘windows/temp’ directory…. you simply need to navigate and open ‘~/.wine/drive_c/windows/temp/cdrom/SETUP.EXE’ which runs and completes the installation process. After installation, Atmel Studio was available in application menu (Applications -> Wine -> Programs->Atmel AVR Tools->AVR Studio 3.56).
Obtaining Supporting Documentation
There are various versions of the ATmega chip in production – and each has a different range of capabilities associated with it. I’m using an Atmega8 microprocessor, so it was important that I made sure I had the relevant datasheet at hand and the AVR 8-bit Instruction Set documents. You can find these via the links below.
[*1] (http://www.atmel.com/dyn/resources/prod_documents/doc2486.pdf)
[*2] (http://www.atmel.com/dyn/resources/prod_documents/doc0856.pdf) <- pages 10 to 14 are especially relevant.
Setting up the Project
Okay, first task was to set-up a new project in AVR Studio.
Project -> new -> [give it a name] / [pick AVR assembler].
This creates a blank project. Next we need a new text file to put our assembly code.
File -> new text file -> [give it the name 'main.asm']
As far as I know, the name isn’t important – what is important is that when you right click this file, ‘assembler entry file’ is ticked. You also need to drag this file into the Assembler Files folder.
Next, right click the route node of the project, and select the ‘project settings’. Change the output file format to ‘intel hex’. This defines the format that will eventually be used by the programmer software / board to upload the code to the microprocessor.
Writing the Code
Okay – next step is to produce the required code.
Open up the text file created a few steps ago.
The very first stage involves setting the start point in your program memory, to hex address 3A. You need to add the following line at the begining of this newly opened file.
.ORG $3A
and then continue to add the following lines of code …
START: LDI r16,high(ramend) ;ramend=$025F p7-9 OUT sph,r16 LDI r16,low(ramend) OUT spl,r16
It’s worth running through some of the conventions here.
- The word preceding the colon, defines a point in the program code which can be called or jumped to later on. This is then used to enable us to call subroutines and create loops.
- The semicolon defines a comment.
- LDI and OUT are instructions … (a full list of the AVR instruction set can be found in the guide linked above [*2], pages 10-14)
- r16 is a register. Registers can be though of as internal variables, which are able to be accessed very quickly by the processor; some are specific and can only be used in certain circumstances, while others are general purpose.
- sph and spl refer to the AVR stack pointer (which is implemented as two 8-bit registers). The stack is a stack of data – you can add (push) data to the stack, or take (pop) data from the stack. Find out more about the stack on page 13 of [*1].
- As far as I can tell ramend, is a device specific constant, which refers to the end of the available data RAM.
For this first program, I simply wanted to make an LED flash. To do this, I need to output a HIGH signal followed by a LOW signal to one of the ports on the ATmega.
I was a bit confused here, thinking that port is another word for pin… it isn’t. The Atmega8 has three ports labelled BCD which are responsible for looking after 23 IO general purpose IO lines/pins.
- Port B
- looks after 8 I/O lines (PB7-0)
- Port C
- looks after 7 I/O lines (PC6-0) … but note that PC6 is special case and is different to others, it’s used as an IO pin or reset see page 5 of [*1] for more info.
- Port D
- looks after 8 I/O lines (PD7-0)
Each port pin consists of three register bits ( DDxn, PORTxn, PINxn). By using a bit of cleverness, all the required physical ports can be accessed through address lookups.
- DDxn bits are accessed at the DDRx I/O address,
- PORTxn bits are accessed at the PORTx I/O address
- PINxn bits are accessed at the PINx I/O address.
(N/B Page 65 of [*1] is a useful overview of how data is output (PORTxn), how pin direction is defined (DDRxn) and where input data is stored/accessed (PINxn), in relation to the available ports and pins.)
Because the ports and IO lines/pins are general purpose, we need to be able to define which are used for input and which are used for output. This is done by setting the port direction.
LDI r18,0b10000000 OUT ddrb,r18
LDI is the instruction for ‘load immediate’, OUT is the instruction for ‘out to i/o location’.
Next, we preload registers r18 and r19 with the data that we’ll use to make our LED flash… because we use these values many times, the assignment happens before the main loop.
LDI r18,0b10000000; set register to pin 7 high LDI r19,0b00000000; set register to all pins low
Then we can add the main loop …
MAINLOOP: out portb,r18 out portb,r19 jmp MAINLOOP
Now, the great thing about AVR Studio – is that you can use it to run your code in a simulator, which allows you to debug the code, while monitoring the status of registers, i/o ports etc..
Before we can simulate the code we need to include a file in our AVR Studio project (which gives device dependant info) at the beginning of the code. (a range of inc files can be found in the ‘Appnotes’ subdirectory of yr AVR Studio install)
.include "m8def.inc"
Then select; Project -> Build and run… You’ll need to select the chip you’re working with. Select View -> ‘registers’ & ‘new io view’… then you can step through yr code with F10 and examine it’s effect.
