Hallo!
Kann jemand folgendes Verhalten reproduzieren.
In meinem aktuellen Projekt zerstört das Hinzufügen von "volatile" bei
häufigen Aufrufen den Variableninhalt.
Das Problem tritt mit folgenden Code auf:
Ich bekomme Fehlermeldungen nach 1 bis 5 Schleifendurchläufen.
Tim schrieb:> Das Problem tritt mit folgenden Code auf:> Ich bekomme Fehlermeldungen nach 1 bis 5 Schleifendurchläufen.
ein Programm macht immer das gleiche (hier auf jeden Fall bei Threads
nicht immer). Damit muss immer das gleiche Ergebiss rauskommen. Es kann
also gar nicht sein das es mal nach 1 oder mal nach 5 Schleifen zu einem
Fehler kommt.
Bist du sicher das deine Hardware OK ist?
Tim schrieb:> void verify(const unsigend int value)
wohl eher void verify(const unsigned int value)
Tim schrieb:> volatile val=TEST_VAL;
WAS ist val? int, double, .. Kartoffelbrei?
Peter II schrieb:> M. K. schrieb:>> AS ist val? int, double, .. Kartoffelbrei?>> nein das ist C und da ist es int.
Mag sein trotzdem sollte man den Typ schon dabei schreiben. Wenn val nun
int ist und verify(..) ein unsigned int verlangt sollte der Compiler
zumindest eine Warnung raus schmeißen.
Aber letztendlich ist das sowieso egal, weil das Konstrukt nicht den
wahren Code zeigt, sondern nur das zeigt was der Programmierer meint was
der wahre Code machen sollte.
Das Problem liegt wahrscheinlich mal wieder ganz wo anders.
Hängt euch bitte nicht an meiner Unfähigkeit auf Pseudocode zu tippen.
Ich werde, wenn ich ihn etwas aufgeräumt habe mal den Originalcode
posten.
zu den angesprochenen Punkten.
# ja es soll natürlich zweimal "unsigned int" heißen
# und das i soll natürlich mit 0 initialisiert sein
Mir ist aufgefallen, das diese Art von Fehler nur an bestimmten Stellen
im Projekt auftritt. Rufe ich die Fkt verify am Anfang der main
funktioniert diese ohne Fehler. Wird sie im späteren Programmverlauf in
einer Unterfunktion gerufen gibt es Fehler.
Tim schrieb:> ir ist aufgefallen, das diese Art von Fehler nur an bestimmten Stellen> im Projekt auftritt. Rufe ich die Fkt verify am Anfang der main> funktioniert diese ohne Fehler. Wird sie im späteren Programmverlauf in> einer Unterfunktion gerufen gibt es Fehler.
gut dann warten wir bis wir etwas mehr code sehen, aber es klingt doch
sehr nach einem Speicher überschreiber.
Tim schrieb:> Hängt euch bitte nicht an meiner Unfähigkeit auf Pseudocode zu tippen.Tim schrieb:> int main()> {> volatile val=TEST_VAL;
Steht die Deklaration von val tatsächlich in der main-Funktion deines
Originalcodes oder ist sie außerhalb einer Funktion und somit Global?
Wird val irgendwo in deinem Originalcode manipuliert, z.B. in einem
Interrupt oder in einer Funktion in der annimmst das val Global
deklariert ist?
Tim schrieb:
> Hängt euch bitte nicht an meiner Unfähigkeit auf Pseudocode zu tippen.
Herr Doktor hier hier und hier tut's furchtbar weh!
Tut mir leid Herr Tim, ich finde da keine Ursache. Sie sind 100% gesund.
Ach nee, Herr Doktor, das weiss ich. Weh tut's meiner Schwester!
Tim schrieb:> Hängt euch bitte nicht an meiner Unfähigkeit auf Pseudocode zu tippen.
Doch, denn du sollst hier keinen Pseudocode zeigen, sondern den, der
nicht funktioniert. Es ist nämlich ziemlich frustrierend, wenn man
Fehler im Code sucht und erklärt, nur um dann als Antwort zu bekommen,
daß der eigentliche Code diese Fehler natürlich gar nicht enthält und
das Problem dafür im geposteten Code gar nicht vorkommt.
> Mir ist aufgefallen, das diese Art von Fehler nur an bestimmten Stellen> im Projekt auftritt. Rufe ich die Fkt verify am Anfang der main> funktioniert diese ohne Fehler. Wird sie im späteren Programmverlauf in> einer Unterfunktion gerufen gibt es Fehler.
Dann kann es sein, daß der Fehler eigentlich wo ganz anders liegt. Wenn
ein anderer Programmteil z.B. über einen falschen Zeiger irgendwo was
reinschreibt, kann der dir deine Variable auch überschrieben. Das von
dir beobachtete Phänomen paßt exakt zu so einem Fehler.
Krapao schrieb:> Tim schrieb:>> Hängt euch bitte nicht an meiner Unfähigkeit auf Pseudocode zu tippen.>> Herr Doktor hier hier und hier tut's furchtbar weh!> Tut mir leid Herr Tim, ich finde da keine Ursache. Sie sind 100% gesund.> Ach nee, Herr Doktor, das weiss ich. Weh tut's meiner Schwester!Tim schrieb:> Ich werde, wenn ich ihn etwas aufgeräumt habe mal den Originalcode> posten.
Mit etwas Glück haben wir dann die verbesserte Schwester 2.0 und der
Fehler ist weg oder wir bekommen es mit der Zwillingsschwester zu tun
mit selben Symptom nur an anderer Stelle.
Tim schrieb:
> Hängt euch bitte nicht an meiner Unfähigkeit auf Pseudocode zu tippen.> Ich werde, wenn ich ihn etwas aufgeräumt habe mal den Originalcode> posten.
Hast Du schon versucht, ob der obige Code in deiner großen Umgebung
auch den Fehler erzeugt ?
Hast Du z.B. die Interrupt-Routinen (falls vorhanden, falls möglich)
ausgehängt und tritt der Fehler dann trotzdem auf ?
Eine Frage, die immer noch offen ist:
Welcher Compiler ? Welche Version ?
Was auch noch interessant ist:
Auf welchem Chip ?
Sind Optimierungen eingeschaltet ?
Falls ja: Tritt der Fehler auch auf, wenn die Optimierungen
ausgeschaltet
sind ?
Glaskugel:
der TE hat nicht so ganz verstanden, was volatile eigentlich bewirkt,
und einfach so ein "volatile uint8_t"-Beispiel aus dem Forum für seinen
16Bit-integer umgemünzt.
Was er eigentlich will ist kein "volatile", sondern atomarer Zugriff.
dafür gibts #include <util/atomic.h> mit passenden Makros.
Ich konnte den Fehler weiter eingrenzen.
Zum Hintergrund und dem echten Code. Ich benutze als Interruptquellen:
Timer0 overflow und Timer1 compare match B. Compiler ist der ICCAVR
V7.13
Ein Auskommentieren der OC1B ISR behebt den Fehler ebenso wie das
löschen von volatile.
in der main wird zyklisch folgendes aufgrufen:
1
for(j=0;j<50;j++)
2
{
3
xprintf("%u %u %u %u\r\n",j,test1,test2,test3);
4
WDR();
5
}
test1, test2, test3 sind vom Typ (volatile) unsigned int und lokal
deklariert
hier die Hilfsfunktionen dazu:
1
voidxprintf(constchar*string,...)
2
{
3
va_listargs;
4
charc_cmd;
5
inti_cmd;
6
unsignedintui_cmd;
7
8
va_start(args,string);
9
while(*string)
10
{
11
if(*string=='%')
12
{
13
*string++;
14
if(*string=='c')
15
{
16
c_cmd=va_arg(args,char);
17
PrintInt(c_cmd);
18
}
19
elseif(*string=='i')
20
{
21
i_cmd=va_arg(args,int);
22
PrintInt(i_cmd);
23
}
24
elseif(*string=='u')
25
{
26
ui_cmd=va_arg(args,unsignedint);
27
PrintUInt(ui_cmd);
28
}
29
else
30
{
31
USART_Transmit_Char('%');
32
USART_Transmit_Char(*string);
33
}
34
*string++;
35
}
36
else
37
{
38
USART_Transmit_Char(*string++);
39
}
40
}
41
va_end(args);
42
}
43
44
voidPrintUInt(unsignedinta)
45
{
46
47
charbuf[6];
48
chari=0;
49
50
do
51
{
52
buf[i]=a%10+'0';
53
a=a/10;
54
i++;
55
}
56
while(a);
57
58
do
59
USART_Transmit_Char(buf[--i]);
60
while(i>0);
61
}
und hier die besagte ISR, die wenn ich ihren Inhalt lösche den Fehler
behebt:
Tim schrieb:
> und hier die besagte ISR, die wenn ich ihren Inhalt lösche den Fehler> behebt
Dann klammere den 2. Teil der ISR aus und schau ob der Fehler immer noch
auftritt. Falls ja noch weiter ausklammern...
Wenn der Fehler leicht reproduzierbar ist, solltest Du schnell
auf die Stelle kommen, die den Fehler verursacht.
Es scheint irgendwie ein 0x0A ("\n") in den Speicher geschrieben
zu werden, weiter hinten dann ein 0x09. Gib die Werte mal statt
mit "%u" mit "%x" aus, dann siehst du bei den Zählern eher,
wo was mit welchem Wert überschrieben wird.
Tim blickst du durch deine Klammerung bei deinem IF-Konstrukt in der ISR
überhaupt durch?
Ich jedenfalls nicht, deshalb habe ich den Teil mal etwas leserlicher
gemacht:
Vielleicht wird cnt aber auch anders initialisiert dann aber auch mehr
oder weniger mit einem zufälligem Wert.
Die anderen Funktionen sehen soweit ganz ok aus.
Tim schrieb:> test1, test2, test3 sind vom Typ (volatile) unsigned int und lokal> deklariert
Warum test1, test2, test3 volatile wenn du sie nur lokal verwendest, was
versprichst du dir davon?
M. K. schrieb:> Ändere in deiner xprintf-Funktion mal die Ausdrücke *string++ in> *(string++) vielleicht hilft das deinem Compiler etwas auf die Sprünge.
Na ja, da die Funktion augenscheinlich das tut, was sie soll, und die
erste Schreibweise eindeutig im Sinnne des C-Standards ist, sollte das
nicht das Problem sein.
In der ISR passiert eigentlich nichts, was andere Speicherbereiche in
Mitleidenschaft ziehen könnte. Selbst das nicht initialisierte cnt stört
da nicht. Insofern liegt das Problem ziemlich sicher ganz woanders.
Ich weiß jetzt nicht, was das IAR-System für debug- und
Simulationsmöglichkeiten bietet. Ein Data-breakpoint auf den
korrumpierten Datenspeicheradressen sollte über das Problem schnell
Aufschluss geben.
Oliver
Tim schrieb:> In meinem aktuellen Projekt zerstört das Hinzufügen von "volatile" bei> häufigen Aufrufen den Variableninhalt.
Nö.
Volatile Speicher wird an einer anderen Adresse angelegt, an der es
zufälliger Weise auffällt, daß jemand Speicher überschreibt.
Volatile ist also nicht der Sündenbock, es macht die Sünde nur sichtbar.
Peter
M. K. schrieb:> Streicht man alles raus was nicht ausgeführt wird, weil cnt immer 0 ist> kommt folgendes dabei raus
Nur ist cnt nicht immer 0.
Hier mal das was "indent" draus macht (wozu hat man Maschinen ;-),
passend eingedampft:
1
void
2
OC1B_isr(void)
3
{
4
staticunsignedcharcnt;
5
6
switch(cnt%8)
7
{
8
case4:
9
...
10
break;
11
case0:
12
...
13
break;
14
}
15
16
if(cnt==199)
17
{
18
...
19
cnt=0;
20
...
21
}
22
else
23
cnt++;
24
}
Vielleicht hat er Tabs verwendet, das ist bei Inline-Code im Forum
absolut tödlich.
Lokale als "static" deklarierte Variablen sind mit 0 initialisiert.
A. K. schrieb:> M. K. schrieb:>>> Streicht man alles raus was nicht ausgeführt wird, weil cnt immer 0 ist>> kommt folgendes dabei raus>> Nur ist cnt nicht immer 0.A. K. schrieb:> Lokale als "static" deklarierte Variablen sind mit 0 initialisiert.
Hier widersprichst du dir gerade selbst, schaust du dir die Deklaration
von cnt an, ist diese in der ISR lokal und static.
Da 0 % 8 = 0 ist wird immer der Block für 0 ausgeführt, also kann man
den kompletten Switch-Block entfernen und nur noch den Inhalt des case 0
behlaten.
Die If-Abfrage wird auch nie true liefern weil cnt nie 199 wird, bis auf
den letzten else-Zweig kann also alles weg.
A. K. schrieb:> Vielleicht hat er Tabs verwendet, das ist bei Inline-Code im Forum> absolut tödlich.
Das weiß ich auch, erklärt aber nicht das man sich Klammern einspart und
so mehrdeutige if-else Verschachtelungen hervorbringt.
M. K. schrieb:> Die If-Abfrage wird auch nie true liefern weil cnt nie 199 wird, bis auf> den letzten else-Zweig kann also alles weg.
Natürlich wird cnt irgendwann auch mal 199 (wenn die ISR nicht vor dem
199zigsten Durchlauf disabled wird). Das ist eine zyklisch aufgerufene
Timer-ISR, und bei jedem Aufruf wird cnt inkrementiert.
M. K. schrieb:> und> so mehrdeutige if-else Verschachtelungen hervorbringt.
Da ist nichts mehrdeutig.
Das alles hat aber gar nichts mit dem Problem zu tun. Das steckt ganz
woanders.
Oliver
M. K. schrieb:> Hier widersprichst du dir gerade selbst, schaust du dir die Deklaration> von cnt an, ist diese in der ISR lokal und static.
Ja und? Sie ist mit Null initialisiert, einmalig beim Programmstart.
Jede spätere Veränderung bleibt erhalten.
A. K. schrieb:> Ja und? Sie ist mit Null initialisiert, einmalig beim Programmstart.> Jede spätere Veränderung bleibt erhalten.
Ahh ok das ist schon eine ganz andere Aussage, dann revidiere ich meine
Aussage!
Oliver schrieb:> Das alles hat aber gar nichts mit dem Problem zu tun. Das steckt ganz> woanders.
Sehe ich genau so.
Guten Abend an alle!
Meines Wissens nach werden lokale static Variable immer mit 0
initialisiert. OC1B_isr() macht an sich das was es soll recht gut und
zwar PWM synchron Messwerte aufnehmen.
Ich habe noch vergessen zu erwähnen, dass das Schreiben auf das Terminal
interruptgesteuert abläuft. Meine Vermutung ist, dass sich die
Interruptaufrufe gegenseitig negativ beeinflussen. Ich habe keine
Möglichkeit in Hardware zu debuggen aber ich werde mal versuchen etwas
mit breakpoints zu spielen und längere Passagen durch den Debugger
laufen zu lassen. Als Programmierumgebung ist mir das AVR Studio auf dem
ICCAVR vorgegeben. Das heißt ich kann den Debugger aus dem AVR Studio
nutzen. Allerdings muss ich mich in Sachen Debugging erst ein wenig
einarbeiten