mikrocontroller.net

Forum: Compiler & IDEs avr-gcc vergisst volatile variable in isr neu zu lesen


Autor: Florian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich habe eine globale volatile variable die ich in der ISR des adcs 
verändere. Jetzt benötige ich den Wert in einer anderen ISR aber das 
funktioniert nicht. Ausser halb der ISR ist die Variable aber OK.
Ist das normal?

Gruß
Florian

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

Bewertung
0 lesenswert
nicht lesenswert
Meine Glaskugel sagt, du hast einen Fehler in Zeile 42.

Zeige Code!

Autor: Florian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
:))

wie heisst die Quelldatei?

Autor: Florian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
globale.h
volatile unsigned short adc_ergebnis[8];
volatile unsigned char  adc_kanal[8];
volatile unsigned short kanal_index;


Separate datei

SIGNAL(SIG_OVERFLOW0)
{

    //pos = adc_ergebnis[2];
        f2 = f1;
        f1 = f0;
        f0 = (float)(pos-des_pos)/(float)1024.0;
        Ua = Ua + (Kp+Ki*T_cnt0+Kd/T_cnt0) * f0 + (-Kp-Kd/T_cnt0) * f1 + 
(Kd/T_cnt0) * f2;


        if((pos-des_pos)<max_fehler || (des_pos-pos)<max_fehler)
        {
            //pwm_stop();
            //return;
        }
        PORTD |= _BV(PD7);


/*         if(pos-des_pos>0) */
            init_pwm_oc1a();

        /* else  */
/*             init_pwm_oc1b() */;

        Te = ((float)Ua/(float)Vcc);            /*  Tein des PWM Signals 
*/

        int c = ((float)Te * (float)TOP);
        setze_tastverhaeltnis(adc_ergebnis[2]);
        //setze_tastverhaeltnis(Te * TOP / T_pwm);
        PORTD &= ~_BV(PD7);
}

Separate Datei:


SIGNAL(SIG_ADC)                      //interrupte sind in ISR 
automatisch ausgeschaltet
{
    adc_ergebnis[kanal_index]   = ADCL;     //erst ADCL dann ADCH um 
sicherzustellen
                                            //           das Werte aus 
einer Wandlung stammen;
    adc_ergebnis[kanal_index]  += (ADCH<<8);

    kanal_index++;
    if(kanal_index==3)
        kanal_index=0;

    ADMUX = adc_kanal[kanal_index]; /* ca. 100 Zyklen seit der Interrup 
ausgelöst wurde */
                                    /*wir können also den mux neu muxen 
*/
    ADCSRA |= _BV(ADSC);
}




Es geht um adc_ergebnis[x]

Autor: unbeschreiblicher Rahul (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>wie heisst die Quelldatei?

main.c

Wenn dem nicht so sein sollte, liegt der Fehler woanders.

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

Bewertung
0 lesenswert
nicht lesenswert
Schön. Aber den Code kann ich nicht in AVR-Studio kopieren
und laufen lassen um nachzusehen was da wirklich passiert.

Autor: Florian (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ahh hallo,

nichts für ungut. Ich bin ja kein Baby mehr. Abgesehen davon dürfte das 
wohl einige arbeit werden das ins avrstudio zu bringen. Aber bitte im 
anhang ist das projekt. Ich dachte nur ob jemand etwas in dem Zusammen 
hang weiss. Ich habe es jetzt anders gemacht. Und zwar habe ich noch 
einen zeiger auf adc_ergebnis erstellt. diesen benutze ich jetzt in der 
ISR.

Ich habs mal angehangen. Es ist ein PWM Servotreiber.
fall jemand interesse an der Elektronik hat, ich bin unter 
florian.hillen@web.de zu erreichen oder gleich hier.

Frohes neues Jahr!

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

Bewertung
0 lesenswert
nicht lesenswert
> Abgesehen davon dürfte das
> wohl einige arbeit werden das ins avrstudio zu bringen.

Halb so wild.
Eine ANgabe brauch ich noch.
Wie stellst du fest, dass da was mit den volatile
Variablen nicht stimmt?
Hast dus im Debugger gesehen oder ist das nur eine Vermutung?

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Florian wrote:

> Abgesehen davon dürfte das
> wohl einige arbeit werden das ins avrstudio zu bringen.

Stimmt, .tar.gz is nich so mein Ding.

XP kann von Haus aus nur .zip


Peter

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

Bewertung
0 lesenswert
nicht lesenswert
Das einzige was ich bis jetzt im Debugger gesehen habe ist,
dass dein Overflow Interrupt zuviel Zeit braucht. Der Prozessor
arbeitet praktisch nur da drinnen. Sobald die ISR fertig ist,
beginnt auch schon der nächste ISR, weil der Timer in der
Zwischenzeit den nächsten Überlauf produziert hat.
Setzt mal den Vorteiler etwas höher.

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

Bewertung
0 lesenswert
nicht lesenswert
Ansonsten klappt bei mir im Debugger der Zugriff auf das
Array einwandfrei. Ich wüsste auch keinen Grund warum das
nicht so sein sollte.
Ich habe mal den Vorteiler um eine Stufe erhöht. Seitdem
werden zwischendurch auch wieder Werte vom ADC abgeholt :-)

Autor: Florian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
aha das werde ich einmal Probieren.
Ich habe festgestellt das da was nicht stimmt weil ich an meiner 
Leistungselektronik einen Motor habe und der immer nur nach dem ersten 
ADC Wert ging.
Ich probies direkt mal aus und meld mich nochmal. Vielen dank auch!
Florian

Autor: Florian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Alles Klar, Du hast recht jetzt läufts.

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

Bewertung
0 lesenswert
nicht lesenswert
Also wars doch ganz gut das vollständige Projekt zu posten :-)

