Forum: Mikrocontroller und Digitale Elektronik ATMega32 Absturz bei Zeicheneingang


von Andreas B. (bitverdreher)


Angehängte Dateien:

Lesenswert?

Hallo,
nachdem ich mir schon länger den Wolf suche, warum mein ATMega32 immer 
abstürzt wenn ich Zeichen über den Uart (mit gtkterm unter Linux) 
einlaufen lasse, bin ich jetzt endlich mal systematisch vorgegangen und 
habe:

a) an der Hardware alles unnötige entfernt. Es handelt sich hier um eine 
3-Achsenmotorsteuerung mit Encoder usw. Der Max hat einen 100nF direkt 
am Versorgungspin. Am ATMega ebenfalls jeweils PIN 11/12 und 30/31 
100nF.
Die 24V Versorgung und die Motoren wurden entfernt.

b) die SW drastisch reduziert, bis der Absturz nicht auftaucht. Das 
Ergebnis steht hier:
1
/*******************************************************************
2
*
3
* Chip type           : ATmega32
4
* Clock frequency     : 14,745600 MHz
5
* lfuse e1 = 1110 0001 -> 0e = 0000 1110
6
* hfuse 99 = 1001 1001 -> d9 = 1101 1001
7
* avrdude -p atmega32 -P /dev/ttyS0 -b 115200 -c avr910 -U lfuse:w:0x0e:m
8
* avrdude -p atmega32 -P /dev/ttyS0 -b 115200 -c avr910 -U hfuse:w:0xd9:m
9
*
10
*    test.c
11
*
12
* To do:
13
*
14
********************************************************************/
15
16
17
#include "hardwaredef.h"
18
19
#include <avr/io.h>
20
#include <avr/interrupt.h>
21
#include <inttypes.h>
22
#include <stdlib.h>
23
#include <util/delay.h>
24
#include "test.h"
25
26
char sCommandString[BUFFER_LENGHT];
27
char sOutString[BUFFER_LENGHT];
28
29
int8_t execute (const char *text);
30
31
int16_t lCommandPar1;
32
int16_t lCommandPar2;
33
34
// Status and Error Flags
35
volatile int8_t iUartFlags;
36
volatile char sInBuffer[BUFFER_LENGHT];
37
volatile uint8_t iBufferPtr;
38
39
void InitPorts(void) {
40
   // port inputs
41
   DDRA &= ~( (1<<SLID_ENC_1) | (1<<SLID_ENC_2) | (1<<SLID_REF) | (1<<TURN_H_END) );
42
   //   DDRB &= ~( (1<<PB6) );
43
   DDRC &= ~( (1<<VERT_REF) | (1<<VERT_H_END) | (1<<TURN_REF) | (1<<SDA) | (1<<SCL) );
44
   DDRD &= ~( (1<<VERT_ENC_1) | (1<<VERT_ENC_2) | (1<<TURN_ENC_1) | (1<<TURN_ENC_2));
45
   // port outputs
46
   DDRA |= (1 << GRIP) | (1 << RESERVE0) | (1 << RESERVE1);
47
   DDRB |= (1 << SLID_3A) | (1 << SLID_4A) | (1 << TURN_1A) |  (1 << TURN_PWM) | (1 << TURN_2A) | (1 << LASER);
48
   DDRC |= (1 << VERT_DIRECTION) | (1 << VERT_STOP);
49
   DDRD |= (1 << VERT_PWM) | (1 << SLID_PWM);
50
   // activate pullup resistors
51
   PORTA |= ((1<<SLID_ENC_1) | (1<<SLID_ENC_2) | (1<<SLID_REF) | (1<<GRIP));
52
   PORTC |= ((1<<SDA) | (1<<SCL));
53
}
54
55
// ------------------------------------------------------------ IRQ
56
ISR(__vector_default) { UsartPuts ("Undefined IRQ"); }
57
58
59
// ------------------------------------------------------------ USART
60
61
void InitUsart(void) {
62
   UBRRH = (uint8_t)(UART_BAUD_CALC(UART_BAUD_RATE,F_CPU)>>8);       // set baud rate
63
   UBRRL = (uint8_t)UART_BAUD_CALC(UART_BAUD_RATE,F_CPU);
64
   UCSRB = (1 << RXEN) | (1 << TXEN) ;                 // enable receiver and transmitter 
65
   UCSRC = (1 << URSEL) | (1 << UCSZ1) | (1 << UCSZ0) | (1 << UPM1); // asynchronous 8N1, even Parity
66
   do UDR; while (UCSRA & (1 << RXC));                               // flush receiver               
67
}
68
69
70
char GetCommand (int16_t *lPar1, int16_t *lPar2, char *sComm) {
71
//int8_t iRecStrPtr;
72
int8_t iTmpBufferPtr;
73
74
   iTmpBufferPtr = 0;
75
76
    if (iUartFlags & FLAG_COMM_COMP ) {                                                       // Jetzt parsen bis EOS
77
       
78
// UsartPuts ("\n\nHier solls nicht hin\n");
79
//       iRecStrPtr = 0;
80
//       while ((sInBuffer[iTmpBufferPtr] != 0x00) && (sInBuffer[iTmpBufferPtr] != 0x20)) {     // Command, max. String Länge aus ISR gesichert
81
//          sComm[iRecStrPtr++] = sInBuffer[iTmpBufferPtr++];
82
//       }
83
//       sComm[iRecStrPtr++] = 0x00;
84
85
      return 1;
86
   } else {
87
      return 0;
88
   }
89
90
}
91
92
void UsartPutc(char c) {
93
int temp_Statusreg;
94
   temp_Statusreg = SREG;
95
   while(!(UCSRA & (1 << UDRE)));                              // wait until UDR ready
96
   UDR = c;                                                    // send character
97
   SREG = temp_Statusreg;
98
}
99
100
void UsartPuts (char *s) {                                    //  loop until *s != NULL
101
   while (*s) {
102
      UsartPutc(*s);
103
      s++;
104
   }
105
}
106
107
void PrintByteBinaer(char byte) {
108
uint8_t iPos;
109
   for (iPos=1; iPos<=8; iPos++) {
110
      if (byte & 0x80)
111
         UsartPutc(0x31);
112
      else
113
         UsartPutc(0x30);
114
      byte = byte << 1;
115
      if (!(iPos & 0x03)) UsartPutc(0x20);
116
   }
117
   UsartPuts("\n");
118
}
119
120
// ------------------------------------------------------------ Mainloop
121
 
