Moin zusammen,
irgendwie habe ich ein ziemlich seltsames Problem bei einem Programm für
einen ATMega16, an dem ich gerade bastele.
Ich habe auf PINA0 und PINA1 jeweils einen Schalter, der mir den Eingang
nach Masse zieht, sowie externe Pull-Ups. Die Pins sind als Eingänge
geschaltet.
Ich verwende folgende Struktur (aufs Notwendige reduziert), um die
Eingänge auszuwerten:
1
// Am Anfang von main
2
volatileunsignedcharprog;
3
4
//...
5
// (im Main-Loop)
6
prog=PINA&0x03;
7
switch(prog)
8
{
9
case3:
10
break;
11
case2:
12
break;
13
case1:
14
break;
15
case0:
16
break;
17
}
Gehe ich jetzt über den JTAG-Debugger drauf, hat die Variable prog immer
den richtigen Wert, abhängig von den externen Schalterstellungen. Bis
dahin kommt also alles wie es soll, Hardware und Software sind also an
sich korrekt.
Allerdings wird das switch-Statement nicht ausgeführt, solange ich eine
Optimierungsstufe ungleich 0 ausgewählt habe. Einen passenden Zweig gibt
es, mehr als vier Möglichkeiten habe ich bei zwei Bit ja nicht. Bei -O0
läuft alles, bei allen anderen Optimierungsstufen nicht. Wenn ich im
Debugger als aktuelle Anweisung das switch-Statement habe, und per
Einzelschritt weiterspringe, komme ich wieder auf das switch-Statement,
als hätte ich keinen passenden Zweig.
Syntaktisch korrekt muß aber alles sein, sonst würde es mit -O0 ja nicht
funktionieren.
Kennt jemand dieses in meinen laienhaften Augen seltsame Verhalten des
Compilers? Habe ich ein Brett vor'm Kopf? Hilfe... Ich habe zwar genug
Platz, mit unoptimiertem Code zu arbeiten, aber ich wüßte doch gerne,
warum der so tut wie er tut.
Zur Ausstattung auf meinem Entwicklungs-PC: Jeweils die aktuellsten
Fassungen von AVR-Studio und WinAVR, die Platine mit dem µC ist über
einen JTAGICE mkII von Atmel angebunden.
Wenn mir jemand helfen kann, soll ihn mein Dank ewiglich verfolgen. ;-)
Ich bin zwar kein Assemblertyp, aber vielleicht hilft Dir in diesem -
für mich auch seltsamen Fall - einfach mal ein Vergleich der
lss-Dateien!?
Erstelle doch einfach mal mit 2 Optimierungsstufen (0 und beliebig) die
hex-Datei und vergleiche dann die jeweiligen Stellen in den lss-Dateien.
Vielleicht findest Du mit denen was raus?
Viel Glück :-)
Füge doch einmal eine "default"-Klausel ein und schau nach, welchen Wert
"prog" annimmt. Ansonsten müßtest Du schon mehr von Deinem Code zeigen,
evtl. könntest Du Dir generierten Assembler-Code anschauen, der bei
-O1..3 herauskommt.
Murkser
Ob ich default mit drin habe oder nicht, macht keinen Unterschied, auf
die Idee war ich auch schon gekommen.
Viel mehr Code gibt es nicht zu zeigen, ich habe eigentlich nur das
Mainloop-Konstrukt weggelassen und die Inhalte der einzelnen
Case-Blöcke. Zwischen der Zuweisung und dem Switch steht nichts, davor
nur ein do { und nach dem Switch-Block ein } while(1);. Die Inhalte der
einzelnen Case-Zweige sind ja dafür erstmal nicht relevant.
Die Assemblergeschichten nutzen mir leider recht wenig, wenn ich ehrlich
bin, verstehe ich da nur Bahnhof. :(
Eike S. schrieb:> Die Inhalte der> einzelnen Case-Zweige sind ja dafür erstmal nicht relevant.
Es sei denn, der Compiler hält den Inhalt für überflüssig.
Innerhalb der einzelnen Case-Blöcke weise ich verschiedene Variablen zu,
die an anderer Stelle (ISR vom Timer) ausgewertet werden. Außerdem setze
ich ein paar Ausgänge in direkter Abhängigkeit von den Eingängen. Selbst
wenn also die Variablen (wieso auch immer) wegoptimiert würden,
spätestens das Setzen der Ausgänge sollte ja eigentlich nicht
wegoptimiert werden können.
Nachtrag: Compilerwarnungen sind eingeschaltet, und Warnungen wegen
ungenutzter Variablen bekommen ich keine.
Eike S. schrieb:> Innerhalb der einzelnen Case-Blöcke weise ich verschiedene Variablen zu,> die an anderer Stelle (ISR vom Timer) ausgewertet werden. Außerdem setze> ich ein paar Ausgänge in direkter Abhängigkeit von den Eingängen. Selbst> wenn also die Variablen (wieso auch immer) wegoptimiert würden,> spätestens das Setzen der Ausgänge sollte ja eigentlich nicht> wegoptimiert werden können.
Werden die Ausgänge denn wirklich anders gesetzt als ohne Optimierung,
oder ist dein Problem einfach nur, dass du mit dem Debugger den Code
nicht vernünftig singlesteppen kannst? Falls nur letzteres: das kommt
mit Optimierung schonmal vor, da muss man mit leben ;-)
Andreas
Moin,
wenn Du im main nur Zuweisungen zu Variablen durchführst die "nur" in
der ISR genutzt/verändert werden, dann solltest du die mit volatile
definieren, da sonst der Optimierer hier voll zuschlägt und alles
wegschmeisst was nicht innerhalb des gleichen Scopes verwendet wird, da
er sich denkt, dass das Ergebnis ja keiner braucht.
Das passiert in die Gegenrichtung genauso. Eine Variable die in der ISR,
nur gesetzt/verändert aber sonst dort an keiner weiteren Stelle
verwendet wird, wird gnadenlos ignoriert. Und im Debugger funktionierts,
das ist das Tolle daran.
Beispiel:
1
volatileuint16_tcounter;
damit passiert kein Unsinn wenn counter in der ISR verändert, aber nur
im main abgefragt wird.
Eike S. schrieb:> Wenn ich im> Debugger als aktuelle Anweisung das switch-Statement habe, und per> Einzelschritt weiterspringe, komme ich wieder auf das switch-Statement,> als hätte ich keinen passenden Zweig.
Was genau funktioniert denn nicht? Werden denn die Ausgänge richtig
gesetzt, wenn du das Programm durchlaufen lässt?
Das der Debugger bei eingeschalteter Optimierung ziemlich planlos durch
das Programm hüpft, ist normal. Das optimierte Programm hat vermutlich
nicht mehr viel mit dem Sourcecode zu tun, da sieht man dann komische
Sachen.
Oliver
Erstmal vielen Dank an alle, die selbst zu nachtschlafender Zeit hier
geantwortet haben! Doch im Einzelnen:
Andreas Ferber schrieb:> Werden die Ausgänge denn wirklich anders gesetzt als ohne Optimierung,> oder ist dein Problem einfach nur, dass du mit dem Debugger den Code> nicht vernünftig singlesteppen kannst? Falls nur letzteres: das kommt> mit Optimierung schonmal vor, da muss man mit leben ;-)
Nee, die Ausgänge werden auch nicht gesetzt. Ohne das Debugger-Wissen,
daß die Eingänge korrekt gelesen werden, hätte ich zuerst auf einen
Fehler der Eingangsbeschaltung/-Konfiguration getippt. Bei
eingeschaltetem Optimizer passiert nach außen hin sichtbar nichts. Es
ist also nicht nur das Problem, nicht singlesteppen zu können.
bob schrieb:> wenn Du im main nur Zuweisungen zu Variablen durchführst die "nur" in> der ISR genutzt/verändert werden, dann solltest du die mit volatile> definieren, da sonst der Optimierer hier voll zuschlägt und alles> wegschmeisst was nicht innerhalb des gleichen Scopes verwendet wird, da> er sich denkt, dass das Ergebnis ja keiner braucht.
Danke, so weit war ich auch schon - nur spätestens beim Hardwarezugriff,
beim Schreiben eines I/O-Registers, da darf doch nichts wegoptimiert
werden. Der geschriebene Wert ist zwar eine Konstante, aber diese ist
abhängig von jeweils durchlaufenen Case-Zweig.
Oliver schrieb:> Was genau funktioniert denn nicht? Werden denn die Ausgänge richtig> gesetzt, wenn du das Programm durchlaufen lässt?
Nein.
> Das der Debugger bei eingeschalteter Optimierung ziemlich planlos durch> das Programm hüpft, ist normal. Das optimierte Programm hat vermutlich> nicht mehr viel mit dem Sourcecode zu tun, da sieht man dann komische> Sachen.
Das Problem hatte ich schon öfter, das würde mich nicht wundern. Wie ich
schon auf einen anderen Post antwortete, es passiert rein gar nichts,
wenn die Optimierung an ist.
Poste doch mal Deine lss-Files (einmal ohne, einmal mit Optimierung).
Auch wenn Du/wir nicht viel damit anfangen kannst/können - evtl. sieht
ja ein anderer den Grund