Forum: Mikrocontroller und Digitale Elektronik GCC AVR32 Problem mit Variable


von Peter (Gast)


Lesenswert?

Ich habs schon mal bei AVR Freaks gepostet, aber da wusste niemand so 
recht.
Compiler ist GCC im AVR32 Studio.

Ich habe eine Variable:
1
volatile Bool pol_timer_status;

Im Hauptprogramm deklariert:
1
extern volatile Bool pol_timer_status;
1
int main(void)
2
{
3
  .....
4
  while(1)
5
  {
6
    ....
7
    if(pol_timer_status == TRUE)
8
    {
9
      pol_timer_status = FALSE;
10
      .....
11
    }
12
  }
13
}

Es passiert unregelmässig das die if-Bedingung TRUE wird, obwohl 
pol_timer_status definitiv FALSE ist. Diese Variable wird nut im TC(0) 
Interrupt gesetzt, und das ist auskommentiert.
Ich komme da irgendwie nicht mehr weiter. Hat jemand den Hauch einer 
Ahnung warum das so sein könnte.
Könnte es was mit dem Cache zu tun haben?

von (prx) A. K. (prx)


Lesenswert?

Peter schrieb:

> Ich komme da irgendwie nicht mehr weiter. Hat jemand den Hauch einer
> Ahnung warum das so sein könnte.

Am gezeigten Code jedenfalls nicht.

> Könnte es was mit dem Cache zu tun haben?

Nein.

Apropos: welchem Cache?

von Peter (Gast)


Lesenswert?

Dem Cache vom AP7000.

Hier hat einer scheinbar das gleiche Problem, was aber zumindest bis 
jetzt nicht gelost wurde:
Beitrag "Merkwürdiges Verhalten bei Variablen und for-schleifen"

von (prx) A. K. (prx)


Lesenswert?

Für sowas braucht mal einen Testcase. Ein auf das absolute Minimum 
reduziertes aber immer noch compilierbares(!) Programm, in dem das 
Problem immer noch auftritt.

Oder die berühmte Glaskugel.

von Stefan E. (sternst)


Lesenswert?

Wenn eine Variable unvermittelt ihren Wert ändert, ist das meistens das 
Resultat eines "Amok-Pointers".
(z.B. bei einem Array-Out-Of-Bound-Zugriff)

von (prx) A. K. (prx)


Lesenswert?

Peter schrieb:

> Hier hat einer scheinbar das gleiche Problem, was aber zumindest bis
> jetzt nicht gelost wurde:

Oft postet jemand ein paar Zeilen eines grösseren Programms und garniert 
sie mit dem Kommentar "hier stimmt etwas nicht".

Um die Absurdität zu betonen sind das das vielleicht 5 Zeilen, die 
totsicher korrekt sind. Jedenfalls als Quellcode. Der Rest fehlt, weil 
der Poster das Problem in den 5 Zeilen vermutet. Ist ein bischen so wie 
ein Patient der mit fertiger Diagnose "mein rechter Arm fehlt" zum Arzt 
geht und ihm zur Begrüssung mit Rechts die Hand schüttelt.

Nur kommt ihm eigentümlicherweise nicht in den Sinn, dass kaum ein Leser 
damit irgend etwas anfangen kann, es sei denn er stolperte zufällig 
selber über genau das gleiche Problem.

Den nur allzu oft liegt das Problem ganz woanders. In dem anderen Thread 
waren beispielsweise die Stacks vergessen worden, was mindestens einen 
Teil des Problems verursachte.

Und wenn man die Korrektheit des Compilers in Zweifel zieht (bzw, dies 
in Betracht zieht), dann sollte der Leser das Problem nachvollziehen 
können. Lies: es compilieren können. Ohne sich durch 2500 Quellzeilen 
wühlen zu müssen.

Ausserdem kommt es nicht selten vor, dass man bei der Reduktion auf das 
Minimum selber drauf stösst.

von Peter (Gast)


Lesenswert?

Ich habe nicht erwartet das ich die Zeilennummer mit dem Fehler bekomme.
Wenn man im Internet nach diesem Phaenomen sucht, findet man viele 
Threads mit fast gleicher Fragestellung, aber leider ohne Antwort.
Das ist doch so ein eklatantes Problem, da kann ich nicht, und bin ich 
nicht der einzige. Leider ist der ganze GCC Kram zumindest fuer mich 
ziemlich undurchsichtig.
Zumal ich eigentlich erwarte das der Compiler- bzw Linker Output etwas 
brauchbares liefert.