122
123
int main(void) {
124
125
   InitUsart();
126
   InitPorts();
127
128
129
   // send init string
130
   UsartPuts ("\n\nVersion 1.00 Andys Testprogramm\n");
131
132
   if (MCUCSR & (1<<BORF))          // Brown-Out Reset
133
      UsartPuts("Brown-Out Reset");
134
   else if (MCUCSR & (1<<PORF))     // Power-On Reset
135
      UsartPuts("Power-On Reset");
136
   else if (MCUCSR & (1<<JTRF))     // JTAG Reset
137
      UsartPuts("JTAG Reset");
138
   else if (MCUCSR & (1<<EXTRF))    // External Reset
139
      UsartPuts("External Reset");
140
   else if (MCUCSR & (1<<WDRF))     // Watchdog Reset
141
      UsartPuts("Watchdog Reset");
142
   else
143
      UsartPuts("Manual Jump");
144
   UsartPuts ("\nMCUCSR: ");
145
   PrintByteBinaer(MCUCSR);
146
   MCUCSR &= 0xE0;                  // Clear Reset-Status
147
   UsartPuts ("\n");
148
149
   sei();                           // set global interrupts
150
151
   UsartPuts ("\n\nReady\n");
152
   
153
   while (1) {
154
     if (GetCommand(&lCommandPar1, &lCommandPar2, sCommandString) !=0) {
155
         UsartPuts("\n");
156
         UsartPuts (sCommandString);
157
         UsartPuts (" ");
158
         UsartPuts (ltoa(lCommandPar1, sOutString, 10));
159
         UsartPuts (" ");
160
         UsartPuts (ltoa(lCommandPar2, sOutString, 10));
161
         UsartPuts (" -> ");
162
         UsartPuts("\n>>");
163
      }
164
   }
165
   return 0;
166
}

