Forum: Compiler & IDEs AUf Kriegsfuß mit dem AVR-GCC.


von robbse (Gast)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

ich denke dass mein Problem für Euch bestimmt kein großes Hindernis 
darstellt, aber ich blicks halt nicht! Ich habe bei uns in der Firma ein 
paar mal mit dem IAR-Compiler was geschrieben und wollte nun meinen Code 
mit GCC ähnlich strukturieren. Habe im Hauptprogramm nur Abfragen auf 
Statusbits laufen, die in Interrupts gesetzt werden (funktioniert). 
Dummerweise scheint diese simple (?) Statusbitabfrage nicht zu gehen! 
Habe mal ein AVR Studio Projekt angehangen, welches sich schon im 
Simulator aufhängt. Wenn Ihr also so freundlich wärt mir diese Eigenheit 
zu erklären..? Danke!

robbse

von Falk W. (dl3daz) Benutzerseite


Lesenswert?

robbse schrieb:
> Hallo zusammen,
...
> Habe im Hauptprogramm nur Abfragen auf
> Statusbits laufen, die in Interrupts gesetzt werden (funktioniert).
> Dummerweise scheint diese simple (?) Statusbitabfrage nicht zu gehen!
> Habe mal ein AVR Studio Projekt angehangen, welches sich schon im
> Simulator aufhängt. Wenn Ihr also so freundlich wärt mir diese Eigenheit
> zu erklären..? Danke!

Ich habe mir mal erlaubt, den vollständigen C-code aus dem 7kB .zip zu 
extrahieren ;-)
1
#include <avr/io.h>
2
3
uint8_t status = 0x01;
4
5
int main(void)
6
{
7
    while(1)
8
    {
9
        if(status & 0x01)
10
        {
11
            status &= ~0x01;
12
        }
13
14
        if(status & 0x02)
15
        {
16
            status &= ~0x02;
17
        }
18
    }
19
20
    return 0;
21
}

Wenn die Variable "status" in einer ISR geändert wird, muß sie als 
"volatile" deklariert werden.

HTH,
Falk

von Matthias H. (Gast)


Lesenswert?

fehlt da nicht noch ein #include <stdint.h>?

von robbse (Gast)


Lesenswert?

Stimmt! Danke :oD

von (prx) A. K. (prx)


Lesenswert?

Aus Sicht des C Compilers ist dieser Code vergleichbar mit
1
int main(void)
2
{
3
    while(1)
4
    {
5
    }
6
}

weil die Variable keine sichtbare Auswirkung hat.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Matthias H. schrieb:
> fehlt da nicht noch ein #include <stdint.h>?

inttypes.h kommt mit avr/io.h, wenn __ASSEMBLER__ nicht define'd ist.

Johann

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


Lesenswert?

Falk Willberg schrieb:

> Wenn die Variable "status" in einer ISR geändert wird, muß sie als
> "volatile" deklariert werden.

Ist aber beim IAR auch nicht anders, wenn man nicht gerade die
Optimierungen abschaltet...

von Michael G. (linuxgeek) Benutzerseite


Lesenswert?

Falk Willberg schrieb:

> Wenn die Variable "status" in einer ISR geändert wird, muß sie als
> "volatile" deklariert werden.

Richtig. Und wenn Dein IAR-Compiler es trotzdem "richtig" macht, 
optimiert er halt schlecht. Da C allerdings standardisiert ist wirst Du 
Dich nicht darauf verlassen koennen, dass andere Versionen des Compilers 
es nicht doch optimieren und es dann ebenfalls nicht mehr funktioniert. 
Mit dem GCC hat das erst einmal garnichts zu tun.

von Falk W. (dl3daz) Benutzerseite


Lesenswert?

Michael G. schrieb:
> Falk Willberg schrieb:
>
>> Wenn die Variable "status" in einer ISR geändert wird, muß sie als
>> "volatile" deklariert werden.
>
> Richtig. Und wenn Dein IAR-Compiler es trotzdem "richtig" macht,
> optimiert er halt schlecht.

Ich habe doch gar keinen IAR ;-)

> Da C allerdings standardisiert ist wirst Du
> Dich nicht darauf verlassen koennen, dass andere Versionen des Compilers
> es nicht doch optimieren und es dann ebenfalls nicht mehr funktioniert.

ISRs sind m.W. sowieso nicht Bestandteil irgendeines C-Standards.
Sobald der Compiler also das kleinste bischen optimiert, wird er 
feststellen, daß "status" höchstens mal in einer Funktion geändert wird, 
die nie aufgerufen wird.

> Mit dem GCC hat das erst einmal garnichts zu tun.

So isses, schrub ich aber auch nicht.