Aber ich gebe dir Recht, das man das Problem auf den kleinsten Code 
herunterbrechen soll, dieses Problem war schon mal da aber dann 
merkwuerdigerweise weg, wobei ich dachte den Fehler gefunden zu haben.

Witzigerweise tritt der Fehler zumindest wie es aussieht nur in der 
while(1) Schleife in main auf. Alle anderen Module funktionieren.
Aber ich finde den Fehler einfach nicht.

wobei bei der while(1) habe ich noch ein ganz anderes Problem.
1
volatile U16 test_var;
2
3
test_var = 5;
4
5
while(test_var)
6
{
7
  test_var++;
8
  .....
9
  test_var--;
10
}

Ich haette zumindest erwartet das die while Schleife ausgefuehrt wird, 
tut sie aber nicht.

von (prx) A. K. (prx)


Lesenswert?

Peter schrieb:

> Ich haette zumindest erwartet das die while Schleife ausgefuehrt wird,
> tut sie aber nicht.

Was für eine Antwort erwartest du? Ja, sie sollte ausgeführt werden. 
Nützt dir diese Antwort etwas? Denn mehr lässt sich dazu nicht sagen.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

A. K. schrieb:
> Oft postet jemand ein paar Zeilen eines grösseren Programms und garniert
> sie mit dem Kommentar "hier stimmt etwas nicht".
>
> Um die Absurdität zu betonen sind das das vielleicht 5 Zeilen, die
> totsicher korrekt sind. Jedenfalls als Quellcode. Der Rest fehlt, weil
> der Poster das Problem in den 5 Zeilen vermutet. Ist ein bischen so wie
> ein Patient der mit fertiger Diagnose "mein rechter Arm fehlt" zum Arzt
> geht und ihm zur Begrüssung mit Rechts die Hand schüttelt.

@Peter

Siehe auch
  Compilerfehler: Aussagekräftige Fehlerbeschreibung
  Compilerfehler: Die häufigsten Nicht-Fehler


Analog gilt das auch, wenn jemand dir helfen soll/will und dein Problem 
anhand von Code nachvollziehen will.

Johann

von Peter (Gast)


Lesenswert?

Aber was hilfts? Wir müssen liefern und können nich noch monatelang mit 
einem GCC Bug rumspielen. Da sind ja tausende von Bugs auf der Liste. 
War ein grosser Fehler auf GCC zu gehen bei einem neuen Prozessor wie 
dem AP7000.

von (prx) A. K. (prx)


Lesenswert?

Peter schrieb:

> Aber was hilfts? Wir müssen liefern und können nich noch monatelang mit
> einem GCC Bug rumspielen. Da sind ja tausende von Bugs auf der Liste.

Hast du mal die Liste bekannter Bugs anderer Compiler gesehen? Wieviele 
der "tausenden" erzeugen falschen Code?

Bislang ist es nur eine durch rein garnichts belegte Vermutung, es sei 
ein Bug des Compilers. Wenn du hier mehr erreichen willst, als deinen 
Frust abzuladen, wirst du mehr liefern müssen.

von Peter D. (peda)


Lesenswert?

Peter schrieb:
> Aber was hilfts? Wir müssen liefern und können nich noch monatelang mit
> einem GCC Bug rumspielen.

Wenn Du einen Compiler-Bug vermutest, dann wäre es umso sinnvoller, wenn 
Du mal einen compilierbaren Code postest, der das Fehlerbild zeigt.

Die Programmschnipselchen-posten-Methode führt eigentlich nie zum 
Erfolg.

Es wundert mich daher nicht, daß mit diesem gravierenden 
Informationsmangel auch bei AVRfreaks keine Hilfe kam. Die habens wohl 
auch nicht so mit dem Hellsehen.

Schau dochmal ins Assemblerlisting, ob vielleicht ein Interrupt die 
Register ändert, aber nicht sichert, mit denen das Main Deine Variable 
testet, bzw. mach den Test mal atomar.



Peter

von Marcus M. (marcus67)


Lesenswert?

Ich programmiere jetzt seit rund 25 Jahren auf den unterschiedlichsten 
Plattformen (von HP-UX über LINUX, Windows bis hin zum MC9S12 und AVR).

