Macros in AVR Assembler

Macros are a good way to make code more readable, for example if it contains code that is often reused or if a lot of 16-bit calculations are done.

Macros in AVR assembler can be defined everywhere in the code as long as they're not used at a location before the macro definition. They can take arguments which are replaced during assembly and can't be changed during runtime. The arguments can only be used in the form @0 or @1 (while 0 or 1 are the argument numbers startnig from 0). The arguments can be almost everything the assembler can handle: integers, characters, registers, I/O addresses, 16 or 32-bit integers, binary expressions...

This works:

.macro ldi16
 
ldi @0, low(@2)
ldi @1, high(@2)
.endmacro
 
ldi16 r16, r17, 1024
; lets make a macro for loading two registers
; with a 16-bit immediate
; load the first argument (@0) with the low byte of @2
; same with second arg (@1) and high byte of @2
; end the macro definition
 
; r16 = 0x00 r17 = 0x04

While this does not:

ldi16 r16, r17, 1024

.macro ldi16
ldi @0, low(@2)
ldi @1, high(@2)
.endmacro
; r16 = 0x00 r17 = 0x04
 
 
 
 
 

Above, I wrote that arguments are replaced during assembly. The following should make it clear:

ldi16 r16, r17, 1024
; is assembled to:
ldi r16, 0
ldi r17, 0x04
; in the macro, this was: 
 
; ldi @0, low(@2)
; ldi @1, high(@2)

As I said, macros can also be used to replace 16-bit calculations. This is one example (along with ldi16):

.macro addi
subi @0, -(@1)
.endmacro
 
.macro addi16
subi @0, low(-@2)
sbci @1, high(-@2)
.endmacro
; This is the "Add Immediate to register" instruction we all
; missed in the instruction set!
 
;Now here's the 16-bit version:
 
 
 
 

Macros can of course be more complex, take more arguments and crash the assembler. If too many macros are defined in one file, the last ones can't be found. I've had this with more than 7 I think. Just split them into more files, that helps sometimes. Or just don't be that lazy and write the code yourself...