Falk

von Sven P. (Gast)


Lesenswert?

Johann L. schrieb:
> Matthias H. schrieb:
>> fehlt da nicht noch ein #include <stdint.h>?
>
> inttypes.h kommt mit avr/io.h, wenn __ASSEMBLER__ nicht define'd ist.
>
> Johann

Nur der Vollständigkeit halber: inttypes.h ist nicht gleich stdint.h und 
auch nicht als Ersatz gedacht.

Wobei man sich nun natürlich fragen könnte, wozu im C-Standard ein 
'volatile' verankert ist, wenn es doch eigentlich 'offiziell' überhaupt 
keine Nebenläufigkeit (Threads, Interrupts) gibt...

von Michael G. (linuxgeek) Benutzerseite


Lesenswert?

Falk Willberg schrieb:

> ISRs sind m.W. sowieso nicht Bestandteil irgendeines C-Standards.
> Sobald der Compiler also das kleinste bischen optimiert, wird er
> feststellen, daß "status" höchstens mal in einer Funktion geändert wird,
> die nie aufgerufen wird.
>
>> Mit dem GCC hat das erst einmal garnichts zu tun.
>
> So isses, schrub ich aber auch nicht.

Der Kommentar bezog sich eigentlich auf den OP, Deinen Beitrag wollte 
ich nur untermauern ;)

Das hatte nur so den Anschein, dass er halt glaubt, GCC wuerde hier 
etwas falsch machen, aber im Endeffekt war sein urspruengliches Programm 
falsch, das sein Compiler aufgrund schlechter Optimierung zufaellig 
richtig uebersetzt hat.

von Karl H. (kbuchegg)


Lesenswert?

Sven P. schrieb:

> Wobei man sich nun natürlich fragen könnte, wozu im C-Standard ein
> 'volatile' verankert ist, wenn es doch eigentlich 'offiziell' überhaupt
> keine Nebenläufigkeit (Threads, Interrupts) gibt...

:-)
Weil es dann immer noch die Möglichkeit gibt, sich einen Pointer auf 
eine memory mapped unit zu generieren und sich Speicherzellen wie von 
Geisterhand selbst verändern.

Auf der anderen Seite: Wie kriegt man so einen Pointer als ordinäres 
C-Programm? Man kann eine Betriebssystemfunktion darum bitten. Meinem 
Verständnis nach ist man damit sowieso um undefined-land, wenn man 
diesen Pointer dereferenziert.
Oder man castet einen int zurecht. Aber auch das ist dann ein 
undefined-land Stunt.

(Oder wars unspecified. Kann mir nie merken, was von beiden was ist. 
Unspecified ist IMHO: Alles kann passieren. Und wenn die Welt dabei 
spontan untergeht, ist das auch ok.
Undefined: Die Welt darf zwar untergehen, allerdings nur dann wenns im 
Handbuch steht. Aber dann muss sie auch jedesmal untergehen.)

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


Lesenswert?

Sven P. schrieb:

> Nur der Vollständigkeit halber: inttypes.h ist nicht gleich stdint.h und
> auch nicht als Ersatz gedacht.

Die Typdefinitionen von <stdint.h> sind eine Untermenge der
Definitionen von <inttypes.h>.  Ursprünglich hatte man wohl nur
<inttypes.h> definiert, das sowohl die Typnamen als auch allerlei
printf- und scanf-Format-Definitionen für deren Ein-/Ausgabe umfasst.
Dann hat man sich drauf besonnen, dass gerade embedded systems ggf.
zwar die Typnamen auch benutzen wollen, aber an den Konvertierungen
gar nicht interessiert sind.  Da hat man <stdint.h> als Untermenge
festgelegt.

> Wobei man sich nun natürlich fragen könnte, wozu im C-Standard ein
> 'volatile' verankert ist, wenn es doch eigentlich 'offiziell' überhaupt
> keine Nebenläufigkeit (Threads, Interrupts) gibt...

Die kann es in einer Implementierung schon geben, nur deren Details
sind nicht im Standard geregelt.  Das einzige Detail, was halt geregelt
ist, ist dabei volatile.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Jörg Wunsch schrieb:

> Die kann es in einer Implementierung schon geben, nur deren Details
> sind nicht im Standard geregelt.  Das einzige Detail, was halt geregelt
> ist, ist dabei volatile.

Wobei der aktuelle GCC da schwächelt und volatile nicht immer 
berücksichtigt. Hier nur ein einfaches Beispiel:
1
extern const volatile char x;
2
3
void foo ()
4
{
5
    while (x);
6
}

Wird mit avr-gcc 4.3.2 (dito blah-gcc) mit -Os zu
1
foo:
2
  lds r24,x   ;  x.0, x
3
.L2:
4
  tst r24   ;  x.0
5
  brne .L2
6
  ret

Johann

von A. N. (netbandit)


Lesenswert?

@Johann:
Vielleicht erkennt GCC, dass es so wenig globale/lokale Variablen gibt, 
dass man x dort dauerhaft auf r24 legen könnte.

Vielleicht ändert sich das wenn das Programm größer wird und der GCC 
nicht mehr gewährleisten kann, dass r24 nicht woanders benutzt wird.

von Stefan E. (sternst)


Lesenswert?

A. N. schrieb:
> Vielleicht erkennt GCC, dass es so wenig globale/lokale Variablen gibt,
> dass man x dort dauerhaft auf r24 legen könnte.
>
> Vielleicht ändert sich das wenn das Programm größer wird und der GCC
> nicht mehr gewährleisten kann, dass r24 nicht woanders benutzt wird.

Mir ist nicht ganz klar, was du damit sagen willst.
x ist volatile deklariert, daher müsste er x in der Schleife immer 
wieder neu aus dem Speicher lesen, ganz unabhängig von irgendwelchen 
Optimierungen.

von Gast (Gast)


Lesenswert?

Falls x überhaupt im Speicher angelegt wird. Wenn es eh direkt in ein 
Register gepackt wird fällt dieses aus dem Speicher holen weg.

von Stefan E. (sternst)


Lesenswert?

Gast schrieb:
> Falls x überhaupt im Speicher angelegt wird. Wenn es eh direkt in ein
> Register gepackt wird fällt dieses aus dem Speicher holen weg.

x ist eine externe globale Variable.

Außerdem sieht man doch am lds vor der Schleife, dass x im Speicher 
existiert.

von A. N. (netbandit)


Lesenswert?

Stimmt, das war wohl schon etwas spät gestern Abend. Naja wäre nicht das 
erste mal, das gcc einen Fehler macht.

von Sven P. (Gast)


Lesenswert?

Aus dem C99-Standard:

> The header <inttypes.h> includes the header <stdint.h> and extends
> it with additional facilities provided by hosted implementations.

Ich hab nix gesagt :-) War mir so garnicht bewusst.

von Marcus M. (marcus67)


Lesenswert?

Johann L. schrieb:
> Jörg Wunsch schrieb:
>
>> Die kann es in einer Implementierung schon geben, nur deren Details
>> sind nicht im Standard geregelt.  Das einzige Detail, was halt geregelt
>> ist, ist dabei volatile.
>
> Wobei der aktuelle GCC da schwächelt und volatile nicht immer
> berücksichtigt. Hier nur ein einfaches Beispiel:
>
>
1
> extern const volatile char x;
2
> 
3
> void foo ()
4
> {
5
>     while (x);
6
> }
7
>
>
> Wird mit avr-gcc 4.3.2 (dito blah-gcc) mit -Os zu
>
1
> foo:
2
>   lds r24,x   ;  x.0, x
3
> .L2:
4
>   tst r24   ;  x.0
5
>   brne .L2
6
>   ret
7
>
>
> Johann

extern const volatile char x;

Na ja, vielleicht hat das ja mit dem "const" in der Deklaration zu tun 
...
Warum sollte ein const sich ändern ...

Gruß, Marcus

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


Lesenswert?

Marcus Müller schrieb:

> extern const volatile char x;
>
> Na ja, vielleicht hat das ja mit dem "const" in der Deklaration zu tun
> ...
> Warum sollte ein const sich ändern ...

Es könnte sich durch Hardware-Einflüsse ändern.  Diese Möglichkeit
wird vom Standard explizit eingeräumt:

EXAMPLE 1      An object declared
        extern const volatile int real_time_clock;
may be modifiable by hardware, but cannot be assigned to, incremented, 
or decremented.

Der Compiler muss also im Zweifelsfalle das const ignorieren, darf
das volatile aber nicht ignorieren.

von Stefan E. (sternst)


Lesenswert?

Marcus Müller schrieb:

> Na ja, vielleicht hat das ja mit dem "const" in der Deklaration zu tun
> ...
> Warum sollte ein const sich ändern ...

In C gilt: const != konstant
Es sagt dem Compiler nur, dass er selber die Variable nicht ändern darf, 
nicht, dass sich der Wert gar nicht ändert. "const volatile" ist z.B. 
eine gute Beschreibung für ein Read-Only-Hardwareregister.

von Marcus M. (marcus67)


Lesenswert?

Habe ich in der Zwischenzeit auch nachgelesen - volatile "überstimmt" 
das const ...

Gruß, Marcus

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.