Forum: Compiler & IDEs flag -Register in ISR


von Ingo B. (tueddler)


Lesenswert?

Hallo,

wieder einmal komme ich nicht weiter. Und zwar habe ich eine 
zeitkritische Anwendung, in der das Speichern von Status- und anderen 
Registern innerhalb der ISR einen nicht unerheblichen Teil der CPU-Zeit 
in Anspruch nimmt, obwohl nur ein Flag gesetzt werden soll. Nun habe ich 
hier im Forum gelesen, dass man die ISR als naked definieren kann:
1
ISR(ADCA_CH0_vect, ISR_NAKED)
2
{
3
  intFlags|=(1<<4); // Bit 4 setzen
4
}

Um zu verhindern, dass der Compiler Code erzeugt, der die nun nicht 
gesicherten Register anfasst, wuerde ich gerne die Variable intFlags in 
ein ungenutztes Peripherie-Register speichern. Mir schwebt da z.B. das 
IRCOM-TXPLCTRL-Rgister des xMegas (ATxMega64A1)vor, das ich auf keinen 
Fall anderweitig nutzen werde. Irgendein ungenutzter Timer geht 
natuerlich auch. Mit den general-purpose-Registern geht das wohl so:
1
register volatile uint8_t intFlags asm("r4")

Wie aber nutze ich ein beliebiges Register? Muss ich da die Adresse 
angeben und wenn ja, wie?

Vielen Dank!

Ingo.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

1) Schreibe die ISR in Assembler!

2) Register sind nicht volatile, entsprechende Compilerwarnung beachten!

von AVR (Gast)


Lesenswert?

Hat der xmega kein GPIO0 mehr, das man via SBI/CBI beackern kann?

von Falk B. (falk)


Lesenswert?

@AVR (Gast)

>Hat der xmega kein GPIO0 mehr, das man via SBI/CBI beackern kann?

Gute Idee. Man kann aber auch andere Registerbits nutzen, die ungenutz 
sind, auch Portbits etc! Müssen halt nur in den unteren Registern 
liegen, um mit sbi/cbi angesprochen werden zu können.

von Ingo B. (tueddler)


Lesenswert?

Johann L. schrieb:
> 1) Schreibe die ISR in Assembler!

Habe leider noch keine Erfahrung im Misch-Kauderwelsch, wohl aber in 
reinem asm. Kannst du mir einen Tipp geben, wo ich etwas ueber die 
Integration von asm-Routinen nachlesen kann? Oder meinst du inline-asm?

> 2) Register sind nicht volatile, entsprechende Compilerwarnung beachten!

Heisst das, dass "volatile" schlichtweg unnoetig ist?

Falk Brunner schrieb:
> Man kann aber auch andere Registerbits nutzen, die ungenutz
> sind, auch Portbits etc!

Meine Frage zielt darauf ab, ob das auch in gcc geht, und wenn wie 
(Bsp). Oder ist hier asm obligatorisch?

Gruss,
Ingo.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Ingo B. schrieb:
> Johann L. schrieb:
>> 1) Schreibe die ISR in Assembler!
>
> Habe leider noch keine Erfahrung im Misch-Kauderwelsch, wohl aber in
> reinem asm. Kannst du mir einen Tipp geben, wo ich etwas ueber die
> Integration von asm-Routinen nachlesen kann? Oder meinst du inline-asm?

Mischen ist hier nicht angesagt sondern reiner Assembler. Dafür wiederum 
gibt es 2 Möglichkeiten:

i) Ein Assemblermodul (.sx oder .S) mit der ISR oder

ii) Integration der in Assembler stehenden ISR per globalem asm
    in die C-Quelle.

Als Vorlage kann die Assembler-Ausgabe des Compilers dienen, welcher 
dieser für eine minimale naked-ISR erzeugt. Siehe -save-temps und das 
s-File.

>> 2) Register sind nicht volatile, entsprechende Compilerwarnung beachten!
>
> Heisst das, dass "volatile" schlichtweg unnoetig ist?

