hab vergessen die optimierung nach fehlersuche wieder anzuschalten und
so weiter programmiert.. nun läuft das prog. nicht mehr bei aktiver
Optim.
folgender code:
1
while(!ReadExtDevice(A))
2
{
3
;// wait until dev. ready
4
}
5
// now dev. ready
quasi eine "warteschleife" die funktion ReadExtDevice liest nur von
einem beliebigen Baustein einen wert.
wird soetwas rausoptimiert / verändert ?
für den compiler müsste ja das return der funktion konstant bzw. auch
das dort in der funktion gelesene konstant sein- oder ? "er" weiß ja
nicht das
"jemand" externes da was dran ändert.
Wo ist denn die Funktion ReadExtDevice definiert?
Wenn der Compiler an der Stelle, wo die Funktion gebraucht wird, den
Sourcecode für die Funktion kennt, kann er den Code auch inline
einsetzen.
Und wenn Du dann IN der Funktion einen Fehler hast, z.B. wenn
ReadExtDevice aus einer Speicherstelle liest, die NICHT volatile
deklariert ist, dann hast Du die Schleife wegoptimiert....
hmm .. ReadExtDevice ist in einem anderen src-file definiert . aber im
aktuellen file bekannt (prototyp).
mein problem ist, dass ich ziehmlich viel code zusammengeschrieben
(+getestet) hab mit deaktivierter Optimierung.
also u.U. hängt es an mehreren stellen - da muss ich jetzt durch und
nochmal alles angucken.
müsste überprüfen ob Variablen die in ISRn benutzt werden volatile sind
und ob While-Schleifen vorhanden sind die intern nix machen.
wär das ca. richtig zusammengefasst ??
>> muss ja nun nach irgendwas suchen ..
evtl. jemand noch andere Idee auf was ich acht geben sollte // auf was
die Optimierung irgendwie einfluss nimmt.
was ist wenn ISR wiederum funktionen aufrufen - die dort geänderten
variablen müssten dann auch volatile sein oder ?
hab gerade was gelesen das u.U. auch nicht-volatile variablen o. auch
schleifen wegoptimiert werden können wenn die variablen oder in den
schleifen benutzen variablen verändert werden, aber diese nie geprüft
werden.
Prinzipiell kann ein Compiler alles wegoptimieren, was nicht benutzt
wird oder von dem er ausgeht, daß es überflüssig ist.
C hat keine Vorstellung von Interrupts. Ein Compiler kann also immer
davon ausgehen, daß eine Variable den Wert hat den er innerhalb des
Progammflusses hineingeschrieben hat.
Wenn sich also von Geisterhand irgendwelche Werte ändern können (zB
durch eine ISR, die bekanntlich nicht im momentanen Programmfluss
dargestellt ist) dann muss man das kennzeichnen.
D.h. entsprechende Objekte/Zugriffe müssen volatile sein, oder man baut
eine Barrier ein, über die zB gcc keine Speicherinhalte wegoptimieren
kann.
hi ..
merkwürdiges problem gefunden !
also .. bin immernoch beim suchen der Fehlerquellen - das mein prog.
mit eingeschalteter optimierung funktioniert.
das Prog. bedient u.A. eine externe UART ( RS232) .
so nun hab ich mir mal ausgeben lassen ( direkt in der ISR) was die denn
so empfängt:
bei ausgeschalteter Opt. : alles OK
bei eingeschalteter Opt. : die zeichen nach der ersten Position immer
fehlerhaft
Errors: framing Error + parity Error
senden geht in beiden Modi!
nun kann es ja nur sein das bei der optimierung irgendetwas in der
UART_initalisierung schief läuft. ( wie gesagt bei ausgeschalteter
Opt. funktionier ja alles) .
kann mir nicht mehr weiterhelfen ..
@ johann du sagtest was von bereichen wo der Compiler nicht optimiert:
wie geb ich sowas an?
in der init. wird ja nix weiter gemacht als über pointer diverse werte
in Register der UART geschrieben ( Über externes Memory Interface)
normalerweise wird doch da nix wegoptimiert !?
es ist echt so ...
hab jetzt mal die UART- initialisierung ausgegeben :
Teil aus UART_Init
1
// Set ModeRegisters
2
PtrOffBUart1[D_SCC_MR1A]=0x13;// 8 bit, no parity
3
PtrOffBUart1[D_SCC_MR2A]=0x07;// standard operation, 1 stop bit
4
//Readout ModeRegister values
5
PtrOffBUart1[D_SCC_CRA]=0x1A;// resets MR-Pointer to MR1
6
VolDummy++;VolDummy++;VolDummy++;VolDummy++;
7
testOut[0]=PtrOffBUart1[D_SCC_MR1A];
8
testOut[1]=PtrOffBUart1[D_SCC_MR2A];
ERLÄUTERUNG: PtrOffBUart1[D_SCC_CRA] = 0x1A; >> setzt nur den UART
internen Pointer auf das erste Register zurück, MR1A und MR2A sind unter
der gleichen BUS-Adresse erreichbar.
ist quatsch jetzt hier den ganzen code zu posten..
also nur mal beispiel
bei deaktivierter Opt. bekomme ich die richtigen Werte ( 0x13, 0x07 )
zurück.
bei aktivierter Opt. kommt 0x07, 0x07 zurück.
wie gesagt liegt das UART_device am ext. Memoryinterface eines
ATMEGA2561 -- die zugriffszeit hab ich auf maximal gestellt - daran
kann es doch nicht liegen/ interessiert die Opt. ja nicht !
muss ich evtl. die Pointer zu den Registern der Externen Devices auch
auf volatile stellen ??? ich mein der Compiler könnte ja auch
denken - dort werden einmalig werte geschrieben die nie geprüft
werden ...
ich komm hier langsam nicht mehr klar ... bitte helft mir !!
Ich seh immer noch nicht was abgeht...
Ist D_SCC_MR1A ein Makro? Auf was? Eine globale Variable? Wie
deklariert?
Wenn die Busadresse gleich ist, dann ist also D_SCC_MR1A=D_SCC_MR2A?
In letzterem Falle kann gcc optimieren, falls PtrOffBUart1[] nicht
volatile ist, was aber auch nicht ersichtlich ist...
hubi wrote:
> muss ich evtl. die Pointer zu den Registern der Externen Devices auch> auf volatile stellen ?
Selbstverständlich! Geräteregister sind der klassische Fall für
volatile (und die ganzen IO-Register des AVR selbst sind ja letztlich
auch nichts anderes als irgendwelche Adressen im Speicherbereich).
Mir ist nicht klar, warum der Zeiger auf die UART-Register im externen
RAM volatile sein soll, im Gegensatz zu den Inhalten der dadurch
adressierten Speicherstellen.
Ich meine, die Adresse ändert sich ja nicht, sondern der Inhalt.
Mir scheint, wenn ich z.B. mit
1
chara;
eine Variable anlege, dann würde mit
1
volatilechara;
eine mögliche Veränderung des Inhaltes berücksichtigt.
Wenn ich aber
1
volatilechar*b;
schreibe, dann bezieht sich das doch auf den Zeiger und nicht auf den
Inhalt.
Mir scheint, als wenn ich eher den Variablen (im Linker- bzw. Makefile)
feste (im ext. RAM) gelegene Adressen zuweisen würde und sie im Code als
volatile bezeichnen sollte.
Könntet Ihr das bitte mal erläutern?
Auweia wrote:
> dann bezieht sich das doch auf den Zeiger und nicht auf den> Inhalt.
Nein. Das wäre der Fall bei
char * volatile b.
oder
typedef char * char_ptr;
volatile char_ptr b;
> schreibe, dann bezieht sich das doch auf den Zeiger und nicht auf den> Inhalt.
Nein. Die Deklaration legt einen Zeiger mit dem Namen b auf ein Objekt
vom Typ volatile char an. Der Zeiger selbst ist nicht volatile! Wenn
der Zeiger auch volatile sein soll, dann müsste es
Danke Johannes.
D.h. also, der Unterschied zwischen
1
volatilechara;
und
1
volatilechar*b;
ist, das b eben ein Zeiger ist und a nicht, aber bzgl. der volatile
Eigenschaft sind beide gleich, oder, anders ausgedrück:
Beiden ist gemeinsam, das sie sich auf volatile Daten a bzw. *b
beziehen.
Korrekt?
Kleiner Tip zum Verständnis von C Deklarationen: Nicht einfach von links
nach rechts lesen, sondern ausgehend vom Variablennamen von innen nach
aussen entsprechende der Prioritäten auflösen.
So löst sich auch zwanglos die bei Anfängern beliebte Verwirrung um
char *a[]; //= array of ptr to char
char (*a)[]; //= ptr to array of char
Und hier eben:
char *volatile p;
als
p
*volatile
char
lesen, demgegenüber
volatile char *p;
als
p
*
volatile char
Das sieht insbesondere deshalb so scheusslich aus, weil "const" und
"volatile" erst später hinzugeführt wurden, aber sich syntaktisch nicht
mehr elegant einfügen liessen (zur Übung die exquisite Scheusslichkeit
"char volatile * const a[] const;").
so UARTs gehen alle ..
jetzt bei dem code für ethernetInterface da gehts teilweise mit -O2
und mit -03 garnicht.
gibts nicht irgendwo ne liste / manual zum (avr-)gcc wo drinn steht
was der so alles anfässt bei den verschieden Optimierungsstufen ???
das man ein paar anhaltspunkte hat wo man aufpassen muss .
sowas wär echt klasse !!
hut und helm wrote:
> gibts nicht irgendwo ne liste / manual zum (avr-)gcc wo drinn steht> was der so alles anfässt bei den verschieden Optimierungsstufen ???
Steht merkwürdigerweise im Manual vom GCC drin. Also welcher -O Level
welche Optimierungsoptionen impliziert, und dort dann jeweils was die
bewirken.
> das man ein paar anhaltspunkte hat wo man aufpassen muss .> sowas wär echt klasse !!
Falscher Ansatz. Besser wär's, sich nach der Sprache C zu richten, und
nicht nach dem was der verwendete Compiler je nach Optimierungsgrad an
Programmierfehlern noch durchgehen lässt.
>Falscher Ansatz.
Das meine ich auch. Allerdings wäre es für Dich, Hubi, vielleicht
hilfreich mal ein paar Tips zu kriegen woran es denn liegen könnte. Denn
aus den Optimierungen zu schliessen was denn am Code falsch ist, kann um
einiges schwieriger sein als richtigen Code zu schreiben. ;-)
Dafür empfiehlt sich dann Lint.
Z.B.
# Splint — an open source evolved version of Lint (C language).
Gibt natürlich noch kommerzielle Lösungen wie PCLint.
Und hilfreich könnte auch
# Cppcheck — a tool that can find memory leaks, buffer overruns and many
other common errors.
sein.
Ob aber Lint oder seine Varianten ein fehlendes volatile erkennen?
Für den vorliegenden Fall "Programm läuft nur ohne Optimierung" gibt es
doch beim avr-gcc gar nicht so viele mögliche Ursachen. Ein fehlendes
"volatile" dürfte zu 99,99999% die Ursache sein. Früher (so zu Zeiten
von Turbo-C o.ä.) gab es noch den Effekt, daß (lokale?) Variablen ohne
Optimierung mit Null vorbelegt, mit aber undefiniert waren. Das ist aber
Geschichte.
Fällt jemandem sonst noch was ein?
Und die Kenntnis darüber, was der gcc genau bei den einzelnen
Optimierungsstufen anstellt, braucht man nur, wenn es um extrem
kritische timings oder um das letzte freie Byte im Flash geht.
Oliver
Nicht ganz so viele Neuner. Compiler-Fehler waren auch schon dabei. Die
Frühjahrs-Version von WinAVR hatte in dieser Hinsicht einen recht
holprigen Start und die Linux-Fraktion ist bis heute etwas gekniffen.