Merke: Wenn jemand glaubt dass er einen Compilerfehler entdeckt
hat, dann hat er zu 99% ein anderes Problem im Programm. Natürlich
haben auch Compiler so ihre Fehler. Aber nicht bei einem
simplen Variablenzugriff.

Autor: Florian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So eine Schmach. Aber wahrscheinlich hast du auch da recht.

Autor: Florian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Auch wenn man überzeugter GNUler ist muss man trotzdem erstmal vertrauen 
in die Werkzeuge gewinnen!

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Möchte nur mal vorsichtshalber darauf hinweisen, dass

volatile unsigned short x;

ISR(suchesdiraus)
{
  x = irgendwas;
}

main()
{
  while(1)
    tu_irgendwas_mit(x);
}

auf AVRs zwar 999 von 1000 mal wunderbar funktionieren wird, aber ab und 
zu Schrott rauskommt. Siehe 
http://www.mikrocontroller.net/articles/Interrupt#....

Autor: Unbekannter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> auf AVRs zwar 999 von 1000 mal wunderbar funktionieren wird,
> aber ab und zu Schrott rauskommt.

Nun, der Schrott macht aber nicht der Compiler, sondern der 
Programmierer, wie üblich. Die Lösung des Problems lautet:


  volatile unsigned short x;

  ISR(suchesdiraus)
  {
    x = irgendwas;
  }

  main()
  {
    unsigned short x_copy;
    while(1)
    {
      cli();
      x_copy = x;
      sei();
      tu_irgendwas_mit(x_copy);
    }
  }



Autor: Sonic (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sollte die Funktion von cli(); und sei(); nicht der Grund sein, warum 
man die Variable als volatile deklariert (mehr als 1 Byte zum Lesen)? 
Sollte eigentlich automatisch vom Compiler erledigt werden.

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nein.

"volatile" sorgt dafür, dass die tatsächlich durchgeführten Zugriffe 
denen im Quelltext entsprechen, d.h. dass da nichts wegoptimiert oder 
umsortiert wird. Atomar werden die Zugriffe mit "volatile" jedoch nicht.

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"Nun, der Schrott macht aber nicht der Compiler"

Wollte ich damit auch nicht ausdrücken. Ich hatte bei Florians Code 
jedoch gleich den Verdacht, dass unabhängig vom eigentlichen Problem 
jemand, der in Interrupts Floating-Point-Rechnungen durchführt, diese 
Feinheit im Umgang mit globalen Variablen auch übersehen hatte - und 
genau so ist es.

Autor: Sonic (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hmm.. so wie ich das verstanden habe dient volatile (!beim AVR!) dazu, 
Variablen, die außerhalb der Funktion 'main' behandelt werden, neu 
einzulesen und während des Einlesens den globalen INT zu sperren, um 
teilweises Lesen zu vermeiden, falls währenddessen ein INT auftritt. 
Hatte auch noch nie Probleme in der Richtung.
Aber, falls das anders ist, wieder was gelernt.

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Alle Ports und Steuerregister sind "volatile". Wenn GCC da jedesmal 
einen cli/sei-Wrapper drumwickeln würde...

Autor: Sonic (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bei Ports und Steuerregistern muss er das ja auch nicht, da die 
Byteorientiert sind. Dachte, nötig ist es nur bei Variablen >8 Bit, da 
es mehrerer Leseoperationen für diese Typen bedarf. Lasse mich aber 
gerne eines Anderen belehren.

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ist auch nur bei >8bit nötig, allerdings sind manche I/O-Register >8 
breit (z.B. bei Timer, ADC). Aber das Philosophieren lässt sich ganz 
einfach abkürzen: Guck in den Code und vertrau darauf, dass GCC sich 
korrekt verhält. Stimmt fast immer.

Autor: Sonic (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also ich hatte noch keine Probleme mit GCC. Find ich prima.

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.