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
volatileBoolpol_timer_status;
Im Hauptprogramm deklariert:
1
externvolatileBoolpol_timer_status;
1
intmain(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?
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?
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.
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.
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
volatileU16test_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.
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.
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 FehlerbeschreibungCompilerfehler: Die häufigsten Nicht-Fehler
Analog gilt das auch, wenn jemand dir helfen soll/will und dein Problem
anhand von Code nachvollziehen will.
Johann
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.
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.
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
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
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
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.
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.
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
> 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...
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.
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 ;-)
>> if(pol_timer_status == TRUE)>ist etwas, was ich mir schnell abgewöhnt hatte.>>Immer auf "!= FALSE" testen (oder einfach das "== TRUE" weglassen).
Warum?
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.
>>>> 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