Ich habe in dieser Zeit wahrscheinlich viele Monate meines Lebens mit 
der Suche nach dubiosen Fehlern verbracht - nur einen Compilerfehler 
habe ich in all den Jahren nicht gefunden (nur einmal einen OS Fehler in 
HP-UX).

All die seltsamen Fehler (es waren auch einige auf dem AVR-GCC dabei) 
waren letztlich meistens Arrayüberläufe oder Pointerfehler. Auch 
seltsame Fehler nach dem Wechsel der AVR-GCC Version ließen sich bisher 
immer auf unsaubere Programmierung hier oder da runterbrechen.

Leider treten sind diese Probleme auf Microcontrollern nur sehr schwer 
zu finden da man spezielle Tools wie Electric Fence o.ä. leider nicht 
einsetzen kann.

Gruß, Marcus

von mizch (Gast)


Lesenswert?

So wie der Code mit test_var da steht, wird test_var nirgends sonst 
verwendet.  Der Compiler ist also frei, alles, was was test_var 
betrifft, wegzuoptimieren (Du hättest es sonst volatile deklarieren 
müssen).  Also ist der einzige Code, der in der while-Schleife 
ausgeführt wird, der Teil, der praktischerweise mit '...' angedeutet 
ist.  Ist dort ein
1
break;
 wird die Schleife verlassen.

Was Dein anderes Problem betrifft:  Schau Dir mal die Variablen vor und 
nach derjenigen an, die nicht gesetzt sein darf.  Meist ist dort der 
Fehler zu finden (falsche Größe deklariert, Array-Überlauf usw.).  Du 
kannst (wenn Dein dargestellter Code zutrifft) ruhig definitiv davon 
ausgehen, dass die abgefragte Variable != 0 ist.

Die Adressen der Variablen erfährst Du mit
1
nm -anl Dein_Obektfile.elf | sort
.

von Peter (Gast)


Lesenswert?

Danke für all die Ideen, aber das Problem liegt meines Erachtens an ganz 
anderer Stelle.
Im Timerinterrupt TC(0) werden nur Flags gesetzt, die dann in der 
while(1) abgefragt werden. Dabei werden die Flags beliebig oft mit 
falschem Wert gelesen.
Wenn man nun diese Flagabfragen testhalber in den TC(0) Interrupt mit 
hereinlegt, funktioniert alles wie es soll.
Der AP7000 hat einen insgesamt 32k grossen Cache, in dem sich vermutlich 
mehr oder minder die while(1) Endlosschleife einlagern wird, die nur ein 
paar hundert Bytes gross ist. Dabei kommt es offenbar zu diesen 
"Lesefehlern".
Wenn ein Interrupt auftritt, wird der Cache automatisch invalidiert und 
die CPU verzweigt in den Interrupt, wo nun alle Variablen offenbar neu 
und richtig gelesen werden.
Da muss ich wohl noch ein wenig spielen um mit der MMU eine Non-cashable 
Area zu erzeugen. Oder die while Schleife in den SDRAM auslagern, der 
problemlos non-cashable les- und schreibbar ist.

von (prx) A. K. (prx)


Lesenswert?

mizch schrieb:

> (Du hättest es sonst volatile deklarieren müssen).

Das hat er.

von (prx) A. K. (prx)


Lesenswert?

Peter schrieb:

> Wenn ein Interrupt auftritt, wird der Cache automatisch invalidiert

Warum dies? Ich kennen diesen AP7000 nicht persönlich, aber so ein 
Verhalten wäre ziemlich unüblich. Üblicherweise sind Caches ziemlich 
transparent gegenüber dem Programmierer, beeinflussen das Zeitverhalten 
aber nicht die Funktion.

von (prx) A. K. (prx)


Lesenswert?

Hab mal einen Blick in die Doku geworfen. Die Caches des AP7000 sind 
sehr klassisch gebaut, vgl. Intel x86, so dass auch ein MMU context 
switch keine Auswirkung hat, erst recht kein Interrupt.

Versteif dich lieber nicht zu sehr auf den Cache. Ich fürchte du baust 
dir damit einen Popanz auf, weil dir sonst nichts mehr einfällt.

Der Cache könnte allenfalls eine Rolle spielen, wenn der I/O-Bereich des 
Timers versehentlich cachable arbeitet. Ich weiss nicht ob man die 
Adressräume des AP7000 explizit programmieren muss, oder ob der selber 
spitzkriegt, dass I/O non-cachable und ordered sein muss

