AVR Studio 5 meckert sehr viel

Gast #2411427
Lesenswert?

Also ich habe jetzt mit AVR Studio 5 ein altes Projekt versucht zu 
kompilieren und irgendwie ist der Wurm drinn.

Bei 4.XX konnte man z.B. ohne Problem Code generieren, wenn man z.B. mit 
der UART Schnittstelle gearbeitet hat, es gab lediglich ne Warnung wenn 
die Datentypen anders waren als vorgesehen. In Version 5 bricht der 
sofort ab, wenn z.B. eine Variable uint8_t sein soll, aber volatile 
uint8_t ist.

Wie kann man dem Compiler das austreiben? Gibts da n Kommando/Befehl?
Warum ist Atmel so eine ungeheure Bastelbude was das angeht?


Knut
Gast #2411513
Lesenswert?

Knut schrieb:
> Also ich habe jetzt mit AVR Studio 5 ein altes Projekt versucht zu
> kompilieren und irgendwie ist der Wurm drinn.

???

> Bei 4.XX konnte man z.B. ohne Problem Code generieren, wenn man z.B. mit

Ich glaube nicht dass Du wirklich generieren meinst, eher wohl 
schreiben?

> der UART Schnittstelle gearbeitet hat, es gab lediglich ne Warnung wenn
> die Datentypen anders waren als vorgesehen. In Version 5 bricht der
> sofort ab, wenn z.B. eine Variable uint8_t sein soll, aber *volatile*
> uint8_t ist.

Ist doch gut, das ist potentiell ein Bug?

> Wie kann man dem Compiler das austreiben? Gibts da n Kommando/Befehl?
> Warum ist Atmel so eine ungeheure Bastelbude was das angeht?

Ist es nicht.

Das ist der benutzte GCC und vermutlich die von der IDE per Default 
benutzten Optionen. Wenn Du das wirklich abstellen willst: 
Projektoptionen im AVR Studio und die Doku zu den GCC-Optionen ansehen.

Hinweis: Du willst die Warnungen/Fehler nicht wirklich einfach 
deaktivieren. Das sind fast(!) alles potentielle Bugs, man kommt 
wesentlich besser weg wenn man die Ursachen verstehen lernt und den Code 
fixt. Gerade bei volatile...
Moderator Persönliche Seite #2411778
Lesenswert?

Knut schrieb:
> Warum ist Atmel so eine ungeheure Bastelbude was das angeht?

Weil du deinem Compiler offenbar Bastelbuden-Code vorlegst. ;-)

Nicht alles, was compiliert, muss auch notwendigerweise korrekter
Code sein.  Man kann lediglich sagen, dass ein Compiler aus korrektem
Code auch ein korrektes Programm bauen muss, aber er ist nicht
verpflichtet, jede Unkorrektheit wirklich festzustellen und mit einem
Fehler oder einer Warnung zu honorieren.  Da der GCC stetig immer
besser wird, Unkorrektheiten zu erkennen, moniert er nun halt Dinge
an, die in deinem Code zwar bereits früher unkorrekt waren, was er
aber in einer älteren Version noch nicht erkannt hat.

Die Firma Atmel hat damit weiter nichts zu tun, als dass sie einen
recht guten Compiler zusammen mit ihrer IDE ausliefert.
Gast #2411953
Lesenswert?

Hmm... seit der neuen Toolchain meckert nun auch 4.19.
Ist vlt. auch gar nicht schelcht. Aber wenn ich eine Variable volatile 
mache, weil sie in einer ISR benutzt wird, aber als "normal" vorgesehen 
ist, wie kann ich das Problem umgehen, dass er meckert?


Knut
#2412284
Lesenswert?

Peter Dannegger schrieb:
> Man kann sie mit eine Macro im Main-Kontext nach volatile casten

Bei 8bit-Werten klappt das Makro noch, aber bei größeren Werten ist es 
eine recht unangenehm zu debuggende Fehlerquelle, sollte man als Warnung 
dazuschreiben.

Im allgemeinen wär's besser, vorher "volatile" zu verstehen, und sich zu 
überlegen, ob man atomaren Zugriff oder eine memory barrier braucht, und 
ob man dies durch ein schreibfaules einfaches "volatile" simulieren 
kann.
#2412392
Lesenswert?

Stefan Ernst schrieb:
> Was genau meinst du damit?

Beispiel:
1
volatile uint16_t counter;
2

3
ISR:
4
  counter++;
5

6

7
Main:
8
  uint16_t x=counter; // oder x=IVAR(counter), wenn counter nicht volatile
9
  print_uint16(x);

Denkbare Ausgabe:
... 0x00FF, 0x0000, 0x0101, ...

oder
... 0x00FF, 0x01FF, 0x0101, ...

Einfach weil während dem umkopieren von counter in x ein Interrupt 
auftreten kann (erstes Byte kopiert, ISR verändert beide, zweites Byte 
kopiert)


Lösung:
interrupts zwischendurch abschalten.
#include <util/atomic.h> hat dafür passende Makros.
#2412465
Lesenswert?

Stefan Ernst schrieb:
> Und was bitte hat das jetzt mit volatile und dem Makro zu tun?

Nichts. Außer das Programmieranfängern hier im Zusammenhang mit ISRs 
immer sofort "volatile","volatile","volatile" an den Kopf geworfen wird, 
als wäre es die Allheillösung. Ist es nicht. Es ist Anfängern nur 
leichter zu erklären, und macht im einfachen Fall (Flag in ISR setzen, 
in main auswerten) ja auch das richtige.
#2412481
Lesenswert?

Εrnst B✶ schrieb:
> Nichts. Ausser das Programmieranfängern hier im Zusammenhang mit ISRs
> immer sofort "volatile","volatile","volatile" an den Kopf geworfen wird,
> als wäre es die Allheillösung. Ist es nicht. Es ist Anfängern nur
> leichter zu erklären.

Und warum folgt daraus jetzt, dass das Makro bei Variablen größer als 8 
Bit nicht funktioniert?

Einziger Zweck des Makros ist es, den Zugriff auf eine Variable volatile 
zu machen, ohne dass die Variable selbst global volatile sein muss. 
Niemand hat behauptet, dass der Zugriff damit auch automatisch atomar 
wäre, oder dass das Thema "atomarer Zugriff" bei Verwendung des Makros 
nicht beachtet zu werden braucht.

"Dein Auto ist kaputt!"
"Ja? Wieso, was ist denn damit?"
"Es kann nicht fliegen."
Gast #2412484
Lesenswert?

Εrnst B✶ schrieb:
> Es ist Anfängern nur
> leichter zu erklären,

Das ist erstens falsch, und zweitens auch...

Es gibt beim Zusammenspiel von ISR's mit dem Restprogramm zwei Probleme 
zu lösen. Das eine löst volatile, das andere atomic. Die Probleme (und 
auch die Lösungen) haben nichts miteinander zu tun, und sind einzeln 
oder auch kombiniert anzuwenden.

Oliver
#2412524
Lesenswert?

Stefan Ernst schrieb:
> "Dein Auto ist kaputt!"
> "Ja? Wieso, was ist denn damit?"
> "Es kann nicht fliegen."

Typisches "Beratungsgespräch" hier im Forum:
"Ich hab da eine ISR ...."
"mach Volatile"
"Ich hab da eine ISR und volatile"
"mach Volatile"
"hab ich doch schon"
"erm.... mach noch mehr Volatile, Alle variablen"
"Häh?"
"und schalt die Optimierung aus!"
"Huh? Aber ich will doch nur meinen 16Bit-Zähler aus der ISR 
verwenden..."

Stefan Ernst schrieb:
> Einziger Zweck des Makros ist es, den Zugriff auf eine Variable volatile
> zu machen, ohne dass die Variable selbst global volatile sein muss.

Dafür ist es ja gut und toll. Aber man sollte darauf hinweisen, dass es 
eben bei 16Bit-Variablen nicht für atomaren Zugriff sorgt, und es 
deswegen nicht alleine zur Lösung aller Interrupt-Sorgen führt.

Was im Gegensatz dazu die ATOMIC_BLOCK-Makros wesentlich besser 
erreichen, denn da wird beim "cli"/"sei" per Memory-Barrier ebenfalls 
ein neu-laden der Variable aus dem Ram erzwungen, und das volatile somit 
in fast allen Fällen überflüssig.
#2413481
Lesenswert?

wie weiter oben beschrieben MUSS eine Varaible, die in einem anderen 
Kontext (aka ISR) verwendet wird, volatile sein.

Der Compiler denkt dass im obigen Beispiel in der main nie schreibend 
auf counter zugegriffen wird. Und folglich wird er den Zugriff bei 
Optimierung auch einsparen - er "kennt" ja den Wert.

volatile erzwingt das das erneute Lesen aus der globalen Variable.
Egal, ob der Interrupt ein- oder ausgeschaltet ist.

probier doch mal aus:
uint16_t counter;
ISR:
counter++;
main:
counter = 0;
while(counter > 100)
{
  counter = 0;
}

Ohne Optimierung steht der Code noch im erzeugten Object-File. Aber mit 
Optimierung (-Os) wird der Code der while Schleife "brutal" gelöscht - 
weil die Bedingung sonst nie erfüllt worden wäre.

Adib.
#2413513
Lesenswert?

Atomic und Volatile sind 2 völlig verschiedenen Dinge.
Ihre einzige Gemeinsamkeit ist, daß beide in Zusammenhang mit Interrupts 
auftreten können.

Meistens macht das Atomic auch implizit ein Volatile.
Aber allein es kann Nachteile bezüglich der Laufzeit haben.
Es macht schon einen Unterschied, ob eine Interruptsperre 6 Zyklen 
dauert oder über 1000 Zyklen:
1
#include <util/atomic.h>
2

3
#define IVAR(x)         (*(volatile typeof(x)*)&(x))
4

5
uint16_t foo;
6

7
void test( float fval )
8
{
9
  uint16_t val;
10
  
11
  val = fval / 123.4;
12
  ATOMIC_BLOCK(ATOMIC_FORCEON){
13
    foo = val;
14
  }
15
}
16

17
void test1( float fval )
18
{
19
  uint16_t val;
20
  
21
  val = fval / 123.4;
22
  ATOMIC_BLOCK(ATOMIC_FORCEON){
23
    IVAR(foo) = val;
24
  }
25
}


Peter
Angehängte Dateien:
#2416005
Lesenswert?

Oliver schrieb:
> Es gibt beim Zusammenspiel von ISR's mit dem Restprogramm zwei Probleme
> zu lösen. Das eine löst volatile, das andere atomic. Die Probleme (und
> auch die Lösungen) haben nichts miteinander zu tun, und sind einzeln
> oder auch kombiniert anzuwenden.

Für einen ambitionierter Anfänger, der sich hier auf den Seiten bewegt, 
ist es nicht einfach, diese beiden Probleme auseinander zu halten. 
Wahrscheinlich wurde schon zu viel darüber geschrieben. Wo findet man 
die anfängertauglichen Merksätze "volatile muss man verwenden, wenn...", 
"Interruptsperren muss man wegen nicht atomarer Zugriffe sperren, 
wenn..."?

Ich habe mir das wie folgt zusammengereimt. Bin mir aber nicht sicher 
und bitte um Verbesserung:

------------------------------------------------------------------------ 
---
Globale Variablen, die innerhalb einer ISR und auch vom übrigen Programm 
verwendet werden, müssen als volatile gekennzeichnet werden.

Bei Zugriff und Veränderung von Variablen und Registern, die
- sowohl in einer ISR als auch im übrigen Programm verwendet werden
- und mehrere MC-Takte brauchen,
müssen Interrupts gesperrt werden. Wenn der MC keine verschachtelten 
Interrupts zulässt, sind diese Interruptsperren nur im übrigen Programm 
und nicht in den ISRn notwendig.
Persönliche Seite #2424517
Lesenswert?

Peter Dannegger schrieb:

> Es macht schon einen Unterschied, ob eine Interruptsperre 6 Zyklen
> dauert oder über 1000 Zyklen:

Aber nicht mit zweierlei Maß messen, gell?
1
#include <util/atomic.h>
2

3
#define IVAR(x)         (*(volatile typeof(x)*)&(x))
4

5
uint16_t foo;
6
uint16_t volatile vfoo;
7

8
void test( float fval )
9
{
10
  uint16_t val;
11
  
12
  val = fval / 123.4;
13
  ATOMIC_BLOCK(ATOMIC_FORCEON){
14
    vfoo = val;
15
  }
16
}
17

18
void test1( float fval )
19
{
20
  uint16_t val;
21
  
22
  val = fval / 123.4;
23
  ATOMIC_BLOCK(ATOMIC_FORCEON){
24
    IVAR(foo) = val;
25
  }
26
}

...und nochmal vergleichen ;-)

Zumindest mit 4.3, 4.5, 4.6 und 4.7 sehe ich identische Ergebnisse.
#2424663
Lesenswert?

Johann L. schrieb:
> Aber nicht mit zweierlei Maß messen, gell?

Es ging darum, daß Atomic auch automatisch Volatile ersetzt.
Und mein Beispiel zeigt, das tut es nicht.

Da Du nun gleich die Variable volatile machst, ist logisch, daß dann der 
Code zum volatile-Cast identisch sein muß.

Ich benutze lieber den Cast.
Dann kann der Interrupt optimieren und im Main sehe ich sofort, daß es 
sich um eine Interruptvariable handelt.


Peter
Persönliche Seite #2424849
Lesenswert?

Εrnst B✶ schrieb:
> Stefan Ernst schrieb:
>> Einziger Zweck des Makros ist es, den Zugriff auf eine Variable volatile
>> zu machen, ohne dass die Variable selbst global volatile sein muss.
>
> Dafür ist es ja gut und toll. Aber man sollte darauf hinweisen, dass es
> eben bei 16Bit-Variablen nicht für atomaren Zugriff sorgt, und es
> deswegen nicht alleine zur Lösung aller Interrupt-Sorgen führt.

Achtung: Es sorgt bei 8-Bit Variablen auch nicht (unbedingt) für 
atomaren Zugriff!. Es ist eine völlig andere Baustelle. Nämlich die, 
dass der Variablenzugriff nicht wegoptimiert wird.

> Was im Gegensatz dazu die ATOMIC_BLOCK-Makros wesentlich besser
> erreichen, denn da wird beim "cli"/"sei" per Memory-Barrier ebenfalls
> ein neu-laden der Variable aus dem Ram erzwungen, und das volatile somit
> in fast allen Fällen überflüssig.

Das halte ich für eine SEHR gewagte These. Der ATOMIC_BLOCK sorgt mit 
Sicherheit nicht für das Neu-Laden einer Variable innerhalb dieses 
Blockes!

Du darfst die beiden Probleme nicht miteinander vertauschen. Das sind 
(wie schon mehrfach erwähnt) zwei verschieden Probleme und manchmal ist 
es nötig, dass beides angewendet wird. Um Atomizität herzustellen und 
gleichzeitig das Wegoptimieren eines Variablenzugriffes zu verhindern.
Persönliche Seite #2424852
Lesenswert?

Peter Dannegger schrieb:
> Johann L. schrieb:
>> Aber nicht mit zweierlei Maß messen, gell?
>
> Es ging darum, daß Atomic auch automatisch Volatile ersetzt.

Nein, atomic ersetzt nicht volatile und auch nicht umgekehrt.

> Und mein Beispiel zeigt, das tut es nicht.
>
> Da Du nun gleich die Variable volatile machst, ist logisch, daß dann der
> Code zum volatile-Cast identisch sein muß.

> [...] und im Main sehe ich sofort, daß es
> sich um eine Interruptvariable handelt.

Wenn es darum geht, den eigenen Code zu verstehen, sind manchmal auch 
Kommentare dienlich ;-)
Gast #2425018
Lesenswert?

Hallo,

das geht aber am eigentlichen Thema vorbei. Das Problem waren ja Fehler 
beim Compilieren von aus Studio 4 in Studio 5 übernommenen Code.

Was mir fehlt ist eine Aussage wie der Code von 4 nach 5 gekommen ist.

Ich habe da andere Erfahrungen. Ich musste AVR Studio 5 einsetzen, weil 
Studio 4 und WINAVR nicht unter Win7 zum laufen zu kriegen waren. Ich 
habe alle Projekte (>100) und 90% davon mit UART-Funktion in Studio 5 
über die Import-Funktion nach Studio 5 konvertiert. Alle Projekte ließen 
sich auf Anhieb kompilieren und liefen auch in der Schaltung so wie sie 
sollten.
#2425036
Lesenswert?

tobi schrieb:
> Hallo,
>
> das geht aber am eigentlichen Thema vorbei. Das Problem waren ja Fehler
> beim Compilieren von aus Studio 4 in Studio 5 übernommenen Code.

Jein.
Das 'Problem' sind erst mal unterschiedliche Compilerversionen bzw. 
Einstellungen in der Commandline des Compileraufrufes.

Die sind insofern ein 'Problem', weil eine neuere Compilerversion oft 
pingeliger ist und Dinge anmerkt, die die alte Version durchgehen liess. 
Das bedeutet nicht automatisch, dass der geschriebene Code in der 
vorhergehenden Version korrekt gewesen wäre. Es bedeutet lediglich, dass 
der Compiler damals noch nicht die notwendigen Tests mit hatte um diese 
Problemkreise zu erkennen.

D.h. die 'Fehler' waren auch vorher schon drinnen, nur sind sie vom 
Compiler nicht angemerkt worden. Und die letzte Compilerversion (bze. 
die geänderten Command line Argumente) tun das eben.

> über die Import-Funktion nach Studio 5 konvertiert. Alle Projekte ließen
> sich auf Anhieb kompilieren und liefen auch in der Schaltung so wie sie
> sollten.

Und so sollte es auch sein, wenn man qualitativ guten C Code schreibt.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren