Introduction: AVR Assembler Tutorial 1

I have decided to write a series of tutorials on how to write assembly language programs for the Atmega328p which is the microcontroller used in the Arduino. If people remain interested I will continue to put out one a week or so until I run out of free time or else people stop reading them.

I am running Arch linux and I am working on an atmega328p-pu set up on a breadboard. You can do it the same way as me or you can simply plug an arduino into your computer and work on the microcontroller that way.

We will be writing programs for the 328p like the one that is in most arduino's but you should note that these same programs and techniques will also work for any of the Atmel microcontrollers and later on (if there is interest) we will work with some of the other ones as well. The details of the microcontroller can be found in the Atmel data sheets and the Instruction Set Manual and so you may want to keep a copy of them for reference. You can find them here (I am also attaching them to this instructable in case they change the links at some point in the future):

www.atmel.com/images/Atmel-8271-8-bit-AVR-Microcon...

http://www.atmel.com/images/atmel-0856-avr-instruc...

Here is what you will need:

1. A breadboard

2. An Arduino, or just the microcontroller

3. A computer running Linux

4. The avra assembler http://sourceforge.net/projects/avra/files/

5. avrdude http://www.nongnu.org/avrdude/

The complete set of my AVR assembler tutorials can be found here: https://www.instructables.com/id/Command-Line-AVR-T...

Step 1: Construct a Testing Board

You can simply use your arduino and do everything in these tutorials on that if you like. However, since we are talking about coding in assembly language our philosophy is inherently to strip away all the periferals and interact directly with the microcontroller itself. So don't you think it would be more fun to do it that way?

For those of you who agree, you can pull the microcontroller out of your arduino and then start by constructing a "Breadboard Arduino" by following the instructions here: http://arduino.cc/en/Main/Standalone

In the picture I show my set up which consists of two standalone Atmega328p's on a large breadboard (I want to be able to keep the previous tutorial wired and loaded on one microcontroller while working on the next one). I have the power supply set up so that the very top rail is 9V and all of the others are 5V from the voltage regulator. I also use an FT232R breakout board to program the chips. I bought them and put bootloaders on them myself, but if you just pulled one out of an Arduino then it is fine already.

Step 2: Install the Assembler and Avrdude

You can now download and install the assembler and avrdude from the links given on the first step of this tutorial. It is likely that if you have already been working with Arduino's then you already have avrdude installed.

After you have avra installed you will notice that there is a subdirectory that comes with it called "sources" and inside that directory are a bunch of include files. These are all of the microcontrollers that you can program with avra. You will notice right away that there is no file for the 328p that we are using here. I have attached one. The file is called m328Pdef.inc which you should put inside the includes directory or anywhere else you like. We will be including it in our assembly language programs. All this does is give each of the registers in the microcontroller names from the data sheet so that we don't have to use their hexidecimal names. The above include file contains "pragma directives" since it was designed for C and C++ programming. If you get tired of seeing the assembler spit out "ignoring pragma directive" complaints just go into the file and delete or comment out all the lines beginning with #pragma

Okay, now that you have your microcontroller ready, your assembler ready, and your programmer ready, we can write our first program.

Step 3: Hello World

The goal of this first tutorial is to build the standard first program one writes when learning any new language or exploring any new electronics platform. "Hello World!." In our case we simply want to write an assembly language program, assemble it, and upload it to our microcontroller. The program will cause an LED to turn on. Causing an LED to "blink" like they do for the normal Arduino hello world program is actually a much more complicated program in assembly language and so we won't do that just yet. We are going to write the simplest "bare bones" code with minimal unnecessary fluff.

First connect an LED from PB5 (see the pinout diagram) which is also called Digital Out 13 on an arduino, to a 220 ohm resistor, then to GND. I.e.

PB5 ----> LED ----> R(220 ohm) ----> GND

Now to write the program. Open up your favorite text editor and create a file called "hello.asm"

;hello.asm
;  turns on an LED which is connected to PB5 (digital out 13)

.include "./m328Pdef.inc"

	ldi r16,0b00100000
	out DDRB,r16
	out PortB,r16
Start:
	rjmp Start

The above is the code. We will go through it line-by-line in a minute, but first lets make sure we can get it working on your device.

After you have created the file, then in a terminal you assemble it as follows:

avra hello.asm

this will assemble your code and create a file called hello.hex which we can upload it as follows:

avrdude -p m328p -c stk500v1 -b 57600 -P /dev/ttyUSB0 -U flash:w:hello.hex

if you are using a breadboard arduino you will have to push the reset button on the breadboard arduino just before you execute the above command. Note that you may also have to add a sudo in front or execute it as root. Also note that on some arduino's (like the Arduino UNO) you will probably have to change the bitrate to -b 115200 and the port -P /dev/ttyACM0 (if you get an error from avrdude about an invalid device signature just add a -F to the command)

If everything has worked as it should you will now have an LED lit up..... "Hello World!"

Step 4: Hello.asm Line-by-line

To finish this introductory tutorial we will go through the hello.asm program line-by-line to see how it works.

;hello.asm
;  turns on an LED which is connected to PB5 (digital out 13)

Everything after a semicolon is ignored by the assembler and hence these first two lines are simply "comments" explaining what the program does.

.include "./m328Pdef.inc"

This line tells the assembler to include the m328Pdef.inc file which you downloaded. You may want to put this in a directory of similar include files and then change the above line to point to it there.

ldi r16, 0b00100000

ldi stands for "load immediate" and tells the assembler to take a working register, r16 in this case, and load a binary number into it, 0b00100000 in this case. The 0b in front says that our number is in binary. If we wanted we could have chosen another base, such as hexidecimal. In that case our number would have been 0x20 which is hexidecimal for 0b00100000. Or we could have used 32 which is base 10 decimal for the same number.

Exercise 1: Try changing the number in the line above to hexidecimal and then to decimal in your code and verify that it still works in each case.

