Forum: Compiler & IDEs Absturz beim Verwenden von volatile


von Hundertvolt (Gast)


Lesenswert?

Hallo,

ich versuche, eine interruptgesteuerte Impulserkennung für eine Funkuhr 
auf einem ATMega32 zu programmieren. Dabei ist es immer wieder passiert, 
dass der Prozessor abgestürzt ist. Ich habe das ganze systematisch immer 
weiter reduziert, bis nur noch der problematische Code übrig war (von 
Impulserkennung ist da nix mehr übrig, Interrupts gibts auch keine 
mehr):
1
include <util/delay.h>
2
#include <avr/io.h>
3
4
5
volatile unsigned char DCFErr; 
6
7
8
int main (void) {      
9
10
11
 DDRD |= ((1 << PD5) | (1 << PD6) | (1 << PD4));  // Ausgangsports setzen          
12
 _delay_ms(1500);                  // kurze Verzögerung
13
14
15
 while(1) {                              // Hauptschleife
16
17
  if  (PIND & (1 << PD3))            // Taster an Pin 3 abfragen
18
    {
19
    PORTD &= ~(1<<PD5);              // LED an Pin 5 aus
20
    } 
21
    
22
  else
23
    {
24
    PORTD |= (1<<PD5);                // LED an Pin 5 an
25
    }
26
27
28
  if (DCFErr == 1)    
29
    {
30
    DCFErr = 0;
31
    }
32
33
      }       //while                   
34
  
35
   return 0;                        // nie erreicht        
36
}             // main

Ich frage da eine Taste ab und setzt eine LED invertiert dazu 
(eigentlich nur zur Absturzkontrolle). Dazu wird die Variable DCFerr 
überprüft.

Wenn ich die Taste nur oft genug oder schnell genug drücke, bleibt die 
LED für die Delay-Zeit im letzen angenommenen Zustand, dann geht es 
wieder - offensichtlich springt er unter bestimmten Umständen an den 
Anfang der main-Funktion!

Es gibt 2 sinnlose Abstellmaßnahmen:
1. die Variable DCFErr innerhalb der main-Funktion zu deklarieren 
(sinnlos, da im richtigen Programm Interrupts und Funktionen global 
darauf zugreifen sollen)
2. den Zugriff auf die Variable wegfallen lassen, also die "If (DCFerr 
== 1)"...  (auch sinnlos, aus o.g. Gründen).

Wie kann der µC dadurch an den Anfang der "main" geraten?? Wieso klappt 
ein simpler Variablenzugriff nicht? Was hat das Drücken der Taste mit 
der Variablen zu tun??!! Es macht übrigens keinen Unterschied ob ein 
"volatile" davor steht oder nicht. Hardwarefehler ist es definitiv 
nicht!

von Oliver (Gast)


Lesenswert?

>Wie kann der µC dadurch an den Anfang der "main" geraten??

An den Anfang der der main kommt man nur nach nach einem reset oder, mit 
der avr-libc, durch einen Interrupt ohne ISR, aber nicht durch deine 
paar Zeilen. Da du anscheinend keine Interrupts benutzt, bleibt nur ein 
reset. Wodurch der ausgelöst wird, musst du rausfinden. Störungen auf 
der Versorgungsspannung, am Reset-pin, wo auch immer.

Oliver

von Peter D. (peda)


Lesenswert?

Oliver schrieb:
> Da du anscheinend keine Interrupts benutzt, bleibt nur ein
> reset.

Es gibt da ein verbreitetes AVR-Board, welches Tasten gegen VCC an 
Kondensatoren gegen GND schaltet -> schwerer Schaltungsfehler!

Bei jedem Drücken schließt man also für einige µs die VCC kurz, bis der 
Kondensator aufgeladen ist.
Ideal für unerwünschte Resets.


Richtig wäre:
- Taste gegen GND,
- interner Pullup ein,
- kein Kondensator!!!


Peter

von Hundertvolt (Gast)


Lesenswert?

Das ist es nicht, diese Möglichkeiten hab ich ausgeschlossen.
Ein hardwareseitiger Reset ließe sich nicht durch eine anders 
deklarierte Variable entfernen. Da würde auch nicht die LED im letzten 
Zustand bleiben. Aber ein Sprung an den Anfang der "main" ist es mit 
Sicherheit, da sich die Zeit, in der die LED in diesem Zustand bleibt, 
mit den Delay einstellen lässt!

von Stefan E. (sternst)


Lesenswert?

Dann poste doch bitte mal den kompletten generierten Assembler-Code. Am 
besten das LSS-File.

von Micro M. (micromann)


Lesenswert?

watchdog geprüft?
bss section geprüft?
Verhält es sich anders, wenn die Variable bei der Definition 
initialisiert wird?

Stack overflow?

von Hundertvolt (Gast)


Lesenswert?

Okay, ist das vielleicht das Pollin-Evalboard? Das Ding benutze ich 
jedenfalls. Da sind 330pF drin, glaube kaum, dass die so viel 
Spannungseinbruch machen können...

Ist ja kein Akt die Dinger auszulöten, aber erklärt das, warum sich das 
Verhalten mit der Variablendeklaration ändert?

von Hundertvolt (Gast)


Lesenswert?

Hier das Disassembly - die Sprungadressen am Ende scheinen tatsächlich 
an den Anfang der main zu führen:
1
main.elf:     file format elf32-avr
2
3
Sections:
4
Idx Name          Size      VMA       LMA       File off  Algn
5
  0 .text         000000b0  00000000  00000000  00000074  2**1
6
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
7
  1 .bss          00000001  00800060  00800060  00000124  2**0
8
                  ALLOC
9
  2 .debug_aranges 00000020  00000000  00000000  00000124  2**0
10
                  CONTENTS, READONLY, DEBUGGING
11
  3 .debug_pubnames 00000026  00000000  00000000  00000144  2**0
12
                  CONTENTS, READONLY, DEBUGGING
13
  4 .debug_info   00000137  00000000  00000000  0000016a  2**0
14
                  CONTENTS, READONLY, DEBUGGING
15
  5 .debug_abbrev 000000d0  00000000  00000000  000002a1  2**0
16
                  CONTENTS, READONLY, DEBUGGING
17
  6 .debug_line   00000135  00000000  00000000  00000371  2**0
18
                  CONTENTS, READONLY, DEBUGGING
19
  7 .debug_frame  00000020  00000000  00000000  000004a8  2**2
20
                  CONTENTS, READONLY, DEBUGGING
21
  8 .debug_str    000000b2  00000000  00000000  000004c8  2**0
22
                  CONTENTS, READONLY, DEBUGGING
23
  9 .debug_loc    00000018  00000000  00000000  0000057a  2**0
24
                  CONTENTS, READONLY, DEBUGGING
25
26
Disassembly of section .text:
27
28
00000000 <__vectors>:
29
   0:  0c 94 2a 00   jmp  0x54  ; 0x54 <__ctors_end>
30
   4:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
31
   8:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
32
   c:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
33
  10:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
34
  14:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
35
  18:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
36
  1c:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
37
  20:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
38
  24:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
39
  28:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
40
  2c:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
41
  30:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
42
  34:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
43
  38:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
44
  3c:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
45
  40:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
46
  44:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
47
  48:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
48
  4c:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
49
  50:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
50
51
00000054 <__ctors_end>:
52
  54:  11 24         eor  r1, r1
53
  56:  1f be         out  0x3f, r1  ; 63
54
  58:  cf e5         ldi  r28, 0x5F  ; 95
55
  5a:  d8 e0         ldi  r29, 0x08  ; 8
56
  5c:  de bf         out  0x3e, r29  ; 62
57
  5e:  cd bf         out  0x3d, r28  ; 61
58
59
00000060 <__do_clear_bss>:
60
  60:  10 e0         ldi  r17, 0x00  ; 0
61
  62:  a0 e6         ldi  r26, 0x60  ; 96
62
  64:  b0 e0         ldi  r27, 0x00  ; 0
63
  66:  01 c0         rjmp  .+2        ; 0x6a <.do_clear_bss_start>
64
65
00000068 <.do_clear_bss_loop>:
66
  68:  1d 92         st  X+, r1
67
68
0000006a <.do_clear_bss_start>:
69
  6a:  a1 36         cpi  r26, 0x61  ; 97
70
  6c:  b1 07         cpc  r27, r17
71
  6e:  e1 f7         brne  .-8        ; 0x68 <.do_clear_bss_loop>
72
  70:  0e 94 3e 00   call  0x7c  ; 0x7c <main>
73
  74:  0c 94 56 00   jmp  0xac  ; 0xac <_exit>
74
75
00000078 <__bad_interrupt>:
76
  78:  0c 94 00 00   jmp  0  ; 0x0 <__vectors>