Eigentlich funktioniert hier gar nichts. Das Ganze ist so ziemlich 
sinnfrei. Aber ich kann unter gtkterm eine Taste gedrückt halten und 
nichts passiert.
Aber wenn ich jetzt den auskommentierten Teil in GetCommand wieder 
einkommentiere und den Finger auf der Tatatur halte, stürzt der Atmel 
ab. Das erkennt man daran, daß er neugestartet wird (kein Watchdog) und 
das MCUCSR Register dann 0 ist.

Das ist die Ausgabe von gtkterm (mit echo):
1
Version 1.00 Andys Testprogramm
2
External Reset
3
MCUCSR: 0000 0010 
4
5
6
7
Ready
8
ggggggg
9
10
Version 1.00 Andys Testprogramm
11
Manual Jump
12
MCUCSR: 0000 0000 
13
14
15
16
Ready
17
ggggggggggggggggggggggggggggggggg
18
19
Version 1.00 Andys Testprogramm
20
Manual Jump
21
MCUCSR: 0000 0000 
22
23
24
25
Ready
26
gggggggggggggggggggggggggggg

Und so ohne Absturz:

1
Version 1.00 Andys Testprogramm
2
External Reset
3
MCUCSR: 0000 0010 
4
5
6
7
Ready
8
ggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
9
ggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
10
ggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
11
ggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
12
ggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
13
ggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
14
gggggggggggggggggg

Mit einem anderne ATmega das gleiche.

Hat jemand eine Idee ? Ich dreh noch langsam durch.
Die fuses sind so gesetzt, wie man es in der Kopfzeile sieht.

Gruß
Andy

von Bernhard M. (boregard)


Lesenswert?

kann das hier
1
       while ((sInBuffer[iTmpBufferPtr] != 0x00) && (sInBuffer[iTmpBufferPtr] != 0x20)) {     // Command, max. String Länge aus ISR gesichert
2
          sComm[iRecStrPtr++] = sInBuffer[iTmpBufferPtr++];
3
       }
4
       sComm[iRecStrPtr++] = 0x00;
einen Pufferüberlauf geben, da nie geprüft wird, ob iRecStrPtr die größe 
von sComm überschreitet? Irgendwann wird dann der Stack überschrieben, 
und es kracht...

von Andreas B. (bitverdreher)


Lesenswert?

Hallo Bernhard,
gut daß Du mich daran erinnerst ;-). Das wollte ich noch reinmachen. 
Normalerweise sollen die Zeichen auch über ein Programm vom PC kommen. 
Hier wollte ich eigentlich dafür sorgen, daß die Zeichenkette in der 
Länge begrenzt bleibt.
Nur hier kommt er ja merkwürdigerwiese gar nicht immer hin.
Das "UsartPuts ("\n\nHier solls nicht hin\n");" wird ja gar nicht 
ausgegeben. iUartFlags bleibt hier durch die starke SW Reduzierung 0.

Gruß
Andy

von Jojo S. (Gast)


Lesenswert?

'Absturz' bei Zeichenempfang hört sich so an wie fehlende oder falsche 
ISR, hat das richtige Programm einen Teil wie :

ISR(USART_RXC_vect)
{
  uint8_t ch;

  ch = UDR;    // read byte from data register
// ...
}

von Andreas B. (bitverdreher)


Lesenswert?

Hallo,

