Forum: Compiler & IDEs globale Variable als Register


von Frank E. (erdi-soft)


Lesenswert?

Hi Leute,

mal wieder ein kleines Problem.

Habe 2 globale Variablen (als volatile deklariert), die ich in der 
Header zum zweiten *.c-File mit extern volatile .... einbinde.

Nun möchte ich die beiden globalen Variablen allerdings gerne dauerhaft 
in einem Register stehen haben. Mit register uint8_t bla asm("r2"); kann 
ich dem Compiler ja sagen, dass diese Variable in r2 stehen soll (mehr 
oder weniger).

Nun weiß ich aber nicht, wie ich das mit dem extern machen soll. Mit 
extern uint8_t bla; heißt es "undefined Reference", mit extern register 
uint8_t bla;
sagt der Compiler "multiple storage classes ....".

Was mache ich falsch? Oder geht das überhaupt?


Gruß,
ERDI - Soft.

von Rolf Magnus (Gast)


Lesenswert?

Nein, das geht nicht. extern impliziert, daß das Objekt auf jeden Fall 
im Speicher steht.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

> Oder geht das überhaupt?

Die Benutzung einer globalen Registervariablen verlangt, dass du
letztlich in allen Übersetzungsmodulen die gleiche Definition benutzt,
denn nur so weiß der Compiler ja darüber, dass dieses Register für
einen bestimmten Zweck vorbelegt ist.

Damit hast du auch das grundlegende Dilemma solcher Variablen auf dem
Tisch: auch die Bibliotheksmodule müssten letztlich ebenfalls mit
einer (deiner!) derartigen Deklaration compiliert werden, damit sie
nicht auf die Idee kommen, das Register selbst zu nutzen.

Mit einem ,,niedrigen'' Register (also r2, r3, ...) ist die Chance
einer Kollision mit der Bibliothek zwar gering, aber wir (also die
Ersteller der Bibliothek) überwachen nicht, welche Register der
Compiler tatsächlich verwendet.  Es könnte gut auch künftige
Bibliotheksmodule geben, die auch die niedrigen Register nehmen
(denkbar ist bspw. dass der Compiler auf sowas zurückgreift, falls mal
jemand eine 64-bit-Gleitkomma-Bibliothek baut).

von Frank E. (erdi-soft)


Lesenswert?

Schön und gut, aber global kann ich nicht einfach register uint8_t bla; 
schreiben, da ihm sonst was fehlt. Würde das ja wirklich sehr gerne dem 
Compiler überlassen.
Witzigerweise ist das aber in der Funktion (z.B. in der main) ohne 
weiteres möglich.

Fragen wir mal anders: Gibt es ne Möglichkeit, ne globale Variable in 
einem Register anzulegen und diese auch anderen Modulen bekannt zu 
machen, ohne explizit ein Register anzugeben?
Bei diesem Projekt benutze ich keine externen Bibliotheken, von dem her 
sind solche evtl. Kollisionen ausgeschlossen.

Aber ich sehe schon, ich muss das doch in Assembler schreiben, sonst 
komm ich mit der Geschwindigkeit nicht hin (sofern ich nicht noch 
irgendwo ne Optimierungsmöglichkeit finde).

Aber danke schonmal für eure Antworten.


Gruß,
ERDI - Soft.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Frank Erdrich wrote:

> Schön und gut, aber global kann ich nicht einfach register uint8_t
> bla; schreiben, da ihm sonst was fehlt.

Nein, aber du kannst (und sollst) in jedem Modul

register uint8_t bla asm("r2");

reinschreiben.

> Witzigerweise ist das aber in der Funktion (z.B. in der main) ohne
> weiteres möglich.

Das ist aber nur eine andere Variante von "auto"-Variable.  Daher
stammt das "register"-Schlüsselwort, damit wurde früher dem Compiler
ein Hinweis gegeben, diese Variable vorzugsweise in einem Register zu
halten.  Heute brauchen die Compiler solcherlei Hinweise nicht mehr,
damit ist das Schlüsselwort praktisch bedeutungslos.

Mit einer Registerbindung hat das nichts zu tun.

> Fragen wir mal anders: Gibt es ne Möglichkeit, ne globale Variable
> in einem Register anzulegen und diese auch anderen Modulen bekannt
> zu machen, ohne explizit ein Register anzugeben?

Nein.