77
78
0000007c <main>:
79
80
81
int main (void) {      
82
83
84
 DDRD |= ((1 << PD5) | (1 << PD6) | (1 << PD4));  // Ausgangsports setzen          
85
  7c:  81 b3         in  r24, 0x11  ; 17
86
  7e:  80 67         ori  r24, 0x70  ; 112
87
  80:  81 bb         out  0x11, r24  ; 17
88
  82:  88 e9         ldi  r24, 0x98  ; 152
89
  84:  9a e3         ldi  r25, 0x3A  ; 58
90
    milliseconds can be achieved.
91
 */
92
void
93
_delay_loop_2(uint16_t __count)
94
{
95
  __asm__ volatile (
96
  86:  20 e9         ldi  r18, 0x90  ; 144
97
  88:  31 e0         ldi  r19, 0x01  ; 1
98
  8a:  f9 01         movw  r30, r18
99
  8c:  31 97         sbiw  r30, 0x01  ; 1
100
  8e:  f1 f7         brne  .-4        ; 0x8c <main+0x10>
101
    __ticks = (uint16_t) (__ms * 10.0);
102
    while(__ticks)
103
    {
104
      // wait 1/10 ms
105
      _delay_loop_2(((F_CPU) / 4e3) / 10);
106
      __ticks --;
107
  90:  01 97         sbiw  r24, 0x01  ; 1
108
    __ticks = 1;
109
  else if (__tmp > 65535)
110
  {
111
    //  __ticks = requested delay in 1/10 ms
112
    __ticks = (uint16_t) (__ms * 10.0);
113
    while(__ticks)
114
  92:  d9 f7         brne  .-10       ; 0x8a <main+0xe>
115
 _delay_ms(1500);                  // kurze Verzögerung
116
117
118
 while(1) {                              // Hauptschleife
119
120
  if  (PIND & (1 << PD3))            // Taster an Pin 3 abfragen
121
  94:  83 9b         sbis  0x10, 3  ; 16
122
  96:  02 c0         rjmp  .+4        ; 0x9c <main+0x20>
123
    {
124
    PORTD &= ~(1<<PD5);              // LED an Pin 5 aus
125
  98:  95 98         cbi  0x12, 5  ; 18
126
  9a:  01 c0         rjmp  .+2        ; 0x9e <main+0x22>
127
    } 
128
    
129
  else
130
    {
131
    PORTD |= (1<<PD5);                // LED an Pin 5 an
132
  9c:  95 9a         sbi  0x12, 5  ; 18
133
    }
134
135
136
  if (DCFErr == 1)    
137
  9e:  80 91 60 00   lds  r24, 0x0060
138
  a2:  81 30         cpi  r24, 0x01  ; 1
139
  a4:  b9 f7         brne  .-18       ; 0x94 <main+0x18>
140
    {
141
    DCFErr = 0;
142
  a6:  10 92 60 00   sts  0x0060, r1
143
  aa:  f4 cf         rjmp  .-24       ; 0x94 <main+0x18>
144
145
000000ac <_exit>:
146
  ac:  f8 94         cli
147
148
000000ae <__stop_program>:
149
  ae:  ff cf         rjmp  .-2        ; 0xae <__stop_program>

von Stefan E. (sternst)


Lesenswert?

> die Sprungadressen am Ende scheinen tatsächlich
> an den Anfang der main zu führen

Wo? Ich sehe da nichts.

von Karl H. (kbuchegg)


Lesenswert?

Hundertvolt schrieb:
> Hier das Disassembly - die Sprungadressen am Ende scheinen tatsächlich
> an den Anfang der main zu führen:

Schon.
Aber da kommt er nie hin.

Ein paar Zeilen drüber

>  a4:  b9 f7         brne  .-18       ; 0x94 <main+0x18>
>  a6:  10 92 60 00   sts  0x0060, r1
>  aa:  f4 cf         rjmp  .-24       ; 0x94 <main+0x18>


Das ist das untere Ende der Endloschleife, wos wieder an den Anfang 
geht.

Wenn du nicht hundert Prozent sicher bist, ob der µC resettet, dann lass 
doch ganz am Anfang eine 2. Led einschalten, die du nach dem delay 
wieder ausschaltest. Dann hast du eine optische Kontrolle, ob ein Reset 
erfolgt ist.

Ich denke auch, dass es irgendein Hardwareproblem ist.
Das das bei deinen Versuchen anscheinend mit dem volatile korreliert 
hat, dürfte Zufall gewesen sein.

von Stefan E. (sternst)


Lesenswert?

Karl heinz Buchegger schrieb:
> Hundertvolt schrieb:
>> Hier das Disassembly - die Sprungadressen am Ende scheinen tatsächlich
>> an den Anfang der main zu führen:
>
> Schon.
> Aber da kommt er nie hin.

Hä?
Kann mich mal jemand aufklären, wo da ein Sprung nach main sein soll?

von Karl H. (kbuchegg)


Lesenswert?

Stefan Ernst schrieb:

> Kann mich mal jemand aufklären, wo da ein Sprung nach main sein soll?

Hast natürlich recht.
Es gibt keinen Sprung ganz an den Programmanfang

von Karl H. (kbuchegg)


Lesenswert?

Karl heinz Buchegger schrieb:

> Das ist das untere Ende der Endloschleife, wos wieder an den Anfang
> geht.

Nur damits keine Missverständnisse gibt:
Mit "an den Anfang" ist das obere Ende der Endlosschleife gemeint.

Keinesfalls aber der Programmanfang.

(Ich hab jetzt die Adressen nicht nachgerechnet, denke aber nicht, dass 
der gcc in seinen Kommentaren lügt)

von Roland Praml (Gast)


Lesenswert?

man könnte auch das MCUCR-Register abfragen. Darin steht der Resetgrund

Gruß
Roland

von Oliver (Gast)


Lesenswert?

>> Hier das Disassembly - die Sprungadressen am Ende scheinen tatsächlich
>> an den Anfang der main zu führen:

>Schon.
>Aber da kommt er nie hin.

Der Anfang von main ist bei 0x7C. Und da wird genau einmal 
hingesprungen, bzw. "gecallt". Am Programmende steht die 
exit-Endlosschleife, da kommt er nie hin. Davor, am Ende von main, gibt 
es die Sprünge nach 0x94, dem Anfang der while-Schleife. Im ganzen 
Hauptprogramm gibt es nirgends Sprünge auf den Anfang von main.

>Hardwarefehler ist es definitiv nicht!

Ein Softwarefehler ist es noch definitiver nicht.

Oliver

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Hundertvolt schrieb:
> Hallo,
>
> ich versuche, eine interruptgesteuerte Impulserkennung für eine Funkuhr
> auf einem ATMega32 zu programmieren.

Unabhängig von deinen Problemen ist das nicht ratsam. Günstiger ist es, 
zB alle 10ms in einer ISR auf den Port zu schauen, an dem das DCF-Modul 
hängt.

Die Flanken sind nicht so sauber, wie man vielleicht glaubt, also 
gleiches Thema wie beim Taster-Entprellen . Ausserdem belegt's dann 
keinen INT-Port.

Ne Zeitbasis wie 10ms hat man eh in den meisten Anwendungen, also 
einfach da reinklinken.

Johann

von Peter D. (peda)


Lesenswert?

Möglich:

- der Programmer lädt ein völlig anderes HEX
- Du machst kein Löschen vor dem Programmieren und kein Verify


Peter

von Hundertvolt (Gast)


Lesenswert?

Danke für Eure Tips, ich hab ein bisschen rumgebastelt.
Anscheinend waren es echt die Kondensatoren in den Tasten, ohne die 
funktionierts. Vielleicht sollte ich die BOD im Mega32 einschalten, 
offensichtlich hat es zu einem Reset gereicht, dass der PC auf 0 gesetzt 
wurde, aber die Registerinhalte z.T. übrig blieben.

Was baut Pollin denn da für einen Mist?! Erst die Kondensatoren, und 
dann das: Ich hab mir das Erweiterungsboard fürs Evalboard geholt, haben 
die tatsächlich die Pinbelegung für den 40poligen Verbindungsstecker 
verbockt; die Stromversorgung darüber geht, aber die Portpins sind 
völlig durcheinandergeschmissen...  gibts einen Thread für sowas, wo 
solche Bugs zu finden sind? Nicht, dass ich da in noch so eine 
bescheuerte Falle laufe...

von Klaus (Gast)


Lesenswert?

> Was baut Pollin denn da für einen Mist?!

So langsam sollte es sich doch bis zum letzen rumgesprochen haben, dass 
Pollin nur ein etwas besserer Schrotthändler 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.