Using binary is simplest though because of the way Ports and Registers work. We will discuss the ports and registers of the atmega328p in more detail in future tutorials but for now I'll just state that we are using r16 as our "working register" meaning that we are just going to use it as a variable that we store numbers in. A "register" is a set of 8 bits. Meaning 8 spots that can either be 0 or 1 (`off' or `on'). When we load the binary number 0b00100000 into the register using the above line we have simply stored that number in the register r16.

out DDRB,r16

This line tells the compiler to copy the contents of the register r16 into the DDRB register. DDRB stands for "Data Direction Register B" and it sets up the "pins" on PortB. On the pinout map for the 328p you can see that there are 8 pins labeled PB0, PB1, ... , PB7. These pins represent the "bits" of "PortB" and when we load the binary number 00100000 into the DDRB register we are saying that we want PB0, PB1, PB2, PB3, PB4, PB6, and PB7 set as INPUT pins since they have 0's in them, and PB5 is set as an OUTPUT pin since we put a 1 in that spot.

out PortB,r16

Now that we have fixed the directions of the pins we can now set the voltages on them. The above line copies the same binary number from our storage register r16 to PortB. This sets all of the pins to 0 volts except pin PB5 to HIGH which is 5 volts.

Exercise 2: Take a digital multimeter, plug the black lead into ground (GND) and then tested each of the pins PB0 through PB7 with the red lead. Are the voltages on each of the pins exactly those corresponding to putting 0b00100000 in PortB? If there are any that aren't, why do you think that is? (see the pin map)
Start:
   rjmp Start

Finally, the first line above is a "label" which labels a spot in the code. In this case labelling that spot as "Start". The second line says "relative jump to the label Start." The net result is that the computer is placed into an infinite loop that just keeps cycling back to Start. We need this because we cannot have the program just end, or fall off a cliff, the program has to just keep running in order for the light to stay lit.

Exercise 3: Remove the above two lines from your code so that the program falls off a cliff. What happens? You should see something that looks like the traditional "blink" program used by Arduino as their "hello world!". Why do you think it acts this way? (Think about what must happen when the program falls off a cliff...)

Step 5: Conclusion

If you have gotten this far then congratulations! You are now able write assembly code, assemble it, and load it onto your microcontroller.

In this tutorial you have learned how to use the following commands:

ldi hregister, numberloads a number (0-255) into a upper half register (16-31)

out ioregister, registercopies a number from a working register to an I/O register

rjmp labeljumps to the line of the program labeled by "label" (which cannot be further than 204 instructions away -- i.e. relative jump)

Now that these basics are out of the way, we can continue to write more interesting code and more interesting circuits and devices without having to discuss the mechanics of compiling and uploading.

I hope you have enjoyed this introductory tutorial. In the next tutorial we will add another circuit component (a button) and expand our code to include input ports and decisions.

Comments

author
acheide (author)2014-10-25

Thanks. Do you know if there is an include file for the at90USB162? I'd like to try this.

author
1o_o7 (author)acheide2014-10-26

There isn't one that I can find. However, if you have some spare time you should write one! Here is the way to do it. Use my m328Pdef.inc file as a template and change the name to correspond to your chip. Then go to the datasheet summary file for the at90usb162 here:

http://www.atmel.com/Images/7707S.pdf

starting with section 4 on page 8 you will find the Register summary. Now you can go through the various sections in the include file and change the hex addresses for the various register names and bits.

Next you can go to the full data sheet here:

http://www.atmel.com/Images/doc7707.pdf

and go through each of the sections and map the names to the bit locations. As an examle of what I mean, say you are on the section of the include file called

; PRR - Power Reduction Register

then you would start on page 43 (section 8.6) in the full data sheet. You will notice that the at90USB162 has two power reduction registers PRR0 and PRR1 whereas the ATmega328p only has one called PRR. So you will have to change that section of the include file accordingly and have two sections instead of one. Essentially you just go through each register and equate the name they give to each bit with the number of the bit. So, for example, I would have a line under the PRR1 section that would read:

.equ PRUSART1 = 0 ; Power reduction USART1

Which comes straight from section 8.6.2 on page 44 of the data sheet. You get the idea? I know it is a bit tedious, but then you can use avra with your chip for these tutorials. Also you will know all the in's and out's of your chip by the time you are done.

author
vasx (author)2017-09-13

Hi!

Thanks for this tutorial!

At this moment I have no linux, so I tried it on Windows 10.

The only difference is, you have to take the AVR-Assembler avrasm2.exe + avrdude.exe

avrasm2 needs the option -fI to produce a hex-File

The assemler from the avr-gnu-toolchain (avr-as.exe) does not work, because it supports another assembly syntax.

For all who are interested, this is my Batch-File
rem *** buildhex.bat ***
@echo off
echo Assemblieren
avrasm2 -fI led_on.asm
avrdude -p atmega328p -c arduino -P com3 -b 115200 -D -U flash:w:led_on.hex:i
echo Fertig
pause

author
1o_o7 (author)vasx2017-09-13

Nice Work!!

author
YiH5 (author)2017-01-06

Hi there, notice that when use avrdude to upload the program, you specified the -c option(programmer type) to be stk500v1, but I can find any description about actually using this stk500 programmer, so why is that? thank you!(I've seen other tutorials use -c arduino instead)

author
LucaS75 (author)2016-04-06

Hi, thanks for this instructable!

I am having trouble compiling AVRA (in Arch Linux). It seems that there is something wrong with the Makefile, but I am not sure. The whole thing is confusing, as the INSTALL file says to install one way, whereas other websites say to install other ways....

author
BenW110 (author)LucaS752017-01-06

hello, I was wondering if you ever managed to resolve this, I am also having problems compiling Avra, I got 1.2.3 installed fine but then found it used a different way of referencing what board you're using and the m328Pdef.inc file would not work on its own.

1.3.0 just has an error in the when I run ./Build because it seems a directory is not created properly

author
Razgud (author)2016-03-28

Just what I was looking for; thank you so much! This is all very new to me and I am having trouble with the AVRA compiling step. I get 4 unknown mnemonic/macro errors, one for each #ifndef, #define, #pragma, and #endif, and one unknown device: ATmega328p from the m328pdef.inc file. Any suggestions?

Here is my hello.asm file

.include "C:\Users\Renaud\Documents\Arduino\AVRA\includes\m328Pdef.inc"

ldi r16, 0b0010000

out DDRB,r16

out PortB,r16

Start:

rjmp Start

author
1o_o7 (author)Razgud2016-03-29

I talked about this in step two.
The inc file is designed so that C compilers can also read it. Either comment out those lines or just delete them. Also make sure your device is spelled correctly. Caps too. Or you will get an unknown device error.

author
tym3k (author)2016-02-14

how to install avra on linux? and is it also compatible with os x?

author
anydocumentary (author)2015-08-04

merci

author
dalendaa (author)2015-04-15

slt je suis terminale et mon projet un suiveur photovoltaique bi axiele mon probleme et le programme arduino pour 1 moteur pas à pas unipolaire tourne 9 h ( 7h à 16h) et puis retoure à l'etat initiale est attendre 14 h (16h à 7h ) et merciiiiii bcp

author
1o_o7 (author)dalendaa2015-05-10

merci aussi! pas de problem. C'est mon pleasure.

author
Tachyon (author)2014-12-19

This is really awesome and I can't wait for the rest of the series! Nice work.

I do have a question. Given the audience, I'm betting that a lot of people would also be interested in how to integrate AVR assembly routines into larger standard Arduino sketches. In other words, use the Arduino IDE and make a sketch for most of the program, but hand code in AVR for key routines that need to be smaller, faster, better, stronger. Then integrate the whole thing for upload to the AVR/Arduino.

I know this is a pretty common thing to do on other platforms and I assume it's also possible on the AVR/Arduino. Any thoughts on including a chapter on how to do that?

Anyway, thanks again. Keep up the good work.

author
1o_o7 (author)Tachyon2014-12-19

Thanks! Here is a link to the 10 that I have completed up to now:

https://www.instructables.com/id/Command-Line-AVR-Tutorials/

author
heyitsme (author)2014-11-26

Can you upload the include file "m328Pdef.inc" again? When I attempt to download it says it isn't available. Thanks.

author
1o_o7 (author)heyitsme2014-11-27

I have attached it to the step about downloading the assembler.

author
kshowell (author)2014-11-25

Awesome ible .... Thank You

author
smilesfromnowhere (author)2014-11-25

Thanks for taking the time to write this!

I loved your tutorial! It's the first one I've found regarding Arduinos and assembler. I can't wait to read the rest of the series!

I'm not sure I'll be able to make use of it right away but it's great to have the knowledge.

author
1o_o7 (author)smilesfromnowhere2014-11-25

Thanks! I am happy to see that there are people who are interested! Assembly language is a lot of fun

author
mirycia (author)2014-11-02

yes i like

bcouse to stand this every need go to university

tnks


author
renaissanceman (author)2014-10-31

Thanks ! Finally a simple and good tutorial on assembler and AVR, I was waiting for this !

Hope you go on posting more tutorials.

Thanks again !

author
SparkySolar (author)2014-10-25

Thank you for your nice Instructable.

Rima

About This Instructable

74,919views

101favorites

License:

Bio: I am interested in a wide range of things as shown in my list of interests. Almost anything creative is fun and worth trying.
More by 1o_o7:Backyard FenceSteel Whiteboard StandArchitect Style Desk Lamp Base
Add instructable to: