mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Compiler Optimierung macht Probleme


Autor: Phil (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute.

Ich habe momentan ein Problem mit meinem Code. Es soll eine LED über 
eine Geradengleichung gedimmt werden. Es funktioniert aber nicht und ich 
weiß nicht wieso. Hab schon nen Debugger rangehangen, aber da ich mich 
damit (noch) nicht so auskenne hilft mir das nicht weiter.

Ich vermute es liegt unter anderem an der Optimierung. Jene kann ich 
aber nicht ausstellen, da sonst der Code zu groß ist. Die Variable 
"zaehler" ist immer "out of scope".

Als Anmerkung sei gesagt, dass "sek" in einer ISR sekündlich hochgezählt 
wird.

Es wäre schön, wenn einer ne Idee hat :-)

Hier mal der Codeausschnitt:
//globale Variablen
volatile uint8_t sek = 0, abschnitt = 0;
uint8_t intervalle_werte[7] PROGMEM = {0, 100, 255, 100, 150, 100, 50}; //gibt die Stützstellen der y-Werte (Helligkeit) an
uint16_t intervalle_t[7] PROGMEM = {0, 5, 10, 15, 33, 37, 60};  // gibt die Stützstellen der x-Werte (Zeit) an

// Zeit lesen
void get_time(void) {
volatile uint8_t i;
  for(i = 0; i < 7; i++) {
    if ( sek < intervalle_t[i]) {
    abschnitt = i;
    break;
    }
  }
}

// Wert lesen und übergeben
uint8_t get_value(void) {

  get_time();

volatile int16_t ergebnis;            // ergebnis = ( (zaehler/nenner) / 1000 ) + n
volatile uint16_t nenner,zeit;        
volatile int32_t zaehler;
volatile int16_t n;

  zeit = sek - intervalle_t[abschnitt-1];
  zaehler = (intervalle_werte [abschnitt] - intervalle_werte [abschnitt - 1]) * (int32_t)1000 * zeit;
  nenner = (intervalle_t[abschnitt] - intervalle_t[abschnitt - 1]);
  n = intervalle_werte[abschnitt - 1] + Verschiebung;
  ergebnis= ((zaehler / nenner) / 1000) + n;
  OCR1A = pgm_read_word(&pwmtable[result]);

  return ergebnis;
}

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>  OCR1A = pgm_read_word(&pwmtable[*result*]);

Woher kommt result ???

Da musst Du schon ein bisschen mehr Code posten um etwas nachvollziehen 
zu können....

Autor: g457 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> uint16_t intervalle_t[7] PROGMEM [..]