Bernhard:
Ich habe es gerade mal geändert:
1
      while ((sInBuffer[iTmpBufferPtr] != 0x00) && (sInBuffer[iTmpBufferPtr] != 0x20 && (iTmpBufferPtr <= (BUFFER_LENGHT-2)))) {     // Command, max. String Länge aus ISR gesichert

-> Gleicher Effekt.

Johannes:
Die ISR hatte es. Das gepostete Programm ist vollständig. Der IRQ des 
Zeichenempfangs ist hier deaktiviert.
Als default steht hier: ISR(__vector_default) { UsartPuts ("Undefined 
IRQ"); }

Gruß
Andy

Ach ja, wem die hardwaredef.h noch interessiert (da wir gerade bei 
"vollständig" sind)

von Andreas B. (bitverdreher)


Angehängte Dateien:

Lesenswert?

Nochmal die hardwaredef.h

Gruß
Andy

von Jojo S. (Gast)


Lesenswert?

das sieht schon komisch aus. Es gibt aber noch Warnings weil UsartPuts() 
aufgerufen wird bevor es deklariert wird, damit kann es den Stack 
kaputtmachen. Aber eigentlich soll die Funktion ja garnicht aufgerufen 
werden.
Wenn die Zeilen auskommentiert bleiben wird der Call zu GetCommand() 
komplett wegoptimiert, wenn die Zeilen eingefügt werden läuft es im 
Simulator richtig ab. Da bliebe ja nur das der Reset durch einen 
Hardwarefehler ausgelöst wird.

von Andreas B. (bitverdreher)


Angehängte Dateien:

Lesenswert?

Hallo Johannes,
ja an einen Hardwarefehler dachte ich ja auch schon. Ehrlich gesagt, war 
ich schon so sicher, daß ich die Platine neu designen wollte. Merkwürdig 
ist ja nur, daß mit dem Auskommentieren dieser Zeilen der AVR nicht mehr 
abstürzt.
Vielleicht ist es auch beides HW und SW....:-(

Und sorry, die test.h habe ich vergessen. Da hätte er bei Dir eigentlich 
schon beim Versuch meckern müssen, sie zu includen.

Aber es wäre super, wenn jemand mit einem ATMega32 und Uart dies mit gcc 
mal compilieren und auf seiner Tastatur mal eine Taste festhalten würde.
Dem Simulator glaub ich da nicht. Ich  habe mir auch noch nie die Mühe 
gemacht, den gdb-avr oder so etwas einzurichten.

Gruß
Andy

von Andreas B. (bitverdreher)


Angehängte Dateien:

Lesenswert?

Und hier noch die Platine. Die Versorgung habe ich mal markiert.
Zusätzlich ist noch am Max232 zwischen Pin 15/16 und am AVR zwischen Pin 
10/11 ein 100n Kerko.

Gruß
Andy

von Andreas B. (bitverdreher)


Angehängte Dateien:

Lesenswert?

Hallo,
jetzt wird es noch merkwürdiger:
schalte ich die Optimierung von s auf 3 dann wird der Code größer, 
schneller (Ich habe jetzt mal eine LED in der main blinken lassen) und 
stürzt nicht mehr ab. :-o
Mit optimierung 2 stürzt er am schnellsten ab.

neue Main:
1
int main(void) {
2
3
   InitUsart();
4
   InitPorts();
5
6
7
   // send init string
8
   UsartPuts ("\n\nVersion 1.00 Andys Testprogramm\n");
9
10
   if (MCUCSR & (1<<BORF))          // Brown-Out Reset
11
      UsartPuts("Brown-Out Reset");
12
   else if (MCUCSR & (1<<PORF))     // Power-On Reset
13
      UsartPuts("Power-On Reset");
14
   else if (MCUCSR & (1<<JTRF))     // JTAG Reset
15
      UsartPuts("JTAG Reset");
16
   else if (MCUCSR & (1<<EXTRF))    // External Reset
17
      UsartPuts("External Reset");
18
   else if (MCUCSR & (1<<WDRF))     // Watchdog Reset
19
      UsartPuts("Watchdog Reset");
20
   else
21
      UsartPuts("Manual Jump");
22
   UsartPuts ("\nMCUCSR: ");
23
   PrintByteBinaer(MCUCSR);
24
   MCUCSR &= 0xE0;                  // Clear Reset-Status
25
26
   UsartPuts ("\n\nReady\n");
27
   
28
   while (1) {
29
      
30
      iCounter++;
31
      if (iCounter == 0) {
32
         if (iLaserOn == 0) {
33
            LASER_OFF;
34
            iLaserOn = 1;
35
         } else {
36
            LASER_ON;
37
            iLaserOn = 0;
38
         }        
39
      }
40
        
41
     if (GetCommand(&lCommandPar1, &lCommandPar2, sCommandString) !=0) {
42
         UsartPuts("\n");
43
         UsartPuts (sCommandString);
44
         UsartPuts (" ");
45
         UsartPuts (ltoa(lCommandPar1, sOutString, 10));
46
         UsartPuts (" ");
47
         UsartPuts (ltoa(lCommandPar2, sOutString, 10));
48
         UsartPuts (" -> ");
49
         UsartPuts("\n>>");
50
      }
51
   }
52
   return 0;
53
}

langsam blick ich es wirklich nicht mehr.

Gruß
Andy

von Michael G. (linuxgeek) Benutzerseite


Lesenswert?

Was um alles in der Welt hat R11 fuer eine Funktion?
Und nicht soviel Code inline posten...

von GagoSoft (Gast)


Lesenswert?

Seltsame Abstürze ergeben sich bei AVRs auch wenn eine ISR doppelt 
ausgeführt wird. Also wenn währent einer Interruptbehandlung der selbe 
Interrupt nochmal ausgeführt wird....

von Michael G. (linuxgeek) Benutzerseite


Lesenswert?

Das kann aber faktisch nicht passieren, weil waehrend der ISR die 
Interrupts deaktiviert sind.

von Sven (Gast)


Lesenswert?

@ Andreas B. (bitverdreher):

mal abgesehen von R11, den Michael schon gefunden hat:

Wenn Du wirklich Hilfe möchtest, dann poste uns doch mal den Schaltplan,
beispielsweise als Eagle File,
dann kann man auch die Fehler besser verfolgen.
Ich habe zb. keine Lust Carrera Bahn auf Deinem Layout zu fahren,
geschweige jetzt pdfs herunterzuladen um dann die Portpins mit Deinen 
angeschlossenen Pins zu vergleichen.

Ebenso solltest Du mal ein einfaches Programm zum einfachen
"echo" der UART-Schnittstelle erzeugen oder jemand der sich erbarmt.

Gruß Sven

von Sven (Gast)


Lesenswert?

Entschuldigung, im ersten Posting ist der Schaltplan. Sorry.

Gruß Sven

von Volker (Gast)


Lesenswert?

Hallo Andreas

Du solltest mal CKOPT in hfuse setzen.

Gruß, Volker

von Andreas B. (bitverdreher)


Lesenswert?

Michael G. wrote:
> Was um alles in der Welt hat R11 fuer eine Funktion?

Das frag ich mich jetzt auch. Das muß ich wohl irgendwoher 
abgepinselt/abgeleitet haben. Und weg ist er (Leiterbahn direkt am AVR 
abgekratzt).
Aber das Problem besteht leider noch genauso.

Sven: Mein original Programm ist 60k groß und besteht aus mehreren 
Files. Was Du hier siehst ist die Reduktion auf das minimalste, um den 
Fehler einzugrenzen. Deswegen lasse ich auch nur eine LED blinken, um 
AVR Lebenszeichen nachzuweisen.

Gagosoft: Die IRQs wurden ausgeknipst (kein sei() mehr)

Gruß
Andy

von Sven (Gast)


Lesenswert?

@ Andreas B. (bitverdreher):

Warum hat der RESET vom AVR nur einen Pullup und keinen C = 100nF ?

Gruß Sven

von Jojo S. (Gast)


Lesenswert?

ich habe das Programm (die vorletzte Version ohne Blink LED) auf meiner 
Mega32 Hardware geladen, es läuft ohne Probleme. Die Ausgaben kommen und 
dann kann ich Daten schicken wie ich will, der AVR ignoriert sie und nix 
stürzt ab. Optimierungen -Os und -O2 probiert. Also ich würde sagen an 
der SW liegts definitiv nicht. Bricht die Versorgung vielleicht zusammen 
durch irgendeinen Schluss von Datenleitung nach Vcc oder Masse?

von Volker (Gast)


Lesenswert?

Hallo nochmal

Hast du das mit dem CKOPT mal ausprobiert? Geht doch schnell :-)

Ich hatte mal ein ähnliches Problem und es hat geholfen.

von Andreas B. (bitverdreher)


Lesenswert?

Hallo Volker,
Ich glaube, das war der Tip des Monats. Ich danke Dir !!
Ins Datenblatt geguckt, Fuse gesetzt und es scheint zu funktionieren.

Was so ein kleines Bit docb ausmacht und für Effekte hevorruft. Ich 
betreibe dieses Ding schon die ganze Zeit problemlos als 3 
Achsensteuerung mit Encoder. Nur der Uart Eingang scheint davon 
betroffen zu sein.

Gruß
Andy

von Andreas B. (bitverdreher)


Lesenswert?

Hallo Sven,
den C habe ich später mal aus Sicherheitsgründen (Angstkondensator nennt 
man das jetzt ja wohl) direkt auf die Platine gelötet. Die sieht auch 
nicht mehr so aus, wie auf dem Bild. Aber wenn es daran gelegen hätte, 
hätte man das vermutlich am Register MCUCSR gesehen oder ?

Johannes: Danke fürs Testen. Das bestätigt mir noch einmal daß das mit 
dem nun funktionierenden AVR mit CKOPT fuse kein Zufall ist.

Gruß
Andy

Jetzt werde ich mal wieder alles zusammenbauen und den AVR wieder voll 
machen.....

Vielleicht sollte ich meine Probleme mal öfter hier hineinstellen ;-)

von Jojo S. (Gast)


Lesenswert?

wg. MCUCSR Register: da gabs hier mal einen kleinen Thread:
Beitrag "Bekomme keine gültigen MCUSR Werte"
in deinem Code wird das Register relativ spät ausgelesen, da kann ja 
schon wieder einiges passiert sein. In dem angebegenen Thread wird das 
Register dann in dem init Code vom Compiler ausgelesen.
Und der Simulator im AVRStudio ist schon genial, wenn es ein 
Compilerfehler gewesen wäre hätte man das beim Steppen schon gesehen. 
Was dem Simulator fehlt ist so Hardware zu simulieren und z.B. Zeichen 
in einem Terminal auszugeben wenn das USART Register beschrieben wird. 
Oder gibt es dafür ein Plugin?

von Andreas B. (bitverdreher)


Lesenswert?

Hallo Johannes,
das stimmt, ich habe das Register erst recht spät ausgelesen. Man sollte 
dies als 1.Befehl zwischenspeichern.
Ich glaube aber kaum, daß Du einen Hardwaresimulator finden wirst, der 
einen Quarzoszillator mit zu geringem Pegel an einem AVR simuliert ;-)
Du kannst ja mal versuchen, Spice ins AVRStudio zu integrieren. Da 
träumen hier glaube ich, viele davon.

Wenn ich etwas debuggen muß, lasse ich mir den Kram übers UART ausgeben. 
Und wenn man da zuviel ausgeben muß, liegt der Verdacht nahe, daß man 
sich vorher über das Programm zu wenig Gedanken gemacht hat.
Aber es stimmt schon, in diesem Fall hätte ich die SW schneller 
ausschließenm können.
Meist sind es aber zeitkritische Dinge, wo man das Bedürfnis hat zu 
simulieren. Und gerade da zeigen sich ja die Schwächen der Simulation.

Allerdings habe ich mich noch nicht mit Jtag beschäftigt. Das scheint 
diesbezüglich schon interessanter zu sein.

Gruß
Andy

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.