> Bei diesem Projekt benutze ich keine externen Bibliotheken, von dem
> her sind solche evtl. Kollisionen ausgeschlossen.

OK, wenn du nicht mal memcpy() & Co benutzt

> Aber ich sehe schon, ich muss das doch in Assembler schreiben, sonst
> komm ich mit der Geschwindigkeit nicht hin (sofern ich nicht noch
> irgendwo ne Optimierungsmöglichkeit finde).

Das bringt was, wenn du 20 oder 30 % daneben liegst, aber nicht, wenn
du 100 % daneben liegst (es sei denn, es handelt sich nur um eine
kurze zeitkritische Schleife oder sowas).

von Frank E. (erdi-soft)


Lesenswert?

Na ja, es handelt sich um ne (eigentlich) simple PWM für ne RGB-LED.
Problem dabei ist, dass es auf Batterie laufen soll, d.h. Taktfrequenz 
so klein wie möglich. (Bei derzeit 1MHz passt es gerade mit nem 
Timer-Zyklus von knapp 80µs. bei 100µs fängts schon leicht an zu 
flimmern. -> 128bit PWM)
Der Timerinterrupt macht prinzipiell nicht weiteres, als ne Variable auf 
max. zu prüfen und evtl. auf 0 setzen und ne 2. Variable wird gesetzt.
Der Rest wird in der Main erledigt. Allerdings bläht mir GCC die ISR 
gewaltig auf.
Derzeit hab ich noch etwa 5-6 Taktzyklen Spielraum, um die letzte 
Option, die Geschwindigkeit, zu implementieren.

Prinzipiell könnte ich natürlich auch nen Controller mit Hardware-PWM 
benutzen, z.B. den tiny25. Nächstes k.O.-Kriterium ist allerdings der 
Preis. So billig als möglich. Deshalb werde ich das wohl oder übel 
sowieso in ASM nochmal umsetzen müssen, da der tiny11 (der günstigste) 
ja nicht vom GCC unterstützt wird.

Nu ja, seis drum. Ich werd mal noch ein wenig mit der ISR 
experimentieren. Vielleicht kann ich da noch ein wenig Code hin 
auslagern. Oder mir fällt noch was ganz anderes ein. :-)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Naja, für sowas kann sich eine reine Assemblervariante noch lohnen,
das ist ja überschaubar.

Die 128-bit-PWM ist gut. :-)  (Ist das ein "long long long int"?)

Billigster (also uralter) Controller und niedriger Stromverbrauch
beißen sich natürlich als Forderungen.  Du bist dir auch dessen
gewahr, dass du den ATtiny11 nur HV-programmieren kannst und dass die
Stabilität dieses uralten RC-Oszillators unter aller Sau ist, ja?
Eine Frequenzvariation von 1:2 zwischen voller und leerer Batterie
dürfte dort normal sein.

Vielleicht ja einen etwas moderneren Controller, ihn auch bissel höher
takten, dafür aber weitgehend schlafen legen?  Da die LED sowieso
kräftig Strom zieht, sollte der idle-Strom des Controllers nicht so
schwer ins Gewicht fallen.  Ich würde wahrscheinlich eher zu einem
ATtiny13 greifen.  Der verbraucht aktiv bei 1 MHz gerade mal so viel
wie ein ATtiny11 idle bei 1 MHz (oder er braucht bei 5 MHz so viel ein
ein ATtiny11 bei 1 MHz).

von Frank E. (erdi-soft)


Lesenswert?

Hast ja Recht, ist ne 7 bit PWM. :-D
Die Controllerwahl ist noch nicht getroffen. Usprünglich war der tiny12 
geplant. Hab grad eben mal schnell nach Preisen geguckt, und da wäre der 
tiny11 der günstigste.
Hatte aber wohl doch nen Grund, dass ich mir damals den tiny12 
ausgesucht habe. Nu ja, die Entscheidung ist nicht dringend, bin ja 
schon froh, dass ich sanfte Farbübergänge habe.

Trotz allem Danke für deine Hilfe.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Naja, der ATtiny12 scheint mir ein ATtiny11 mit ISP zu sein, ansonsten
aber genauso alt und entsprechend miserabel in den Daten.  Der '13
kostet nur paar Cent mehr und ist deutlich moderner.  Der hat ja sogar
ein CKLPR, da könntest du den Takt on the fly zum Rechnen hochschrauben.

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.