www.mikrocontroller.net

Forum: Compiler & IDEs Absturz beim Verwenden von volatile


Autor: Hundertvolt (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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):
include <util/delay.h>
#include <avr/io.h>


volatile unsigned char DCFErr; 


int main (void) {      


 DDRD |= ((1 << PD5) | (1 << PD6) | (1 << PD4));  // Ausgangsports setzen          
 _delay_ms(1500);                  // kurze Verzögerung


 while(1) {                              // Hauptschleife

  if  (PIND & (1 << PD3))            // Taster an Pin 3 abfragen
    {
    PORTD &= ~(1<<PD5);              // LED an Pin 5 aus
    } 
    
  else
    {
    PORTD |= (1<<PD5);                // LED an Pin 5 an
    }


  if (DCFErr == 1)    
    {
    DCFErr = 0;
    }

      }       //while                   
  
   return 0;                        // nie erreicht        
}             // 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!

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Hundertvolt (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Stefan Ernst (sternst)
Datum:

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

Autor: Micro Mann (micromann)
Datum:

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

Stack overflow?

Autor: Hundertvolt (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Hundertvolt (Gast)
Datum:

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

main.elf:     file format elf32-avr

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         000000b0  00000000  00000000  00000074  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .bss          00000001  00800060  00800060  00000124  2**0
                  ALLOC
  2 .debug_aranges 00000020  00000000  00000000  00000124  2**0
                  CONTENTS, READONLY, DEBUGGING
  3 .debug_pubnames 00000026  00000000  00000000  00000144  2**0
                  CONTENTS, READONLY, DEBUGGING
  4 .debug_info   00000137  00000000  00000000  0000016a  2**0
                  CONTENTS, READONLY, DEBUGGING
  5 .debug_abbrev 000000d0  00000000  00000000  000002a1  2**0
                  CONTENTS, READONLY, DEBUGGING
  6 .debug_line   00000135  00000000  00000000  00000371  2**0
                  CONTENTS, READONLY, DEBUGGING
  7 .debug_frame  00000020  00000000  00000000  000004a8  2**2
                  CONTENTS, READONLY, DEBUGGING
  8 .debug_str    000000b2  00000000  00000000  000004c8  2**0
                  CONTENTS, READONLY, DEBUGGING
  9 .debug_loc    00000018  00000000  00000000  0000057a  2**0
                  CONTENTS, READONLY, DEBUGGING

Disassembly of section .text:

00000000 <__vectors>:
   0:  0c 94 2a 00   jmp  0x54  ; 0x54 <__ctors_end>
   4:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
   8:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
   c:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
  10:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
  14:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
  18:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
  1c:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
  20:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
  24:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
  28:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
  2c:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
  30:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
  34:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
  38:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
  3c:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
  40:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
  44:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
  48:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
  4c:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>
  50:  0c 94 3c 00   jmp  0x78  ; 0x78 <__bad_interrupt>

00000054 <__ctors_end>:
  54:  11 24         eor  r1, r1
  56:  1f be         out  0x3f, r1  ; 63
  58:  cf e5         ldi  r28, 0x5F  ; 95
  5a:  d8 e0         ldi  r29, 0x08  ; 8
  5c:  de bf         out  0x3e, r29  ; 62
  5e:  cd bf         out  0x3d, r28  ; 61

00000060 <__do_clear_bss>:
  60:  10 e0         ldi  r17, 0x00  ; 0
  62:  a0 e6         ldi  r26, 0x60  ; 96
  64:  b0 e0         ldi  r27, 0x00  ; 0
  66:  01 c0         rjmp  .+2        ; 0x6a <.do_clear_bss_start>

00000068 <.do_clear_bss_loop>:
  68:  1d 92         st  X+, r1

0000006a <.do_clear_bss_start>:
  6a:  a1 36         cpi  r26, 0x61  ; 97
  6c:  b1 07         cpc  r27, r17
  6e:  e1 f7         brne  .-8        ; 0x68 <.do_clear_bss_loop>
  70:  0e 94 3e 00   call  0x7c  ; 0x7c <main>
  74:  0c 94 56 00   jmp  0xac  ; 0xac <_exit>

00000078 <__bad_interrupt>:
  78:  0c 94 00 00   jmp  0  ; 0x0 <__vectors>

0000007c <main>:


int main (void) {      


 DDRD |= ((1 << PD5) | (1 << PD6) | (1 << PD4));  // Ausgangsports setzen          
  7c:  81 b3         in  r24, 0x11  ; 17
  7e:  80 67         ori  r24, 0x70  ; 112
  80:  81 bb         out  0x11, r24  ; 17
  82:  88 e9         ldi  r24, 0x98  ; 152
  84:  9a e3         ldi  r25, 0x3A  ; 58
    milliseconds can be achieved.
 */
void
_delay_loop_2(uint16_t __count)
{
  __asm__ volatile (
  86:  20 e9         ldi  r18, 0x90  ; 144
  88:  31 e0         ldi  r19, 0x01  ; 1
  8a:  f9 01         movw  r30, r18
  8c:  31 97         sbiw  r30, 0x01  ; 1
  8e:  f1 f7         brne  .-4        ; 0x8c <main+0x10>
    __ticks = (uint16_t) (__ms * 10.0);
    while(__ticks)
    {
      // wait 1/10 ms
      _delay_loop_2(((F_CPU) / 4e3) / 10);
      __ticks --;
  90:  01 97         sbiw  r24, 0x01  ; 1
    __ticks = 1;
  else if (__tmp > 65535)
  {
    //  __ticks = requested delay in 1/10 ms
    __ticks = (uint16_t) (__ms * 10.0);
    while(__ticks)
  92:  d9 f7         brne  .-10       ; 0x8a <main+0xe>
 _delay_ms(1500);                  // kurze Verzögerung


 while(1) {                              // Hauptschleife

  if  (PIND & (1 << PD3))            // Taster an Pin 3 abfragen
  94:  83 9b         sbis  0x10, 3  ; 16
  96:  02 c0         rjmp  .+4        ; 0x9c <main+0x20>
    {
    PORTD &= ~(1<<PD5);              // LED an Pin 5 aus
  98:  95 98         cbi  0x12, 5  ; 18
  9a:  01 c0         rjmp  .+2        ; 0x9e <main+0x22>
    } 
    
  else
    {
    PORTD |= (1<<PD5);                // LED an Pin 5 an
  9c:  95 9a         sbi  0x12, 5  ; 18
    }


  if (DCFErr == 1)    
  9e:  80 91 60 00   lds  r24, 0x0060
  a2:  81 30         cpi  r24, 0x01  ; 1
  a4:  b9 f7         brne  .-18       ; 0x94 <main+0x18>
    {
    DCFErr = 0;
  a6:  10 92 60 00   sts  0x0060, r1
  aa:  f4 cf         rjmp  .-24       ; 0x94 <main+0x18>

000000ac <_exit>:
  ac:  f8 94         cli

000000ae <__stop_program>:
  ae:  ff cf         rjmp  .-2        ; 0xae <__stop_program>

Autor: Stefan Ernst (sternst)
Datum:

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

Wo? Ich sehe da nichts.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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)

Autor: Roland Praml (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
man könnte auch das MCUCR-Register abfragen. Darin steht der Resetgrund

Gruß
Roland

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Möglich:

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


Peter

Autor: Hundertvolt (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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...

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.