voltile bei globalen Registern hat keinen Effekt. Dementsprechend kann 
GCC Zugriffe auf globale Register wegoptimieren.

von Falk B. (falk)


Angehängte Dateien:

Lesenswert?

@ Ingo B. (tueddler)

>Habe leider noch keine Erfahrung im Misch-Kauderwelsch, wohl aber in
>reinem asm. Kannst du mir einen Tipp geben, wo ich etwas ueber die
>Integration von asm-Routinen nachlesen kann?

In der Doku der libc, ist beim WinAVR dabei.

> Oder meinst du inline-asm?

Nein.

>> 2) Register sind nicht volatile, entsprechende Compilerwarnung beachten!

>Heisst das, dass "volatile" schlichtweg unnoetig ist?

Nein, es funktioniert nicht wie gewünscht.

>> Man kann aber auch andere Registerbits nutzen, die ungenutz
>> sind, auch Portbits etc!

>Meine Frage zielt darauf ab, ob das auch in gcc geht,

Was?

Siehe Anhang.

von Falk B. (falk)


Angehängte Dateien:

Lesenswert?

Uuups, da fehlt ein reti ;-)

von Ingo B. (tueddler)


Lesenswert?

Falk Brunner schrieb:
> Nein, es funktioniert nicht wie gewünscht.

Was heisst gewuenscht? Ich moechte nur, dass der Compiler die Variable 
ausschliesslich in der angegebenen Adresse (z.B. timer compare register) 
speichert und nicht im SRAM.

>>Meine Frage zielt darauf ab, ob das auch in gcc geht,
>
> Was?

Naiv soetwas wie:
1
register uint8_t intFlags asm("TXPLCTRL");

Also, wie kann ich gcc klarmachen, dass die Adresse fuer intFlags die 
eines Peripherie-Registers ist?

Dein Beispiel sollte es schon tun, nur warum kann ich sicher sein, dass 
der Code, der im define angegeben wird
1
PORTD &=~(1<<PD0);
 keines der nun nicht gespeicherten Register (Status etc.) aendert?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Ingo B. schrieb:

> Naiv soetwas wie:
>
1
register uint8_t intFlags asm("TXPLCTRL");
>
> Also, wie kann ich gcc klarmachen, dass die Adresse fuer intFlags die
> eines Peripherie-Registers ist?

Garnicht. Schreib einfach TXPLCTRL und gut ist.

von Ingo B. (tueddler)


Lesenswert?

Johann L. schrieb:
> voltile bei globalen Registern hat keinen Effekt. Dementsprechend kann
> GCC Zugriffe auf globale Register wegoptimieren.

Nun bin ich verwirrt. Sind Register nicht immer global? Also entweder 
weise ich einer Variable das Register zu (dann steht dieses Register 
fuer den Compiler fuer den Rest des Codes nicht mehr zur Verfuegung), 
oder die ganze Aktion "register uint8_..." hat keinen Sinn, oder? 
Offensichtlich verstehe ich da etwas nicht richtig...

von Ingo B. (tueddler)


Lesenswert?

Johann L. schrieb:
> Garnicht. Schreib einfach TXPLCTRL und gut ist.

Meinst du:
1
register uint8_t intFlags TXPLCTRL;

von Johann L. (gjlayde) Benutzerseite


Lesenswert?


von Ingo B. (tueddler)


Lesenswert?

Johann L. schrieb:
> Wenn alles andere scheitert: Doku lesen!

Super, danke, das hatte ich nicht gesehen. Aber im Prinzip stimmt meine 
Vorstellung schon. Nur, dass das "nicht zur Verfuegung stehen" bei 
lokalen Registern nur innerhalb der Funktion zutrifft, oder?

