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


von Florian (Gast)


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

von Karl H. (kbuchegg)


Lesenswert?

Meine Glaskugel sagt, du hast einen Fehler in Zeile 42.

Zeige Code!

von Florian (Gast)


Lesenswert?

:))

wie heisst die Quelldatei?

von Florian (Gast)


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]

von unbeschreiblicher Rahul (Gast)


Lesenswert?

>wie heisst die Quelldatei?

main.c

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

von Karl H. (kbuchegg)


Lesenswert?

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

von Florian (Gast)


Angehängte Dateien:

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!

von Karl H. (kbuchegg)


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?

von Peter D. (peda)


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

von Karl H. (kbuchegg)


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.

von Karl H. (kbuchegg)


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 :-)

von Florian (Gast)


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

von Florian (Gast)


Lesenswert?

Alles Klar, Du hast recht jetzt läufts.

von Karl H. (kbuchegg)


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.

von Florian (Gast)


Lesenswert?

So eine Schmach. Aber wahrscheinlich hast du auch da recht.

von Florian (Gast)


Lesenswert?

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

von A.K. (Gast)


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#Atomarer_Datenzugriff.

von Unbekannter (Gast)


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);
    }
  }



von Sonic (Gast)


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.

von A.K. (Gast)


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.

von A.K. (Gast)


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.

von Sonic (Gast)


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.

von A.K. (Gast)


Lesenswert?

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

von Sonic (Gast)


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.

von A.K. (Gast)


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.

von Sonic (Gast)


Lesenswert?

Also ich hatte noch keine Probleme mit GCC. Find ich prima.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.