Forum: Mikrocontroller und Digitale Elektronik ATmega1284P 6tes Bit wird gelöscht


von Andreas H. (heilinger)


Angehängte Dateien:

Lesenswert?

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.

von Peter (Gast)


Lesenswert?

>"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"

von Thomas (kosmos)


Lesenswert?

simulier das ganze im AVR-Studio Schritt für Schritt und schau dir das 
entsprechende Bit im Register an um rauszufinden wo/wann es geändert 
wird.

von Andreas H. (heilinger)


Lesenswert?

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.

von Oliver (Gast)


Lesenswert?

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.

von Peter (Gast)


Lesenswert?

>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!

von 900ss (900ss)


Lesenswert?

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

von Andreas H. (heilinger)


Lesenswert?

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
13
         Tu16 u16_DiffAir;
14
         Tu16 u16_ADD_;
15
16
//Code aus elisa-Flowregelung
17
  u16_DiffAir = u16_AIRFlowInZehntellmin - (u16_StatAIRFlowSollZehntellmin + u16_VarAIRFlowSollZehntellmin);
18
19
  u16_DummyAir1 = u16_AIRFlowInZehntellmin + 64;                     // Minimum 4-fach
20
  if (u16_DummyAir1 > WERT_MAX) 
21
    u16_DummyAir1 = WERT_MAX;                                        // Maximum 1-fach
22
23
  if ((u16_DiffAir & 0x8000) == 0x8000)                              // Ist < soll; PWM - erhöhen
24
  {
25
                                                                     // bei kleinem Flow schneller
26
    u16_DummyAir2 = (Tu16)0 - u16_DiffAir;
27
28
    if(u16_DummyAir2 <= DIFF_MAX) 
29
      u16_ADD_ = ((u16_DummyAir2   * FAKTOR_FLOWREGELUNG) / u16_DummyAir1);
30
    else                   
31
      u16_ADD_ = ((DIFF_MAX * FAKTOR_FLOWREGELUNG) / u16_DummyAir1);
32
  }
33
  else
34
  {                                                                  // Ist > soll -> langsamer /2
35
    if (u16_DiffAir  <= DIFF_MAX) 
36
      u16_ADD_ = ((u16_DiffAir * FAKTOR_FLOWREGELUNG) / u16_DummyAir1) / 2;
37
    else
38
      u16_ADD_ = ((DIFF_MAX    * FAKTOR_FLOWREGELUNG) / u16_DummyAir1) / 2;
39
40
    u16_ADD_ = (Tu16)0 - u16_ADD_;                                   // hier negativ
41
  }
42
43
  if (u16_ADD_ & 0x8000)                                             // PWM - verkleinern
44
  {
45
    if (u16_PWMAir10bit64fach > (Tu16)(IFLOW_PWMIN - u16_ADD_))
46
      u16_PWMAir10bit64fach = u16_PWMAir10bit64fach + u16_ADD_;
47
    else
48
      u16_PWMAir10bit64fach = IFLOW_PWMIN;
49
  }
50
  else                                                               // PWM - vergroessern
51
  { 
52
    if (u16_PWMAir10bit64fach < (Tu16)(IFLOW_PWMAX - u16_ADD_))
53
      u16_PWMAir10bit64fach = u16_PWMAir10bit64fach + u16_ADD_;
54
    else
55
      u16_PWMAir10bit64fach = IFLOW_PWMAX;
56
  }
57
//Code aus elisa-Flowregelung zu Ende
58
59
  u16_DummyFlowAir = PWM_MAX - (u16_PWMAir10bit64fach / 64);
60
  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

von Peter D. (peda)


Lesenswert?

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

von Andreas H. (heilinger)


Lesenswert?

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?
1
#define UBRR_19k2                             129
2
#define ARRAYGROESSE_O2SENSOR                  9
3
4
void USART1_init(Tu16 u16_Ubrr1)
5
{
6
  UBRR1H = (Tu8) (u16_Ubrr1>>8);                                     
7
  UBRR1L = (Tu8) u16_Ubrr1;
8
  
9
  UCSR1C = (1<<UCSZ11) | (1<<UCSZ10); 
10
  UCSR1B = (1<<RXCIE1)|  (1<<TXEN1)  | (1<<RXEN1); 
11
  UCSR1A = (1<<U2X1);  
12
}
13
14
ISR(USART1_RX_vect)
15
{
16
  static Tu8 u8_ZaehlerRXDBytes = 0;
17
         Tu8 u8_EmpfangenesByte;
18
19
  u8_EmpfangenesByte = UDR1;
20
21
22
  if (u8_ZaehlerRXDBytes < ARRAYGROESSE_O2SENSOR)                    
23
    u8_ReceiveRX1[u8_ZaehlerRXDBytes] = u8_EmpfangenesByte;
24
25
  if (u8_EmpfangenesByte == 0x0D)                                    
26
  {
27
    if (u8_ZaehlerRXDBytes < ARRAYGROESSE_O2SENSOR)                  
28
      f120_FlagVol.O2SensorkommunikationKomplett = 1;
29
30
    u8_ZaehlerRXDBytes = 0;
31
  }
32
  else
33
  {
34
    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.

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.