> if ( sek < intervalle_t[i]) {
             ^
das (und sämtliche andere Zugriffe auf den PROGMEM) dürfte so nicht 
funktionieren wie erwartet -> pgm_read_*()

..weiter hab ichs mir noch nicht angesehen..

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was sollen denn diese ganzen volatiles für lokale Variablen? Ist dir die 
CPU zu schnell?

Autor: Phil (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter schrieb:
> Woher kommt result ???

Es muss natürlich Ergebnis heißen.

g457 schrieb:
> das (und sämtliche andere Zugriffe auf den PROGMEM) dürfte so nicht
>
> funktionieren wie erwartet -> pgm_read_*()

Das hab ich gerade gesehen und bin dabei es zu ändern.

A. K. schrieb:
> Was sollen denn diese ganzen volatiles für lokale Variablen

Wenn ich die Variablen nicht volatile hatte wurden sie vom Compiler 
wegveroptimiert. Zumindest waren sie "out of scop" auch innerhalb der 
fkt.

Ich änder gerad den Code nochmal um und wenn ich nicht weiter weiß poste 
ich ihn wieder :-)

Danke schonmal. Das mit dem progmem hab ich nicht gesehen... Wenn man 
das ganze Woche mit C# rummacht vergisst man sowas ganz schnelle -.-

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Es funktioniert aber nicht und ich weiß nicht wieso.
Du hast einen Wissensvorsprung, denn immerhin weißt du schon mal,
WAS nicht funktioniert... :-o

Autor: ... ... (docean) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
du weißt aber das du die Helligkeit und Storm/Spannung nicht linear 
zusammenhängen?

siehe auch http://www.mikrocontroller.net/articles/LED-Fading

Autor: Εrnst B✶ (ernst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hier ein Code-Schnippsel, der was ähnliches macht:
// ggfs unterschiedliche calibration-arrays für R,G,B-LEDs...
// oder nur eines für alles...
prog_uint8_t led_calibration[]= {
0,0,
50,10,
100,30,
150,80,
200,140,
0xFF,0xFF
};

uint8_t get_calibration(prog_uint8_t data[], uint8_t value) {
  uint8_t low_pos;
  uint8_t low_val;
  uint8_t high_pos;
  uint8_t high_val;
  while (pgm_read_byte(&data[2])<value) {
    data+=2;
  } 
  low_pos=pgm_read_byte(&data[0]);
  low_val=pgm_read_byte(&data[1]);
  high_pos=pgm_read_byte(&data[2]);
  high_val=pgm_read_byte(&data[3]);
  high_val-=low_val;
  high_pos-=low_pos;
  value-=low_pos;
  return low_val+value*high_val/high_pos;
}

Autor: Phil (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
... ... schrieb:
> du weißt aber das du die Helligkeit und Storm/Spannung nicht linear
>
> zusammenhängen?

deswegen wird doch der Wert zum Schluss durch ein Lookuptable übergeben!

Ich habe den Code wieder aktualisiert und er funktioniert jetzt mit der 
Einschränkung, dass ich nicht weiß, warum die Variable "zaehler" ständig 
"not valid" im AVR Studio angezeigt wird. Liegt es daran, dass es eine 
32bit Variable ist? Habe ich falsch gecastet?

Hier nochmal der aktualisierte Code mit den behobenen Fehlern:
//globale Variablen
volatile uint8_t sek = 0, abschnitt = 0;
volatile int16_t Verschiebung = 0;

uint8_t intervalle_werte[7] PROGMEM = {0, 100, 255, 100, 150, 100, 50}; //gibt die Stützstellen der y-Werte (Helligkeit) an
uint16_t intervalle_t[7] PROGMEM = {0, 5, 10, 15, 33, 37, 60};  // gibt die Stützstellen der x-Werte (Zeit) an

// Zeit lesen
void get_time(void) {
volatile uint8_t i;
  for(i = 0; i < 7; i++) {
    if ( sek < intervalle_t[i]) {
    abschnitt = i;
    break;
    }
  }
}

// Wert lesen und übergeben
uint8_t get_value(void) {

  get_time();

volatile int16_t ergebnis;            // ergebnis = ( (zaehler/nenner) / 1000 ) + n
volatile uint16_t nenner;        
volatile int32_t zaehler;
volatile int16_t n, zeit;

  zeit = sek - pgm_read_word (&intervalle_t[abschnitt-1]);
  zaehler = (pgm_read_byte(&intervalle_werte [abschnitt]) - pgm_read_byte (&intervalle_werte [abschnitt - 1])) * (int32_t)1000 * zeit;
  nenner = (pgm_read_word (&intervalle_t[abschnitt]) - pgm_read_word (&intervalle_t[abschnitt - 1]));
  n = pgm_read_byte (&intervalle_werte[abschnitt - 1]) + Verschiebung;
  ergebnis= ((zaehler / nenner) / 1000) + n;
  OCR1A = pgm_read_word(&pwmtable[result]);

  return ergebnis;
}

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Phil schrieb:

> Ich habe den Code wieder aktualisiert und er funktioniert jetzt mit der
> Einschränkung, dass ich nicht weiß, warum die Variable "zaehler" ständig
> "not valid" im AVR Studio angezeigt wird. Liegt es daran, dass es eine
> 32bit Variable ist? Habe ich falsch gecastet?

Es liegt wahrscheinlich daran, dass du optimierten Code debugst und der 
Optimizer einen Weg gefunden hat, wie er die Variable wegeliminiert.

Wenn du den Optmizer eingeschaltet hast, kann, darf und wird der 
Optimizer den Code umstellen und Variablen entfernen.

Autor: Phil (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und warum sollte man beim Debuggen die Optimierung abschalten?

Ich versteh schon, dass der hier und da ein wenig optimiert. Aber ich 
versteh nicht wie man vorgehen soll wenn der Code wächst und wächst und 
man einfach nicht mehr die Optimierung abschalten kann, weil ebn sonst 
der uc voll ist und sich gar nicht mehr flashen lässt...

Komisch finde ich ja, dass obwohl die Variable volatil ist, der Compiler 
sie wohl TROTZDEM wegoptimiert.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Phil schrieb:
> Und warum sollte man beim Debuggen die Optimierung abschalten?
>
> Ich versteh schon, dass der hier und da ein wenig optimiert.

Nicht hie und da!
Der Optimizer rührt da anständig um!

> Aber ich
> versteh nicht wie man vorgehen soll wenn der Code wächst und wächst und
> man einfach nicht mehr die Optimierung abschalten kann, weil ebn sonst
> der uc voll ist und sich gar nicht mehr flashen lässt...

ev. hilft es, nur Teile des Codes zu optimieren.

> Komisch finde ich ja, dass obwohl die Variable volatil ist, der Compiler
> sie wohl TROTZDEM wegoptimiert.

Da es sich hier um eine Funktionslokale Variable handelt kann der 
Optimizer den kompletten Lebenszyklus der Variablen überblicken.

Ich rate jetzt mal ein wenig.
Wenn der Optimizer den Code so umstellt
  nenner = (pgm_read_word (&intervalle_t[abschnitt]) - pgm_read_word (&intervalle_t[abschnitt - 1]));
  n = pgm_read_byte (&intervalle_werte[abschnitt - 1]) + Verschiebung;
  zaehler = (pgm_read_byte(&intervalle_werte [abschnitt]) - pgm_read_byte (&intervalle_werte [abschnitt - 1])) * (int32_t)1000 * zeit;
  ergebnis= ((zaehler / nenner) / 1000) + n;
ändert sich am Ergebnis nichts.
Aber: Dadurch, dass er das Berechnen von 'zaehler' nach hinten 
verschoben hat, hat er das Ergebnis nach der Berechnung bereits in einem 
Register vorliegen. Und da es dort bereits liegt, braucht er es in der 
nachfolgenden Division nicht erneut laden -> kürzerer Code. Damit ist 
aber auch klar, da die Variable sonst nirgends mehr benutzt wird, dass 
niemand die Variable braucht. Insbesondere ist das 'volatile' an dieser 
Stelle sinnlos, da ausserhalb der Funktion sowieso niemand auf diese 
Variable zugreifen kann und diese Variable (als funktionslokale 
Variable) auch sonst nicht erreichbar ist (zb über einen Pointer), da 
keine Funktion aufgerufen wird, der die Adresse dieser Variablen 
übergeben wird.

Du unterschätzt gewaltig, was der Optimizer mit deinem Code alles machen 
kann und wieviel Gehirnschmalz da mitlerweile drinnen steckt.

Autor: Läubi .. (laeubi) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Phil schrieb:
> Komisch finde ich ja, dass obwohl die Variable volatil ist, der Compiler
> sie wohl TROTZDEM wegoptimiert.
Wenn dich das wundert wundert mich nix ;P
volatile heißt doch nur das sich die Variable außerhalb des 
Sichtbereiches des Compilers ändern kann.
Wenn du die Variable aber nie liest (und diese Funktionslokal ist) kann 
er diesen Ausdruck:
ergebnis= ((zaehler / nenner) / 1000) + n;
OCR1A = pgm_read_word(&pwmtable[result]);
return ergebnis;
Wunderbar optimieren zu:
OCR1A = pgm_read_word(&pwmtable[result]);
return ((zaehler / nenner) / 1000) + n;
(Wobei wir immer noch nicht wissen woher eigentlich result kommt...)

Autor: Läubi .. (laeubi) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Phil schrieb:
> versteh nicht wie man vorgehen soll wenn der Code wächst und wächst und
> man einfach nicht mehr die Optimierung abschalten kann, weil ebn sonst
> der uc voll ist und sich gar nicht mehr flashen lässt...
Dein "Problem" ist denke ich einfach das du einen riesen Haufen (manche 
nenen es auch Codewust) an Abhängigkeiten zusammenklatscht, gewürzt mit 
ein paar Annahmen und Try&Error Programmierung.

Normalerweise versucht man Funktionen so zu gestalten das diese 
möglichst eigenständig arbeiten und auch getestet werden können. Wenn 
ich dann weiß dass die Funktion korrekt funktioniert kann ich diese in 
anderen Programteilen dann nutzen und muss nicht das gesamte Programm 
debuggen.

Autor: Phil (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> ev. hilft es, nur Teile des Codes zu optimieren.

optimieren.. ich hoffe du meinst compilieren bzw. debuggen. Oder kann 
man tatsächlich die Optimierungsstufe für ganze Codeabschnitte 
einstellen? Wär ja cool. Glaub aber kaum, dass das geht.. Wegen der 
"Ganzheitlichkeit" :-)

Also ich habe jetzt den Code in ein eigenes Projekt ausgelagert und 
siehe da. Es funktioniert auch OHNE volatile und alle Variablen 
EINSCHLIESSLICH "zaehler" haben einen resonablen Wert.

Die große Frage für mich lautet jetzt.

Kann ich nun ruhigen Gewissens den Code in meinem eigentlichen Projekt 
so lassen, oder muss ich "Angst" haben, dass mir der Optimierer wieder 
nen fetten Strich durch die Rechnung macht. Nicht optimiert und 
ausgelagert läuft er.

Läubi .. schrieb:
> Dein "Problem" ist denke ich einfach das du einen riesen Haufen (manche
>
> nenen es auch Codewust) an Abhängigkeiten zusammenklatscht, gewürzt mit
>
> ein paar Annahmen und Try&Error Programmierung.

Kurzn: Anfänger. Japp. Das bin ich :-)

Autor: Klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Optimizer macht dir niemals ein Strich durch die Rechnung (mal 
abgesehen, von globalen Variablen und Interrupts, aber das tut hier nix 
zur Sache).


Dass der Optimizer Variablen rausschmeißt, ändert nichts an der 
funktionalität des Codes. Allerdings kannst du sie dann im debugger 
nicht mehr anzeigen lassen, wie du festgestellt hast. Das ist aber kein 
Hinweis darauf, dass der Code nicht funktioniert.

Also:
- Wenn du bei einer Variable  "Not in Scope" oder "Location not Valid" 
angezeigt bekommst, is das kein Grund zur Sorge. Das hat alles seine 
Richtigkeit.
-  Wenn du aber zum Debuggen unbedingt den Inhalt einer Variabelen sehen 
möchtest, kannst du sie (temporär!) als Volatile deklarieren. In den 
meisten Fällen wird sie dann nicht wegoptimiert. Durch das Volatile hast 
du dir nur die Möglichkeit geschaffen, die Variable im Debugger 
anzuzeigen, aber keine Funktionalität des Codes geändert.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.