Path:
Home =>
AVR-english =>
Beginner => Structure
Structure of AVR-assembler-programs
This page shows the basic structure of an assembler program. These structures are
typical for AVR assembler. This text discusses
The most helpful things in assembler programs are comments. If you need to understand
older code that you wrote, sometimes years after, you will be happy about having some or
more hints what is going on in that line. If you like to keep your ideas secret, and to
hide them against yourself and others: don't use comments.
A comment starts with a semicolon. All that follows behind on the same line will be ignored
by the compiler. If you need to write a comment over multiple lines, start each line with a
semicolon. So each assembler program should start like that:
;
; Click.asm, Program to switch a relais on and off each two seconds
; Written by G.Schmidt, last change: 7.10.2001
;
Put comments around all parts of the program, be it a complete subroutine or a table.
Within the comment mention the special nature of the routine, pre-conditions necessary to
call or run the routine. Also mention the results of the subroutine in case you later will
have to find errors or to extend the routine later.
Single line comments are defined by adding a semicolon behind the command on the line. Like
this:
LDI R16,0x0A ; Here something is loaded
MOV R17,R16 ; and copied somewhere else
To the top of that page
Purpose and function of the program, the author, version information and other comments
on top of the program should be followed by the processor type that the program is written
for, and by relevant constants and by a list with the register names.
The processor type is especially important. Programs do not run on other chip types without
changes. The instructions are not completely understood by all types, each type has typical
amounts of EEPROM and internal SRAM. All these special features are included in a header file
that is named xxxxdef.inc, with xxxx being the chip type, e.g. 2313, tn2323, or m8515. These files
are available by ATMEL. It is good style to
include this file at the beginning of each program. This is done like that:
.NOLIST ; Don't list the following in the list file
.INCLUDE "m8515def.inc" ; Import of the file
.LIST ; Switch list on again
The path, where this file can be found, is only necessary if you don't work with ATMEL's
Studio. Of course you have to include the correct path to
fit to your place where these
files are located.
During assembling, the outpu of a list file listing the results is switched on by default.
Having listing ob might result in very long list file (*.lst) if you include the header
file. The directive .NOLIST turns off this listing for a while, LIST turns it on again.
Let's have a short look at the header file. First these files define the processor type:
.DEVICE ATMEGA8515 ; The target device type
The directive .DEVICE advices the assembler to check all instructions if these are
available for that AVR type. It results in an error message, if you use code sequences that
are not defined for this type of processor. You don't need to define this within your
program as this is already defined within the header file.
The header file also defines the registers XH, XL, YH, YL, ZH and ZL. These are needed if
you use the 16-bit-pointers X, Y or Z to access the higher or lower byte of the pointer
separately. All port locations are also defined in the header file, so PORTB translates to
a hex number where this port is located on the defined device. The port's names are
defined with the same names that are used in the data sheets for the respective processor
type. This also applies to single bits in the ports. Read access to port B, Bit 3, can be
done using its bit name PINB3, as defined in the data sheet.
In other words: if you forget to include the header file you will run into a lot of error
messages during assembly. The resulting error messages are in some cases not necessarily
related to the missing header file.
Others things that should be on top of your programs are the register definitions you work
with,e.g.:
.DEF mpr = R16 ; Define a new name for register R16
This has the advantage of having a complete list of registers, and to see which registers are
still available and unused. Renaming registers avoids conflicts in the use of these registers
and the names are easier to remember.
Furtheron we define the constants on top of the source file, especially those that have a
relevant role in different parts of the program. Such a constant would, e.g., be the Xtal
frequency that the program is adjusted for, if you use the serial interface on board. With
.EQU fq = 4000000 ; XTal frequency definition
at the beginning of the source code you immediately see for which clock you wrote the program.
Very much easier than searching for this information within 1482 lines of source code.
To the top of that page
After you have done the header, the program code should start. At the beginning of the code the
reset- and interrupt-vectors (their function see in the JUMP
section) are placed. As these require relative jumps, we should place the respective interrupt
service routines right behind. In case of ATmega types with larger flash memory JUMP instructions
can be used here, so be careful here. There is some space left then for other subroutines, before we
place the main program.
The main program always starts with initialisation of the stack pointer, setting registers to
default values, and the init of the hardware components used. The following code is specfic
for the program.
To the top of that page
The described standardized structure is included in a program written for Windows Operating
Systems, which can be downloaded here. Unzip the executable file, and simply run it. It shows this:
Here you can choose ATtiny by clicking on it,
and then select ATtiny13 in the dropdown field AVR-Type.
You are now asked to navigate to its respective include-file tn13def.inc. Show the program the way
where the header file is located.
Here you can enter your desired multi purpose register, the output configuration on ports A and B,
if available, and if you want to use interrupts.
Click Update to fill the window with your code frame. Click CopyToClipboard, if you
want to paste this into your code editor, or WriteToFile to write this to an assembler code
file instead.
If you don't know what it is for and what to do, press the Help button.
This produces the following code (download the assembler file here):
;
; ********************************************
; * [Add Project title here] *
; * [Add more info on software version here] *
; * (C)20xx by [Add Copyright Info here] *
; ********************************************
;
; Included header file for target AVR type
.NOLIST
.INCLUDE "tn13def.inc" ; Header for ATTINY13
.LIST
;
; ============================================
; H A R D W A R E I N F O R M A T I O N
; ============================================
;
; [Add all hardware information here]
;
; ============================================
; P O R T S A N D P I N S
; ============================================
;
; [Add names for hardware ports and pins here]
; Format: .EQU Controlportout = PORTA
; .EQU Controlportin = PINA
; .EQU LedOutputPin = PORTA2
;
; ============================================
; C O N S T A N T S T O C H A N G E
; ============================================
;
; [Add all constants here that can be subject
; to change by the user]
; Format: .EQU const = $ABCD
;
; ============================================
; F I X + D E R I V E D C O N S T A N T S
; ============================================
;
; [Add all constants here that are not subject
; to change or calculated from constants]
; Format: .EQU const = $ABCD
;
; ============================================
; R E G I S T E R D E F I N I T I O N S
; ============================================
;
; [Add all register names here, include info on
; all used registers without specific names]
; Format: .DEF rmp = R16
.DEF rmp = R16 ; Multipurpose register
;
; ============================================
; S R A M D E F I N I T I O N S
; ============================================
;
.DSEG
.ORG 0X0060
; Format: Label: .BYTE N ; reserve N Bytes from Label:
;
; ============================================
; R E S E T A N D I N T V E C T O R S
; ============================================
;
.CSEG
.ORG $0000
rjmp Main ; Reset vector
reti ; Int vector 1
reti ; Int vector 2
reti ; Int vector 3
reti ; Int vector 4
reti ; Int vector 5
reti ; Int vector 6
reti ; Int vector 7
reti ; Int vector 8
reti ; Int vector 9
;
; ============================================
; I N T E R R U P T S E R V I C E S
; ============================================
;
; [Add all interrupt service routines here]
;
; ============================================
; M A I N P R O G R A M I N I T
; ============================================
;
Main:
; Init stack
ldi rmp, LOW(RAMEND) ; Init LSB stack
out SPL,rmp
; Init Port B
ldi rmp,(1<<DDB2)|(1<<DDB1)|(1<<DDB0) ; Direction of Port B
out DDRB,rmp
; [Add all other init routines here]
ldi rmp,1<<SE ; enable sleep
out MCUCR,rmp
sei
;
; ============================================
; P R O G R A M L O O P
; ============================================
;
Loop:
sleep ; go to sleep
nop ; dummy for wake up
rjmp loop ; go back to loop
;
; End of source code
;
To the top of that page
©2002-2009 by http://www.avr-asm-tutorial.net