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

Comments

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

Things to be written on top

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

Things that should be done at program start

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

Structuring of program code

avr_head opening screen 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.

avr_head file requester You are now asked to navigate to its respective include-file tn13def.inc. Show the program the way where the header file is located.

avr_head entries 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