von Experte (Gast)


Lesenswert?

> Aber was hilfts? Wir müssen liefern und können nich noch monatelang
> mit einem GCC Bug rumspielen.

Ah, da liegt der Hund begraben. Frickel-Bude mit mangelndem Know-How 
will Kohle machen und hat ein Problem. Schuld ist natürlich jemand 
anders.


> Im Timerinterrupt TC(0) werden nur Flags gesetzt, die dann in der
> while(1) abgefragt werden. Dabei werden die Flags beliebig oft mit
> falschem Wert gelesen.

   [...]

> Wenn ein Interrupt auftritt, wird der Cache automatisch invalidiert
> und die CPU verzweigt in den Interrupt, wo nun alle Variablen offenbar
> neu und richtig gelesen werden.

Aha!

Siehst Du: Du bist das Problem, nicht der Compiler. Du verstehst nichts 
von Barrieren verschiedener Art und glaubst mit "volatile" werden Deine 
Probleme auf magische Weise gelöst...

Ich kann Dir helfen. Die Stunde 150,- € Netto.


> War ein grosser Fehler auf GCC zu gehen bei einem neuen Prozessor
> wie dem AP7000.

Du kannst noch heute einen kommerziellen Compiler kaufen und heute Abend 
alles portiert haben...

von Peter (Gast)


Lesenswert?

Nee danke, lass mal. Bevor ich so jemanden wie dir einen Auftrag geben 
würde, würde ich das Projekt lieber zurück geben.
Ein Mindestmaß an Höflichkeit sollte schon sein, menschlich, als auch 
als Dienstleister, der du ja offenbar bist, einem potentiellen 
Auftraggeber gegenüber.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Peter schrieb:
> Aber was hilfts? Wir müssen liefern und können nich noch monatelang mit
> einem GCC Bug rumspielen. Da sind ja tausende von Bugs auf der Liste.
> War ein grosser Fehler auf GCC zu gehen bei einem neuen Prozessor wie
> dem AP7000.

GCC optimiert aggressiv. Das offenbart oft mehr Ungenauigkeiten in einer 
Anwendung als bei Compilern, die den C-Standard nicht so extrem 
ausreizen (zB Thema Aliasing, Strict Overflow, ...)

Ob avr32-gcc für die "Zeile"
>     if(pol_timer_status == TRUE)

wirklich falschen Code erzeugt, sollte sich recht einfach nachprüfen 
lassen. Es ist ziemlich wahrscheinlich nicht der Fall.

Wie auch immer, ohne compilerbaren Testfall ist's Lesen ausm Kaffeesatz.

Kaffeesatz sieht in C nämlich so aus ;-)
1
   ...

von Werner B. (werner-b)


Lesenswert?

>     if(pol_timer_status == TRUE)
ist etwas, was ich mir schnell abgewöhnt hatte.

Immer auf "!= FALSE" testen (oder einfach das "== TRUE" weglassen).

von sepp (Gast)


Lesenswert?

>>     if(pol_timer_status == TRUE)
>ist etwas, was ich mir schnell abgewöhnt hatte.
>
>Immer auf "!= FALSE" testen (oder einfach das "== TRUE" weglassen).

Warum?

von Simon K. (simon) Benutzerseite


Lesenswert?

sepp schrieb:
>>>     if(pol_timer_status == TRUE)
>>ist etwas, was ich mir schnell abgewöhnt hatte.
>>
>>Immer auf "!= FALSE" testen (oder einfach das "== TRUE" weglassen).
>
> Warum?

Weil TRUE alles > 0 sein kann und keinen definierten Wert haben muss.
Bei richtiger Definition passt das aber schon so.

von Thomas K. (muetze1)


Lesenswert?

... oder einfach nur if (var), da die Evaluierung wahr ergibt wenn das 
Argument != 0 ist.

von TimTom (Gast)


Lesenswert?

>>>>     if(pol_timer_status == TRUE)
>>>ist etwas, was ich mir schnell abgewöhnt hatte.
>>>
>>>Immer auf "!= FALSE" testen (oder einfach das "== TRUE" weglassen).
>>
>> Warum?
>
> Weil TRUE alles > 0 sein kann
Äh, alles ungleich 0

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.