Bleibt die Frage, wie ich statt "r0" etc. ein Peripherie-Register 
spezifiziere. Ein Code-Beispiel, dass die falsche Version oben 
korrigiert waere super.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Ingo B. schrieb:
> Johann L. schrieb:
>> Wenn alles andere scheitert: Doku lesen!
>
> Super, danke, das hatte ich nicht gesehen. Aber im Prinzip stimmt meine
> Vorstellung schon. Nur, dass das "nicht zur Verfuegung stehen" bei
> lokalen Registern nur innerhalb der Funktion zutrifft, oder?

Nein, selbst in der Funktion kann das Register anderwärtig verwendet 
werden.

> Bleibt die Frage, wie ich statt "r0" etc. ein Peripherie-Register
> spezifiziere. Ein Code-Beispiel, dass die falsche Version oben
> korrigiert waere super.

Du denkst zu kompliziert.
1
#include <stdint.h>
2
3
#define TXPLCTRL (*(uint8_t volatile*) 0x1234)
4
5
void foo (void)
6
{
7
    TXPLCTRL = 0;
8
    TXPLCTRL = 1;
9
    TXPLCTRL |= 2;
10
    TXPLCTRL &= ~2;
11
    // etc
12
}

von Ingo B. (tueddler)


Lesenswert?

Johann L. schrieb:
> Nein, selbst in der Funktion kann das Register anderwärtig verwendet
> werden.

OK, hier steht's:
"This option does not guarantee that GCC generates code that has this 
variable in the register you specify at all times. You may not code an 
explicit reference to this register in the assembler instruction 
template part of an asm statement and assume it always refers to this 
variable. However, using the variable as an asm operand guarantees that 
the specified register is used for the operand."

Nur was genau heisst "asm operand"? Ist das register-keyword also nur 
von Nutzen, wenn ich asm-Code anwende (z.B damit ich sicher sein kann, 
dass in r0 die Variable intFlags steht)? Irgendwie ist mir der Sinn von 
"register" wohl doch noch nicht klar. Gibt es irgendwo dazu ein 
praktischen Beispiel, dass den Sinn verdeutlicht?

Johann L. schrieb:
> Du denkst zu kompliziert.

Hmm ja, das sollte gehen, da muss ich noch etwas rumprobieren...

Danke jedenfalls fuer die Tipps!

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Ingo B. schrieb:
> Johann L. schrieb:
>
> Nur was genau heisst "asm operand"?

Inline asm kann Input- und / oder Output-Operanden haben, im Manual "C 
Expression Operands".

http://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html

> Ist das register-keyword also nur von Nutzen, wenn ich asm-Code
> anwende (z.B damit ich sicher sein kann, dass in r0 die Variable
> intFlags steht)?

Die Zuordnung Variable <-> lokales Register gilt nur zum "Zeitpunkt" der 
Verwendung als asm-Operand.

> Gibt es irgendwo dazu ein praktischen Beispiel, das den Sinn
> verdeutlicht?

Ja, hier, für avr-gcc:
1
static inline uint8_t prandom8 (void)
2
{
3
    register uint16_t p asm ("r26");
4
    asm volatile ("%~call lfsr_8" : "=r" (p));
5
    return p;
6
}

prandom8 ist eine C-Funktion, die eine 8-Bit Pseudozufallszahl liefern 
soll. Die Implementierung steht in asm in lfsr_8, allerdings genügt 
diese Funktion nicht dem avr-gcc ABI: Sie gibt nämlich einen 16-Bit 
Pseudozufall in R26/R27 zurück. prandom8 funktioniert hier als Wrapper 
für die asm-Funktion und teilt dem Compiler die Nebeneffekte des Aufrufs 
von lfsr_8 mit.

Alles in allem beschreibt das asm einen transparenten Funktionsaufruf, 
d.h. es ist ein Funktionsaufruf, den der Compiler aber nicht als solchen 
sieht.

Eingesetzt wird das in einem Context wo minimaler Overhead geboten ist 
aber dennoch möglichst viel des Codes (Asteroids-Clone) in C steht.

http://www.youtube.com/watch?v=TDiPibnHgW4

Das Spiel läuft übrigens auf einem ATmega168, und als globales 
Flag-Register wird GPIOR0 eingesetzt.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.