Du machst eine naked Funktion, siehe auch das Beispiel bei GCC im Abschnitt Interrupts.
Code:
#include <avr/io.h>
uint8_t register G_cLastData asm ("r2");
void __attribute__ ((naked))
SIG_INTERRUPT0 (void)
{
// Port D
__asm__ __volatile (
"in r2, %0" "\n\t"
"reti"
:
: "M" (_SFR_IO_ADDR (PORTD))
);
}
GCC macht daraus:
Code:
.global __vector_1
.type __vector_1, @function
__vector_1:
in r2, 24
reti
Wichtig ist, daß in ALLEN deinen Modulen R2 so als Register deklariert ist, damit GCC nicht auf die Idee kommt, nach R2 Werte zu allokieren. Das gilt auch für Module, die G_cLastData nicht verwenden!
Oder du must anfangen, zu sichern mit push/pop:
Code:
#include <avr/io.h>
uint8_t volatile G_cLastData;
void __attribute__ ((naked))
SIG_INTERRUPT0 (void)
{
// Port D
__asm__ __volatile (
"push r2" "\n\t"
"in r2, %1" "\n\t"
"sts %2, r2" "\n\t"
"pop r2" "\n\t"
"reti"
:
: "M" (_SFR_IO_ADDR (PORTD)) : "i" (&G_cLastData)
);
}
Das führt zu
Code:
.global __vector_1
.type __vector_1, @function
__vector_1:
push r2
in r2, 18
sts G_cLastData, r2
pop r2
reti
Wichtig ist, daß dabei keine Instruktion den Status ändert (SREG). Daß R2 verwendet wird, braucht GCC nicht zu interessieren. Falls man GCC die Register-Allokierung überlässt, weiß man nicht, wofür er sich entscheidet. Und da GCC kein Epilog machen soll (naked), geht das auch gar nicht, weil das Register nicht wieder hergestellt werden könnte. Daher wird auch das Speichern in die Variable im Asm gemacht.
Zu den Zeiten der ISR-Befehlen muss noch die Interrupt-Respond-Zeit hinzugezählt werden (IRQ-Latenz) und die Zeit für den Sprung aus der Vektor-Tabelle, sie ist also davon abhängig, welche IRQs sonst noch aktiv sind und wie deren ISRs aussehen.
Lesezeichen