Hallo,
habe ein Problem, was wohl tiefgründiger zu finden ist.
Ich benutze einen ATmega1284P mit dem AVR Studio und WinAVR-20100110.
Nun zum Problem:
Ich hatte mir eine Struktur gebaut um Flags zu setzen/löschen, die
folgendermaßen aussieht:
1
typedef struct /*TsFlags*/
2
{
3
unsigned AlarmbuttonPushed; : 1;
4
unsigned EinAusbuttonPushed; : 1;
5
unsigned FlowprofilStarten; : 1;
6
unsigned PEEPFlowprofilDurchgefuehrt; : 1;
7
8
unsigned StoppuhrAuf0; : 1;
9
unsigned LCDReady; : 1;
10
unsigned FreigabeGeraetAusschalten; : 1;
11
unsigned TouchscreenKalibriert; : 1;
12
13
[weitere Flags, immer nur ein Bit]
14
} TsFlags;
Nun hatte ich das Problem, dass das Flag LCDReady während der Laufzeit
gelöscht wird. Dieses wird in meinem Code nur gesetzt nach dem ich mein
LCD Display intialisiert habe, wird von mir im Code aber nie gelöscht.
Ich frage nur ab, ob es gesetzt ist in einer if-Verzweigung, was in
einem Interrupt geschieht.
Auffällig hierbei ist, dass das Flag LCDReady das 6. Bit ist. Ich hatte
vor dem ersten Bit 8 Dummybits eingefügt, um die Adresse der
nachfolgenden Bits um ein Byte zu verschieben. Das Problem war aber nach
wie vor vorhanden. Ich habe dann die Elemente in der Struktur von
"unsigned" zu "unsigned char" geändert und das Problem ist nicht mehr
aufgetreten. Es sei noch erwähnt, dass der code an dem ich das Flag
setze und abfrage bereits Wochen vorher porgrammiert wurde und bis dahin
ohne Probleme lief.
Das Problem war aber natürlich nicht gelöst, sondern erstmal umgangen.
Nun nach ein paar Wochen macht sich erneut ein solches Problem
bemerkbar:
Eine Variable (16 Bit), die ich für die Regelung eines Ventils benutze
springt auf dem 6. Bit.
Ich habe ein Tool auf dem PC wo ich mir jede Millisekunde 4 Variablen
anzeigen lassen kann, synchron zu meinem 1kHz-Timer als Interrupt.
Dort ist zu sehen, dass sich die Regelvariable vom Wert 28628 auf 20431
ändert. Die Änderung in den niederwertigen Bits kommt durch den
Regelalgorithmus zustande. Und zusätzlich wird eben das 6. Bit im
höherwertigen Bit gelöscht. Die Regelung läuft stabil und kann so einen
starken Sprung nicht verursachen.
Das gleiche Problem bekomme ich bei der Berechnung eines
Druckmittelwerts. Der Ist-Druck bewegt sich um die 357 und der
berechnete Mittelwert springt von 358 auf 326, ohne das der Istwert
unter einem Wert von 326 liegt. Wieder wird dort das 6. Bit gelöscht.
Die Regelung läuft in einem Interrupt und die Variablen werden auch nur
dort verwendet und werden lokal benutzt.
Was ich bisher gemacht habe:
Arrays auf Überlauf kontrolliert.
Ich benutze keine Pointer um auf eine Adresse zu speichern, sondern nur
zum Lesen von Arrays.
Ich benutze keine unions.
Mein Programm wurde von einem Kollegen gereviewt und dieser konnte auch
kein Bug finden, der dieses Problem auslöst. Mein source code ist über
20 kB, weswegen ich ihn hier nicht posten kann. Es scheint sich um ein
generelles Problem zu handeln und hoffe, dass jemand einen Tipp hat wie
so etwas zustande kommen kann.
Den Sprung der Variablen habe ich grafisch dokumentiert. Wenn es zur
Verständlichkeit beiträgt, kann ich die Bilder posten.
Ich hatte die Flowvariable mal global deklariert, um zu zeigen, auf
welcher Adresse sie sitzt. Im Anhang das Bild dazu. Wenn ich sie global
deklariere, besteht das Problem weiterhin.
>"unsigned" zu "unsigned char" geändert und das Problem ist nicht mehr>aufgetreten.
Das ist eh riesengrosse Scheisse, bloss "unsigned" zu verwenden, ohne
weitern Typ!
"unsigned char" ist schon besser (und meistens portierbar) noch besser
ist es die wirklich portablen Datentübpen zu verwenden wie zum Beispiel
"uint8_t"
Hallo,
wir benutzen folgende Datentypen wegen der Portierbarkeit
1
typedef unsigned char Tu8;
2
typedef signed char Ts8;
3
typedef unsigned short Tu16;
4
typedef signed short Ts16;
5
typedef unsigned long Tu32;
6
typedef signed long Ts32;
Bei dem 8Bit-Typ ist es mir eben egal, ob das 6. Bit manipuliert wird
oder nicht, weil ich ja quasi nur das niederwertigste benutze, was eben
auch ein Hinweis sein könnte, dass nur das 6. Bit manipuliert wird.
Andreas H. schrieb:> Es scheint sich um ein> generelles Problem zu handeln und hoffe, dass jemand einen Tipp hat wie> so etwas zustande kommen kann.
Na ja, entweder ist das 6. Bit in deinem Prozessor kaputt, oder das
Progamm hat doch eine Macke. Die Wahrscheinlichkeit steht 1:1 Zillion
gegen den Prozessorfehler...
Fehler eingrenzen, Code verkleinern, bis was greifbares erkennbar wird.
Oliver
P.S. Dein typedef struct oben ist so nicht kompilierbar.
>wir benutzen folgende Datentypen wegen der Portierbarkeit>>typedef unsigned char Tu8;>typedef signed char Ts8;>typedef unsigned short Tu16;>typedef signed short Ts16;>typedef unsigned long Tu32;>typedef signed long Ts32;
Ist nicht wirklich portabel, es steht nirgends dass short = 16 Bit sein
muss!
Wiese haben so viele Programmierer die unsinnige Idee, sich ihre eigene
Welt zu definieren? Ich sehe immer wieder Dinge wie: u8, u08, U08, UINT8
und so weiter, jetzt kommst Du noch mit Tu8 grrrrrr
=> Es ist schlichtweg idiotisch und sollte verboten werden, irgend was
zu definieren, was nicht schon mit <stdint.h> abgedeckt wird!
Peter schrieb:> Es ist schlichtweg idiotisch und sollte verboten werden, irgend was> zu definieren, was nicht schon mit <stdint.h> abgedeckt wird!
Ich bemerke immer wieder, dass selbst erfahrene Softwareentwickler das
nicht kennen und staune auch immer wieder darüber. Sie benutzen die
wildesten eigenen Typdefinitionen. :-(
stdint.h ist wirklich "Gold" wert.
Edit: Ach ja ist etwas offtopic :-/
Zu euren Anregungen mit den Datentypen. Ich werds mal weiterreichen. Wir
sind gerade dabei uns einen Standard aufzubauen und hatten uns den
MISRA-C-Standard rausgesucht. Keine Ahnung, ob das da auch drinsteht.
Ich habe es halt vorgegeben bekommen...
um nochmal zu dem ursprünglichen Problem zurückzukommen:
Wenn es einen Array-Überlauf gibt bzw. ein Pointer falsch gesetzt sein
sollte, so würde es mich doch wundern, dass immer das 6.Bit betroffen
ist und die anderen Bits dieses Problem nicht aufweisen. Das Kippen des
sechsten Bits kommt sehr unregelmäßig, ist also nicht reproduzierbar.
Ich werde parallel dazu mal eine gleiche Platine mit nem neuen
Mirkocontroller aufbauen und schauen, ob sich diese Symptome erneut
zeigen. Trotzdem würde ich mich noch zu Anregungen freuen, die mein
Problem betreffen.
Ich möchte gerade nochmal ein genaueres Beispiel bringen. Hier der code
dazu.
1
#define PWM_MAX 1023
2
#define FAKTOR_FLOWREGELUNG (Tu16) 256
3
#define DIFF_MAX (Tu16) 255
4
#define WERT_MAX (Tu16) 256
5
#define IFLOW_PWMIN (Tu16) 512
6
#define IFLOW_PWMAX (Tu16) 65023
7
8
void Flowregelung_AIR(void)
9
{
10
static Tu16 u16_DummyFlowAir = 0; //für Änderung des PWM-Signals
11
static Tu16 u16_PWMAir10bit64fach = 0; //64-facher PWM-Wert für AIR-Flow P-Ventil
12
Tu16 u16_DummyAir1, u16_DummyAir2; //Abhängig vom AbsolutWert
OCR1A = u16_DummyFlowAir; //Anpassung des AIR-PWM-Signals, OCR0A = 1023 bedeutet PWM aus
61
62
// OCR1B = 1023; //Anpassung des O2-PWM-Signals
63
}
diese Funktion wird nur aus dem Interrupt aufgerufen. Die Variablen sind
alle lokal, können also woanders nicht manipuliert werden.
Wie im ersten Bild beschrieben handelt es sich um die Variable
"u16_PWMAir10bit64fach". Diese wird eigentlich nur nur durch die
Variable "u16_ADD_" beeinflusst. Ich hatte mir beide Variablen auf dem
PC ausgeben lassen und konnte sehen, dass die Variable
u16_PWMAir10bit64fach sich zeitlich vor der Variable u16_ADD_ ändert,
und diese erst nach ca. 3 weiteren Zyklen als Reaktion sich dann auch
ändert. Das beudetet für mich, dass die Variable "u16_PWMAir10bit64fach"
der Urspung von dem Ganzen ist, wobei sie doch ganz klar von u16_ADD_
abhängt.
Der Wert von u16_ADD_ liegt zwischen +/- 25 und der von
u16_PWMAir10bit64fach bei ca. 29000
Der AVR hat keine Bitbefehle. Er muß also das ganze Byte aus dem SRAM
holen, manipulieren und zurückschreiben.
Wird auch nur ein Bit in einem Interrupt verwendet, müssen sämtliche
Bitzugriffe des selben Bytes im Main atomar gekapselt werden (atomic.h).
Man könnte auch das GPIOR0 verwenden.
Peter
Hallo,
ich bin leider immer noch nicht weitergekommen.
Was ich jedoch sehr seltsam finde:
Ich habe einen Sauerstoffsensor an dem USART1 dranhängen. Wenn ich
diesen abziehe, zeigt sich das oben geschilderte Problem deutlich
öfters. Wenn ich das ganze mit dem O2-Sensor betreibe, reduzieren sich
die vorkomnisse um ein Vielfaches.
Ich benutze nur die RxD-Leitung von Usart1. An die Leitung geht auch ein
4k7 pull-up-Widerstand, also ist der Pegel bei angezogenem Sensor auch
stabil (habe ich auch aufm Scope angeguckt).
Nun hab ich die Initilaisierung des USART1 wegkommentiert, und trotzdem
hat der Anschluss des O2-Sensors dieses Problem.
Hier sind mal die Abschnitte welche den USART1 betreffen, evtl. findet
ihr da ja nen Fehler?
if (u8_ZaehlerRXDBytes < (ARRAYGROESSE_O2SENSOR + 1))
35
u8_ZaehlerRXDBytes++;
36
}
37
}
38
39
40
int main(void)
41
{
42
USART0_init(UBRR_115k2);
43
USART1_init(UBRR_19k2);
44
//...
45
}
Desweiteren kann ich sagen, dass mein komplettes System (also mit
angeschlossener Peripherie) je nach Optimierungsstufe des Compilers
anders reagiert.
Bisher habe ich immer mit der Optimierung -Os kompaliert. Wenn ich mit
-O2 kompaliere reagiert noch alles genauso. Wenn ich jedoch -O2 mit
"finline-functions " bzw. mit -O3 kompaliere, reagiert meine Peripherie
komplett anders, ohne bisher genauer hingesehen zu haben, was genau
anders ist.