AVR Assembler Makros: Unterschied zwischen den Versionen
K (Textersetzung - „</avrasm>“ durch „</syntaxhighlight>“) |
Jofe (Diskussion | Beiträge) K (Syntaxhighlight repariert (avrasm→asm), Kategorisierung ans Ende verschoben, Kleinigkeiten) |
||
(3 dazwischenliegende Versionen von 3 Benutzern werden nicht angezeigt) | |||
Zeile 1: | Zeile 1: | ||
[[ | Hier entsteht eine Sammlung von verschiedenen nützlichen [[Makro]]s für den [[AVR]]-[[Assembler]]. | ||
=== 16-Bit-Konstante in Z-Pointer laden === | |||
<syntaxhighlight lang="asm"> | |||
<syntaxhighlight lang=" | |||
.MACRO SetZPtr ;(Adresse) | .MACRO SetZPtr ;(Adresse) | ||
ldi ZL, LOW(@0) | ldi ZL, LOW(@0) | ||
Zeile 13: | Zeile 11: | ||
Natürlich auch möglich mit X- und Y-Pointer. | Natürlich auch möglich mit X- und Y-Pointer. | ||
==Speicher== | ==Speicher== | ||
=== 2 Register ohne Zwischenspeicher vertauschen === | === 2 Register ohne Zwischenspeicher vertauschen === | ||
<syntaxhighlight lang=" | <syntaxhighlight lang="asm"> | ||
.MACRO SWAP ;(a, b) | .MACRO SWAP ;(a, b) | ||
eor @0, @1 | eor @0, @1 | ||
Zeile 29: | Zeile 26: | ||
=== Konstante addieren === | === Konstante addieren === | ||
<syntaxhighlight lang=" | <syntaxhighlight lang="asm"> | ||
.MACRO ADDI ;(a, k) | .MACRO ADDI ;(a, k) | ||
subi @0, -(@1) | subi @0, -(@1) | ||
Zeile 37: | Zeile 34: | ||
=== Konstante addieren (16 Bit) === | === Konstante addieren (16 Bit) === | ||
<syntaxhighlight lang=" | <syntaxhighlight lang="asm"> | ||
.MACRO ADDIW ;(RdL:RdH, k) | .MACRO ADDIW ;(RdL:RdH, k) | ||
subi @0L, LOW(-@1) | subi @0L, LOW(-@1) | ||
sbci @0H, HIGH(-@1) | sbci @0H, HIGH(-@1) | ||
.ENDMACRO | .ENDMACRO | ||
</syntaxhighlight> | </syntaxhighlight> | ||
oder (sinnlos) | oder (sinnlos) | ||
<syntaxhighlight lang=" | <syntaxhighlight lang="asm"> | ||
.MACRO ADDIW ;(Rd, k) | .MACRO ADDIW ;(Rd, k) | ||
sbiw @0, (-@1) | sbiw @0, (-@1) | ||
Zeile 50: | Zeile 47: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
DAS geht auch ohne Makro | DAS geht auch ohne Makro | ||
<syntaxhighlight lang=" | <syntaxhighlight lang="asm"> | ||
adiw a, b | adiw a, b | ||
</syntaxhighlight> | </syntaxhighlight> | ||
SBIW und ADIW sind aber beide auf die Register(paare) R24, R26, R28, R30 beschränkt UND nehmen nur Zahlen | SBIW und ADIW sind aber beide auf die Register(paare) R24, R26, R28, R30 beschränkt UND nehmen nur Zahlen <64 an. | ||
==I/O== | ==I/O== | ||
Bei | Bei größeren und neueren AVRs sind etliche I/O-Register nicht mit IN/OUT-Befehlen ansprechbar. LDS/STS erreicht zwar alle, ist aber bei kleineren oder älteren ineffizient. | ||
=== Port lesen === | === Port lesen === | ||
<syntaxhighlight lang=" | <syntaxhighlight lang="asm"> | ||
.macro input | .macro input | ||
.if @1 < 0x40 | .if @1 < 0x40 | ||
Zeile 73: | Zeile 70: | ||
=== Port schreiben === | === Port schreiben === | ||
<syntaxhighlight lang=" | <syntaxhighlight lang="asm"> | ||
.macro output | .macro output | ||
.if @0 < 0x40 | .if @0 < 0x40 | ||
Zeile 89: | Zeile 86: | ||
Branch if Bit in I/O-Register is Set | Branch if Bit in I/O-Register is Set | ||
<syntaxhighlight lang=" | <syntaxhighlight lang="asm"> | ||
.macro bbis ;port,bit,target | .macro bbis ;port,bit,target | ||
.if @0 < 0x20 | .if @0 < 0x20 | ||
Zeile 107: | Zeile 104: | ||
Branch if Bit in I/O-Register is Cleared | Branch if Bit in I/O-Register is Cleared | ||
<syntaxhighlight lang=" | <syntaxhighlight lang="asm"> | ||
.macro bbic ;port,bit,target | .macro bbic ;port,bit,target | ||
.if @0 < 0x20 | .if @0 < 0x20 | ||
Zeile 123: | Zeile 120: | ||
.endm | .endm | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== Location Pointer == | == Location Pointer == | ||
=== Align === | === Align === | ||
Manchmal ist es notwendig, Tabellen oder Puffer auf eine bestimmte Byte- oder Wortgrenze zu bringen, z.B. um beim Zugriff einen Überlauf des Index in das obere Adressbyte zu verhindern. | Manchmal ist es notwendig, Tabellen oder Puffer auf eine bestimmte Byte- oder Wortgrenze zu bringen, z.B. um beim Zugriff einen Überlauf des Index in das obere Adressbyte zu verhindern. | ||
<syntaxhighlight lang=" | <syntaxhighlight lang="asm"> | ||
.macro align ;align to 1<<@0 | .macro align ;align to 1<<@0 | ||
alignfromhere: | alignfromhere: | ||
Zeile 159: | Zeile 157: | ||
Bereits verbrauchte Takte werden aus den Instruktionen errechnet, die zwischen | Bereits verbrauchte Takte werden aus den Instruktionen errechnet, die zwischen | ||
den zu verzögernden Ereignissen liegen. Beispiel: | den zu verzögernden Ereignissen liegen. Beispiel: | ||
<syntaxhighlight lang=" | <syntaxhighlight lang="asm"> | ||
sbi porta,0 | sbi porta,0 | ||
wait_ns 1000,2,R16 | wait_ns 1000,2,R16 | ||
Zeile 175: | Zeile 173: | ||
erreicht, allerdings nimmt dann auch die Genauigkeit der Verzögerung ab (exakt bis +1 Takt). | erreicht, allerdings nimmt dann auch die Genauigkeit der Verzögerung ab (exakt bis +1 Takt). | ||
<syntaxhighlight lang=" | <syntaxhighlight lang="asm"> | ||
; | ; | ||
; wait_ns waittime in ns , cyles already used , waitcount register | ; wait_ns waittime in ns , cyles already used , waitcount register | ||
; | ; | ||
; cycles already used will be subtracted from the delay | ; cycles already used will be subtracted from the delay | ||
Zeile 192: | Zeile 190: | ||
.else | .else | ||
.if (cycles > 6) | .if (cycles > 6) | ||
.set loop_cycles = (cycles / 3) | .set loop_cycles = (cycles / 3) | ||
ldi @2,loop_cycles | ldi @2,loop_cycles | ||
dec @2 | dec @2 | ||
Zeile 222: | Zeile 220: | ||
Einige Beispiele: | Einige Beispiele: | ||
Verschachteltes If-Then-Else<syntaxhighlight lang=" | Verschachteltes If-Then-Else<syntaxhighlight lang="asm"> | ||
cpi r16,'a' | cpi r16,'a' | ||
ifeq a_chr | ifeq a_chr | ||
Zeile 242: | Zeile 240: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Mehrere und/oder verknüpfte Bedingungen<syntaxhighlight lang=" | Mehrere und/oder verknüpfte Bedingungen<syntaxhighlight lang="asm"> | ||
cpi zh,high(end_buffer) | cpi zh,high(end_buffer) | ||
ifeq_and end_buffer_reached | ifeq_and end_buffer_reached | ||
Zeile 253: | Zeile 251: | ||
ld r0,z+ ;read buffer | ld r0,z+ ;read buffer | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Das Gleiche als Do-Loop<syntaxhighlight lang=" | |||
Das Gleiche als Do-Loop<syntaxhighlight lang="asm"> | |||
; reading a buffer until end | ; reading a buffer until end | ||
; similar to: for z = buffer to end_buffer | ; similar to: for z = buffer to end_buffer | ||
Zeile 268: | Zeile 266: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Mehr Beispiele und das SAM-include als [[Media:sam.zip|Download.]] | Mehr Beispiele und das SAM-include als [[Media:sam.zip|Download]]. | ||
[[Kategorie:AVR]] |
Aktuelle Version vom 25. April 2023, 19:28 Uhr
Hier entsteht eine Sammlung von verschiedenen nützlichen Makros für den AVR-Assembler.
16-Bit-Konstante in Z-Pointer laden
.MACRO SetZPtr ;(Adresse)
ldi ZL, LOW(@0)
ldi ZH, HIGH(@0)
.ENDMACRO
Natürlich auch möglich mit X- und Y-Pointer.
Speicher
2 Register ohne Zwischenspeicher vertauschen
.MACRO SWAP ;(a, b)
eor @0, @1
eor @1, @0
eor @0, @1
.ENDMACRO
Arithmetik
Konstante addieren
.MACRO ADDI ;(a, k)
subi @0, -(@1)
.ENDMACRO
Konstante addieren (16 Bit)
.MACRO ADDIW ;(RdL:RdH, k)
subi @0L, LOW(-@1)
sbci @0H, HIGH(-@1)
.ENDMACRO
oder (sinnlos)
.MACRO ADDIW ;(Rd, k)
sbiw @0, (-@1)
.ENDMACRO
DAS geht auch ohne Makro
adiw a, b
SBIW und ADIW sind aber beide auf die Register(paare) R24, R26, R28, R30 beschränkt UND nehmen nur Zahlen <64 an.
I/O
Bei größeren und neueren AVRs sind etliche I/O-Register nicht mit IN/OUT-Befehlen ansprechbar. LDS/STS erreicht zwar alle, ist aber bei kleineren oder älteren ineffizient.
Port lesen
.macro input
.if @1 < 0x40
in @0, @1
.else
lds @0, @1
.endif
.endm
Port schreiben
.macro output
.if @0 < 0x40
out @0, @1
.else
sts @0, @1
.endif
.endm
Portbit abfragen
Abfrage eines Bits eines I/O-Ports und Sprung wenn 1/0. Überschreibt u.U. ZL.
Branch if Bit in I/O-Register is Set
.macro bbis ;port,bit,target
.if @0 < 0x20
sbic @0, @1
rjmp @2
.elif @0 < 0x40
in zl, @0
sbrc zl, @1
rjmp @2
.else
lds zl, @0
sbrc zl, @1
rjmp @2
.endif
.endm
Branch if Bit in I/O-Register is Cleared
.macro bbic ;port,bit,target
.if @0 < 0x20
sbis @0, @1
rjmp @2
.elif @0 < 0x40
in zl, @0
sbrs zl, @1
rjmp @2
.else
lds zl, @0
sbrs zl, @1
rjmp @2
.endif
.endm
Location Pointer
Align
Manchmal ist es notwendig, Tabellen oder Puffer auf eine bestimmte Byte- oder Wortgrenze zu bringen, z.B. um beim Zugriff einen Überlauf des Index in das obere Adressbyte zu verhindern.
.macro align ;align to 1<<@0
alignfromhere:
.if (alignfromhere & ((1<<@0)-1)) ;if not already aligned
.org (alignfromhere & (0xffff<<@0)) + (1<<@0)
.endif
.endmacro
@0 bezeichnet die Anzahl rechtsbündiger binärer Nullen. Beispiel: align 8 setzt die nächste Adresse auf $xx00. Funktioniert in allen Segmenten.
Delay
Verzögerung um X Nanosekunden
von Klaus2m5
Taktgenaue Verzögerung der Instruktionsausführung durch Angabe der Verzögerungszeit in Nanosekunden. Dabei werden maximal 4 Instruktionen erzeugt. Taktgenau bedeutet, dass auf die nächste volle Anzahl von Takten aufgerundet wird. Beispiel: 75ns bei 20MHZ (50ns Taktzeit) bedeutet eine tatsächliche Verzögerung von 2 Zyklen und entspricht 100ns.
Die Variable Osc_Hz muss der verwendeten Taktquelle angepasst werden und definiert die CPU-Taktfrequenz in Hertz.
wait_ns wird mit folgenden Parametern aufgerufen:
1. Verzögerungszeit in Nanosekunden 2. bereits verbrauchte Takte 3. ein Immediate-Register (R16-R31) als Zähler
Bereits verbrauchte Takte werden aus den Instruktionen errechnet, die zwischen den zu verzögernden Ereignissen liegen. Beispiel:
sbi porta,0
wait_ns 1000,2,R16
cbi porta,0
In diesem Fall besteht die Anzahl der verbrauchten Takte lediglich aus den Instruktionen, die zum Ereignis führen. Am Ende von SBI wird die steigende Flanke, am Ende von CBI die fallende Flanke des Signals erzeugt. Wenn wir also möglichst exakt eine Pulsbreite von einer Mikrosekunde erzeugen wollen, müssen wir die Ausführungszeit von CBI von unserer Wartezeit abziehen. Die Ausführung von CBI liegt vor dem Ereignis!
Wenn die Verzögerungszeit kleiner als die Anzahl bereits verbrauchter Taktzyklen ist, wird keine weitere Verzögerung erzeugt. Die maximale Verzögerung ist 767 Takte entsprechend 38350ns bei 20MHZ. Bei niedrigeren Frequenzen wird eine längere Verzögerung erreicht, allerdings nimmt dann auch die Genauigkeit der Verzögerung ab (exakt bis +1 Takt).
;
; wait_ns waittime in ns , cyles already used , waitcount register
;
; cycles already used will be subtracted from the delay
; the waittime resolution is 1 cycle (delay from exact to +1 cycle)
; the maximum delay at 20MHz (50ns/clock) is 38350ns
; waitcount register must specify an immediate register
;
.set Osc_Hz = 7372800 ;7,3728 MHz (Baudrate xtal)
.set cycle_time_ns = (1000000000 / Osc_Hz) ;clock duration
.macro wait_ns
.set cycles = ((@0 + cycle_time_ns - 1) / cycle_time_ns - @1)
.if (cycles > (255 * 3 + 2))
.error "MACRO wait_ns - too many cycles to burn"
.else
.if (cycles > 6)
.set loop_cycles = (cycles / 3)
ldi @2,loop_cycles
dec @2
brne pc-1
.set cycles = (cycles - (loop_cycles * 3))
.endif
.if (cycles > 0)
.if (cycles & 4)
rjmp pc+1
rjmp pc+1
.endif
.if (cycles & 2)
rjmp pc+1
.endif
.if (cycles & 1)
nop
.endif
.endif
.endif
.endmacro
Strukturierte Programmierung
SAM (Structured Assembly Macros)
von Klaus2m5
SAM unterstützt strukturiertes Programmieren durch If-Then-Else und Do-Loop Makros. Beliebige Verschachtelung und Mehrfachbedingungen sind möglich. Läuft unter aktuellen Versionen von AVRASM2.
Einige Beispiele:
Verschachteltes If-Then-Else
cpi r16,'a'
ifeq a_chr
cpi r17,'b'
ifeq a_and_b
;...a&b
else a_and_b
;...a&-b
end a_and_b
else a_chr
cpi r17,'c'
ifeq c_but_no_a
;...-a&+c
else c_but_no_a
;...-a&c
end c_but_no_a
end a_chr
Mehrere und/oder verknüpfte Bedingungen
cpi zh,high(end_buffer)
ifeq_and end_buffer_reached
cpi zl,low(end_buffer)
ifeq end_buffer_reached
ldi zh,high(buffer) ;wrap buffer
ldi zl,low(buffer)
end end_buffer_reached
ld r0,z+ ;read buffer
Das Gleiche als Do-Loop
; reading a buffer until end
; similar to: for z = buffer to end_buffer
ldi zh,high(buffer) ;init buffer pointer
ldi zl,low(buffer)
do read_buf
ld r0,z+
cpi zh,high(end_buffer)
loopne read_buf
cpi zl,low(end_buffer)
loopne read_buf
Mehr Beispiele und das SAM-include als Download.