Bin gerade weiter dabei einige Fehler zu killen, welche aufgrund des unterschiedlichen Befehlssatzes AVR5(1) und AVR25 zustande kommen.
Der längere Weg ist dieser...
Code: Alles auswählen
{$if defined (ATMega328p)}
procedure TNeoPixel.show; assembler; nostackframe;
label wait, NextBit, NextByte, nop1, nop2, nop3;
asm
push r29 // verwendete Register sichern
push r28 // Y = r28/r29 fnumBytes
push r27 // X = r26/r27 zeigt auf Pixels
push r26 //
push r18 // hi PinMask
push r19 // lo PinMask
push r20 // Bit Zähler
push r21 // aktuell ausgegebenes Byte
push r22 // next
push r30 // Z = r30/r31 zeigt (vorerst) auf self
push r31 // wird nach dem initialisieren gesichert und dann auf die Portadresse umgestellt
push r24 // Das Ergebnis von canShow wird in r24 zurückgegeben
push r25 // canShow verändert r24 und r25, benötigt aber den Zeiger auf self darin
wait:
pop r25
pop r24
push r24
push r25
call canShow
tst r24
breq wait
pop r25
pop r24
movw r30,r24 // self in Z register laden
ldd r28,Z+TNeoPixel.fnumBytes // fnumBytes in r28/r29 = Y Register laden
ldd r29,Z+TNeoPixel.fNumBytes+1
ldd r26,Z+TNeoPixel.fPixels // Zeiger auf fPixels in X Register laden
ldd r27,Z+TNeoPixel.fPixels+1
ldd r22,Z+TNeoPixel.fPinMask
ldd r24,Z+TNeoPixel.fPin // Arduino Pin
ldd r25,Z+TNeoPixel.fPin+1
push r30 // Z Register sichern. Wird von digitalReadPort überschrieben
push r31
call digitalReadPort // Den aktuellen Zustand des Ports auslesen (wird in r24 zurückgeliefert)
pop r31
pop r30
ldd r18,Z+TNeoPixel.fPort // Portadresse zwischenspeichern
ldd r19,Z+TNeoPixel.fPort+1
push r30 // Da wir nach dem senden der Sequenz 300us warten müssen,
push r31 // speichern wir den Inhalt des Z Registers auf dem Stack zwischen
movw r30,r18 // Portadresse in das Z Register laden.
// ab hier kann nicht mehr auf self zugegriffen werden
mov r18,r24 // Aktuellen Portzustand in r18 schreiben
mov r19,r18 // und diesen auch nach lo schreiben
or r18,r22 // Pin Bit setzen (hi)
com r22 // Alle Bits ausser unserem setzen
and r19,r22 // Pin Bit löschen, alles andere so lassen wie es ist
com r22 // unser Bit wieder setzen, alles andere löschen
ldi r20,8 // Bit Zähler
ld r21,X+ // erstes Byte laden und X Register erhöhen
mov r22,r19 // next := lo
cli // Interrupts sperren
NextBit:
st Z,r18 // PORT := hi (T = 0)
sbrc r21,7 // if (Byte and 128) then (T = 2)
mov r22,r18 // next := hi (T = 4)
dec r20 // Bit := Bit - 1 (T = 5)
st Z,r22 // Port := next (T = 7)
mov r22,r19 // next := lo (T = 8)
breq NextByte // if Bit = 0 then NextByte (from dec above)
rol r21 // Rotate Left on Byte (T = 10)
rjmp nop1 // 3 Takte Pause (T = 11)
nop1:
nop // (T = 13)
st Z,r19 // Port := lo (T = 15)
rjmp nop2 // 3 Takte Pause machen
nop2:
nop //
rjmp NextBit // Nächstes Bit ausgeben
NextByte:
ldi r20,8 // Bit := 8
ld r21,X+ // Nächstes Byte von fPixels laden
st Z,r19 // Port := lo
rjmp nop3 // 1 Takt warten
nop3:
sbiw r28,1 // Bytezähler decrementieren
brne NextBit // Nicht Null? nächstes Byte ausgeben
pop r31 // die Adresse von self wieder zurück
pop r30 // holen
sei // Interrupts wieder zulassen
call micros // Aktuellen Microsekundenzählerstand in fEndTime speichern
std Z+TNeoPixel.fEndTime,r22
std Z+TNeoPixel.fEndTime+1,r23
std Z+TNeoPixel.fEndTime+2,r24
std Z+TNeoPixel.fEndTime+3,r25
pop r31 // gesicherte Register wieder herstellen.
pop r30
pop r22
pop r21
pop r20
pop r19
pop r18
pop r26
pop r27
pop r28
pop r29
end;
{$endif}
{$if defined (ATtiny45) of defined (ATtiny85)}
procedure TNeoPixel.show; assembler; nostackframe;
label wait, NextBit, NextByte, nop1, nop2, nop3;
asm
push r29 // verwendete Register sichern
push r28 // Y = r28/r29 fnumBytes
push r27 // X = r26/r27 zeigt auf Pixels
push r26 //
push r18 // hi PinMask
push r19 // lo PinMask
push r20 // Bit Zähler
push r21 // aktuell ausgegebenes Byte
push r22 // next
push r30 // Z = r30/r31 zeigt (vorerst) auf self
push r31 // wird nach dem initialisieren gesichert und dann auf die Portadresse umgestellt
push r24 // Das Ergebnis von canShow wird in r24 zurückgegeben
push r25 // canShow verändert r24 und r25, benötigt aber den Zeiger auf self darin
wait:
pop r25
pop r24
push r24
push r25
rcall canShow
tst r24
breq wait
pop r25
pop r24
movw r30,r24 // self in Z register laden
ldd r28,Z+TNeoPixel.fnumBytes // fnumBytes in r28/r29 = Y Register laden
ldd r29,Z+TNeoPixel.fNumBytes+1
ldd r26,Z+TNeoPixel.fPixels // Zeiger auf fPixels in X Register laden
ldd r27,Z+TNeoPixel.fPixels+1
ldd r22,Z+TNeoPixel.fPinMask
ldd r24,Z+TNeoPixel.fPin // Arduino Pin
ldd r25,Z+TNeoPixel.fPin+1
push r30 // Z Register sichern. Wird von digitalReadPort überschrieben
push r31
rcall digitalReadPort // Den aktuellen Zustand des Ports auslesen (wird in r24 zurückgeliefert)
pop r31
pop r30
ldd r18,Z+TNeoPixel.fPort // Portadresse zwischenspeichern
ldd r19,Z+TNeoPixel.fPort+1
push r30 // Da wir nach dem senden der Sequenz 300us warten müssen,
push r31 // speichern wir den Inhalt des Z Registers auf dem Stack zwischen
movw r30,r18 // Portadresse in das Z Register laden.
// ab hier kann nicht mehr auf self zugegriffen werden
mov r18,r24 // Aktuellen Portzustand in r18 schreiben
mov r19,r18 // und diesen auch nach lo schreiben
or r18,r22 // Pin Bit setzen (hi)
com r22 // Alle Bits ausser unserem setzen
and r19,r22 // Pin Bit löschen, alles andere so lassen wie es ist
com r22 // unser Bit wieder setzen, alles andere löschen
ldi r20,8 // Bit Zähler
ld r21,X+ // erstes Byte laden und X Register erhöhen
mov r22,r19 // next := lo
cli // Interrupts sperren
NextBit:
st Z,r18 // PORT := hi (T = 0)
sbrc r21,7 // if (Byte and 128) then (T = 2)
mov r22,r18 // next := hi (T = 4)
dec r20 // Bit := Bit - 1 (T = 5)
st Z,r22 // Port := next (T = 7)
mov r22,r19 // next := lo (T = 8)
breq NextByte // if Bit = 0 then NextByte (from dec above)
rol r21 // Rotate Left on Byte (T = 10)
rjmp nop1 // 3 Takte Pause (T = 11)
nop1:
nop // (T = 13)
st Z,r19 // Port := lo (T = 15)
rjmp nop2 // 3 Takte Pause machen
nop2:
nop //
rjmp NextBit // Nächstes Bit ausgeben
NextByte:
ldi r20,8 // Bit := 8
ld r21,X+ // Nächstes Byte von fPixels laden
st Z,r19 // Port := lo
rjmp nop3 // 1 Takt warten
nop3:
sbiw r28,1 // Bytezähler decrementieren
brne NextBit // Nicht Null? nächstes Byte ausgeben
pop r31 // die Adresse von self wieder zurück
pop r30 // holen
sei // Interrupts wieder zulassen
rcall micros // Aktuellen Microsekundenzählerstand in fEndTime speichern
std Z+TNeoPixel.fEndTime,r22
std Z+TNeoPixel.fEndTime+1,r23
std Z+TNeoPixel.fEndTime+2,r24
std Z+TNeoPixel.fEndTime+3,r25
pop r31 // gesicherte Register wieder herstellen.
pop r30
pop r22
pop r21
pop r20
pop r19
pop r18
pop r26
pop r27
pop r28
pop r29
end;
{$endif}
Ausschlag gebend für diesen Umständlichen Weg ist leider der Aspekt
und da scheue ich mich auch nicht dies zuzugeben das ich nicht weiß, wie ich den Compilerschalter (MCU-Auswahl) in ASM hinbekomme.
mir persönlich wäre auch unter ASM folgender Weg angenehm.
Code: Alles auswählen
{$if defined (ATMega328p)}
call canShow
{$endif}
{$if defined (ATtiny45) of defined (ATtiny85)}
rcall canshow
{$endif}
Lediglich nachstehden Meldungen muß ich noch anfassen.
ATTiny85
/usr/bin/avr-ld: region `data' overflowed by 762 bytes
ATTiny45
/usr/bin/avr-ld: region `text' overflowed by 2540 bytes
/usr/bin/avr-ld: region `data' overflowed by 1018 bytes
Wenn dies vom Tisch ist, einmal Toasten und Testlauf, Änderungen Dokumentieren, bevor ich es in's git werfe.