Programming techniques in AVR Assembler language

Assembler-Directives

Assembler-Directives control the assembler, they don't create any own code. The leading dot must be in column 1 of the line.
SegmentDirectiveDescription
Header .DEVICEDefines the type of the target processor and the applicable set of instructions (illegal instructions for that type trigger an error message, syntax: .DEVICE AT90S8515)
.DEFDefines a synonym for a register (e.g. .DEF MyReg = R16)
.EQUDefines a symbol and sets its value (later changes of this value remain possible, syntax: .EQU test = 1234567, internal storage of the value is 4-byte- Integer)
.SETFixes the value of a symbole (later redefinition is not possible)
.INCLUDEIncludes a file and assembles its content, just like its content would be part of the calling file (typical e.g. including the header file: .INCLUDE "C:\avrtools\appnotes\8515def.inc")
Code .CSEGStart of the code segment (all that follows is assembled to the code segment and will go to the program space)
.DBInserts one or more constant bytes in the code segment (could be numbers from 0..255, an ASCII-character like 'c', a string like 'abcde' or a combination like 1,2,3,'abc'. The number of inserted bytes must be even, otherwise an additional zero byte will be inserted by the assembler.)
.DWInsert a binary word in the code segment (e.g. produces a table within the code)
.LISTMACMacros will be listed in the .LST-file. (Default is that macros are not listed)
.MACROBeginning of a macro (no code will be produced, call of the macro later produces code, syntax: .MACRO macroname parameters, calling by: macroname parameters)
.ENDMACROEnd of the macro
EEPROM .ESEGAssemble to the EEPROM-segment (the code produced will go to the EEPROM section, the code produces an .EEP-file)
.DBInserts one or more constant bytes in the EEPROM segment (could be numbers from 0..255, an ASCII-character like 'c', a string like 'abcde' or a combination like 1,2,3,'abc'.)
.DWInserts a binary word to the EEPROM segment (the lower byte goes to the next adress, the higher byte follows on the incremented address)
SRAM .DSEGAssemble to the data segment (here only BYTE directives and labels are valid, during assembly only the labels are used)
.BYTEReserves one or more bytes space in the data segment (only used to produce correct labels, does not insert any values!)
Everywhere .ORGDefines the address within the respective segment, where the assembler assembles to (e.g. .ORG 0x0000)
.LISTSwitches the listing to the .LST-file on (the assembled code will be listet in a readable text file .LST)
.NOLISTSwitches the output to the .LST-file off, suppresses listing.
.INCLUDEInserts the content of another source code file, as if its content would be part of the source file (typical e.g. including the header file: .INCLUDE "C:\avrtools\appnotes\8515def.inc")
.EXITEnd of the assembler-source code (stops the assembling process)

Advanced Assembler Directives

Advanced Assembler Directives allow Please note again, that these directives are only meaningful for the assembler and during the assembly process, the assembled program itself, as loaded into the AVR, does not have any conditions!

The Syntax of these directives look like this:

Assembler expressions

Expressions are needed to calculate within the assembler source code. These expressions are calculated during the assembly process, they don't produce any execuatble code.
TypeSymbolDescription
Calculation +Addition
-Subtraction or negative number
*Multiplication
/Integer-Division
Binary &Bitwise AND
|Bitwise OR
^Bitwise Exclusive-OR
~Bitwise NOT
<<Shift left
>>Shift right
Logical <Less than
>Greater than
==Equal
<=Less or equal
>=Graeter or equal
!=Unequal
&&AND
||OR
!NOT

Shift left

Some hints for Shift-Left (<<): the following code lines are used very often:

  ldi r16,1<<ADSC
  out ADCSRA,r16


In this example, ADSC is a certain bit in Port ADCSRA, both defined somewhere in the header file for this AVR. In that case it starts an AD conversion (in most cases bit 6), if written to the Port ADCSRA. The expression with << causes that a One (binary 0000.0001) is shifted left six times and gets to 0100.0000. This number is written to the port ADCSRA and causes an AD conversion start.

Using this notation has the advantage, that the exact location of the ADSC bit in the ADCSRA port doesn't have to be known exactly. Its location can even change from one header file to another, without changing the source code. Compared to the formulation

  ldi r16,0b01000000
  out 0x06,r16


the transparency is much higher. And not having to count binary zeroes is another advantage.

What if other bits in the same port have to be set to one simultanously, for example the Interrupt Enable bit ADIE (bit 3)? Then just OR these bitwise:

  ldi r16,(1<<ADSC) | (1<<ADIE)
  out ADCSRA,r16


The brackets set the exact calculation priorities.