PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : wieder mal unerklärliche Resets



damfino
30.08.2011, 21:34
Hallo zusammen,

Ich kämpfe wieder mit unerklärlichen Resets, und je mehr ich versuche Fehler zu vermeiden, desto weniger funktioniert. Mal fährt er 5 Minuten richtig, mal 2h, zuletzt hatte ich alle Arrays global definiert, und dann stürzt er nach 1 Minute ab.
Sieht nach Stacküberlauf oder falschen Array Index aus, ich seh aber einfach den Fehler nicht.

Verwendet wird ein Atmega1284P mit 16Mhz, sollte also mit 16kB mehr als genug RAM vorhanden sein da zuvor ein 644 mit 4kB verwendet wurde. Speicherbedarf der Arrays + globale Variablen derzeit bei knapp 4kb, dazu die einzelnen Funktionen mit in Summe ca 100Byte.
Die Änderungen gegenüber dem Code für den 644er sind: Entfall von UART, Entfall vom LCD, und dafür mehr am TWI (Fleury lib), mehr Sensoren/Bumper ausgewertet. Also im Prinzip den alten Code genommen, UART und LCD gegen TWI Routinen getauscht, und Auswertung von 4 statt 1 Bumper. Arrays sind schon extra größer als notwendig definiert. Und ich bekomme das ehemals stabile Programm nicht mehr zum laufen.



Ich poste hier mal den Code der am ehesten für die Fehler verantwortlich ist:

die Arrays (für A* testweise global, ansonsten in der Funktion definiert)

#define grund_x 23 // 23 Anzahl Felder W-O
#define grund_y 42 //42 Anzahl Felder S-O
unsigned char Karte[grund_x+1][grund_y+1];

#define kartenfeld 100 // Größe eines Kartenfeldes in 1cm Einheit= 1m X 1m
#define pos_x_max (grund_x*kartenfeld-1)
#define pos_y_max (grund_y*kartenfeld-1)

// A*: Rand wird nicht berücksichtigt, daher um 2 kleiner
#define max_x_karte grund_x-2
#define max_y_karte grund_y-2
#define max_x max_x_karte-1
#define max_y max_y_karte-1

unsigned char x_vor_l_punkt[max_x_karte+1][max_y_karte+1]; // l_punkt <100, 100, 200, x_vor 0-99
unsigned char y_vor[max_x_karte+1][max_y_karte+1];
unsigned char g_wert[max_x_karte+1][max_y_karte+1];

für die Karte gibts eigene Routinen um Fehler auszuschließem:

unsigned char Karte_lesen(unsigned char x, unsigned char y)
{
unsigned char wert;
wert=150;
if ((x<grund_x)&&(y<grund_y))
{
wert=Karte[x][y];
}
return(wert);
}

void Karte_schreiben(unsigned char x, unsigned char y, unsigned char wert)
{
if ((x<grund_x)&&(y<grund_y)&&(x>=0)&&(y>=0))
{
if (wert==0)
{
if (Karte[x][y]<100) Karte[x][y]++;
}
else
{
if (Karte[x][y]<besetzt) Karte[x][y]=wert;
if (wert==besetzt) Karte[x][y]=besetzt; // für initialsierung der Karte notwendig
}
}
}

im A* sieht es so aus:

for (xt=0;xt<=max_x;xt++)// niedrigsten f-Wert ermitteln
{
for (yt=0;yt<=max_y;yt++)
{
if ((x_vor_l_punkt[xt][yt]>=100)&&(x_vor_l_punkt[xt][yt]<200)) // Punkte auf open List vergleichen

{

ff=2*((abs(xt-x_ziel))+(abs(yt-y_ziel)));
fwert=g_wert[xt][yt]+ff;// f=g+ h-Wert
for (ii=0;ii<8;ii++)
{
if (ii==0) {xx=xt;yy=yt+1;}
if (ii==1) {xx=xt;yy=yt-1;}
if (ii==2) {xx=xt+1;yy=yt;}
if (ii==3) {xx=xt-1;yy=yt;}
if (ii==4) {xx=xt+1;yy=yt+1;}
if (ii==5) {xx=xt+1;yy=yt-1;}
if (ii==6) {xx=xt-1;yy=yt+1;}
if (ii==7) {xx=xt-1;yy=yt-1;}

if (xt<=0) {xx=0;}
if (yt<=0) {yy=0;}
if (xx>max_x) {xx=max_x;}
if (yy>max_y) {yy=max_y;}

if (Karte_lesen(xt,yt)>=blockiert) fwert=fwert+2;
}

if (fwert>512) fwert=512;

if (fwert<temp)
{temp=fwert;xf=xt;yf=yt;}
}
}
}


In Verdacht habe ich auch die ISR, da diese doch länger ist:


/*+++++++Timer2++++++++++++++++*/
TCCR2A = (1<<WGM21);// CTC Mode


TCCR2B = (1<<CS22); // Prescaler 64
TIMSK2 = (1<<OCIE2A); //Interupt compare match enable
OCR2A=23; // alle 0,1ms 1 Interrupt


/*+++ Interrupt Messer +++++++++*/
EICRA |= (1<<ISC20) | (1<<ISC21); // steigende Flanke
EIMSK |= (1<<INT2); // Int enable

/*+++ Interrupt Vorderrad +++++++++*/
PCICR |= (1<<PCIE3); // Int 31-24 enable
PCMSK3 |= (1<<PCINT24); // Pin D0

/*+++ Interrupt Odo Links +++++++++*/
EICRA |= (1<<ISC10) ; // jede Flanke
EIMSK |= (1<<INT1); // Int enable
/*+++ Interrupt Odo Rechts +++++++++*/
EICRA |= (1<<ISC00); // jede Flanke
EIMSK |= (1<<INT0); // Int enable




/********** Interrupts ***********************************/

volatile unsigned char timecount,odo_li,odo_re,timer_zwei, mowerspeed;
volatile short i_summe,v_alt;
volatile unsigned short drehzahl_ist;
volatile unsigned short radcount, messer_zeit;

ISR(ISR_Timer2)
{
timer_zwei++;
messer_zeit++ ; if (messer_zeit>14000) messer_zeit=14000;
if (timer_zwei>100)
{timer_zwei=0;
timecount++;
radcount++;
}



}

ISR(INT0_vect) //Odo_re
{
odo_re++;

}

ISR(INT1_vect) // Odo_li
{
odo_li++;

}


ISR(INT2_vect) // Messerdrehzahl
{
short mowersp,v;


drehzahl_ist= (unsigned short)(300000L/messer_zeit);

v = (short)(drehzahl_soll-drehzahl_ist); //Vergleich
i_summe = i_summe + v/10; //(i_summe*9)/10 + v; //Integration I-Anteil
if (i_summe < -1000) i_summe = -1000; //Begrenzung I-Anteil
if (i_summe > 1000) i_summe = 1000;


mowersp=(3*v+15*((i_summe))+8*((v -v_alt)))/80;
v_alt=v;

if (mowersp < 77) mowersp = 77; //Begrenzung Stellgröße
if (mowersp > 255) mowersp = 255;
mowerspeed=(unsigned char)(mowersp);
Mower=mowerspeed;
messer_zeit=0;


}


ISR(PCINT3_vect) // Vorderrad
{
radcount=0;
}


die Messerdrehzahl, bzw PWM Wert für den Motor wird 2x pro Umdrehung berechnet, dh bei 2 Impulse pro Umdrehung und 2500U/min ca alle 12ms.

Pointer gibt es im Programm ausser den Arrays keine, was sonst kann den Code noch ruinieren?

Kämpfe mich mit Zeit und Schlafmangel schon wochenlang durch den Code, bin für jeden Hinweis dankbar!

LG!

KR-500
31.08.2011, 08:10
Hi,

also nurmal so ein paar Ideen um den Fehler einzugrenzen, ich nehme an das du einen Rasenmäherroboter bauen willst ;) Und wenn Motoren im Spiel sind würde ich auf jeden Fall gucken ob der Reset nicht durch einen Spannungseinbruch zu Stande kommt, wenn zum Beispiel die Motoren auf einmal mehr Strom ziehen. Du kannst es ja einfach mal testen indem du ein Rad probeweise belastest. Das musst du natürlich nur probieren wenn Motor und µc aus der selben Batterie gespeist werden.
Eine weitere Idee wäre einfach mal über die USART zu debuggen und Probeweise alle Variablen ausgeben lassen, so kannst du gucken ob irgendwelche Indexe zu weit gehen.

Viele Grüße
KR-500

damfino
31.08.2011, 12:13
Hi,
die Versorgung der Kontroller ist über Dioden von den Motoren getrennt, und mit 470µF Elko (nach der Diode) gepuffert. Der 2. Kontroller, ein Atmega32, funktioniert immer.
Aber der Hauptkontroller hat irgendwann Fehler in der Programmausführung, bzw wenn aktiviert spricht der Watchdog an.

Bisher gab es auch keine Resets wenns den Mäher im hohen Gras gewürgt hat, die Akkus haben mittlerweile wieder volle Leistung und könnten 50A liefern, daher vermute ich den Fehler in der Software.

LG!

KR-500
31.08.2011, 13:40
Hi,

ok dann kann man die Stromversorung ja auschließen. Aus deinem ersten Post entnehme ich das der Fehler eher sporadisch auftritt, was es natürlich noch mal schwieriger macht den Fehler asufindig zu machen :(


Und ich bekomme das ehemals stabile Programm nicht mehr zum laufen.

Hast du denn mal Probiert ob deine alte stabile Version des Programms überhaupt noch läuft auf dem Atmega1284P? Wäre sicher gut zu wissen, ob der Controller funktioniert.

Ich hatte mal ein ähnliches Problem bei dem sich der Controller immer wieder sporadisch resettet hat, dabei hatte ich versehentlich den USART Empfangsinterrupt aktiviert aber keine entsprechende ISR-Routine dazu gehabt, mit anderen Worten, immer wenn etwas über die Serielle Schnittstelle an den Atmega gesendet wurdem stürzte er ab. Vielleicht hast du auch irgendwo einen interrupt aktiviert aber keine ISR Definiert, dann dürfte der Controller ja irgendwo hinspringen bzw sogar an die Addresse Null, und würde sich somit resetten. (Ich hoffe das war jetzt richtig^^)

KR-500

damfino
31.08.2011, 20:42
Das alte Programm kann leider nicht 1:1 verwendet werden. Grund für den Umbau war der Mangel an I/O Pins, deswegen sind das LCD und GPS (UART) auf den 2. Kontroller gewandert, und die Kommunikation erfolgt über TWI.
Die aufwändigen Berechnungsroutinen von Navigation und Karten Arrays sind identisch, die Ausgaben fürs LCD mussten natürlich geändert werden. TWI wurde aber schon vorher verwendet.

Letztes Jahr nur kurz in Betrieb war die ISR für die Messerdrehzahl, hier gab es noch einige Änderungen bis der PID Regler verlässlich funktionierte.

Wegen fehlgeleiteter ISR ist das eingebaut:

ISR (__vector_default) // falsche Interrupt erkennen, abbrechen
{cli();PORTC &= ~( (1<<DDC2) | (1<<DDC3) );PORTC &= ~( (1<<DDC4) | (1<<DDC5) );PORTC |= (1<<DDC6) | (1<<DDC7);
;LED_rot_ein;Anzeige_Sonder(18);
while(1) {wdt_reset();}

Schaltet alle Motoren ab und ich bekomme eine entsprechende Anzeige am LCD.

Ich hatte letztes Jahr ganz ähnliche Aussetzer, damals war das Karten Array schuld.

Der Fehler ist einigermaßen reproduzierbar, seitdem ich die A* Arrays global definiert hab:
Er stürzt nach 1 Umdrehung bei der Spiralfahrt ab. Dabei wird A* aber nicht verwendet. Das Kartenarray wird verwendet, über die oben angeführten Routinen die dafür sorgen sollen dass die Array Grenzen eingehalten werden.

Ein Variablenüberlauf kann dafür sorgen dass eine Berechnung falsch ausgeht, zB wird aus 18000 wegen Überlauf -14000. Falsch berechnete Positionen sollten die Kartenroutinen abfangen. Aber das stört doch nicht den normalen Programmablauf mit unberechenbarem Verhalten, oder?

Oder was kann noch alles den Stack durcheinander bringen?

LG!

markusj
31.08.2011, 21:07
Versuch Mal, nach und nach Programmkomponenten zu deaktivieren (zum Beispiel besagten A*), vielleicht lässt sich so die Problemzone eingrenzen. Debug-Ausgaben über den Aufruf einzelner Routinen können ebenfalls helfen, um (ungewollt) aufgerufene Programmteile zu identifizieren.

mfG
Markus

damfino
04.09.2011, 21:03
Ich konnte jetzt wieder mal testen:
.) A* und Navigation deaktiviert (Funktionen gelassen, Inhalt auskommentiert): Absturz innerhalb 1 min.
.) alle Inline Funktionen wieder normal eingebunden: wieder viele Abstürze
.) den ganzen Code auf Fehler durchsucht, wieder mal nichts gefunden.
.) Brownout aktiviert, jetzt gibt es eher das Problem dass dieser gleich beim einschalten aktiviert wird.
.) ebenso versucht das Register vom Power on Reset auszuwerten, aber damit bekommt man den Kontroller gleich gar nicht zum laufen. Wollte damit einen eventuellen schlechten Kontakt der Steckverbindungen erkennen.

Derzeit verwende ich die letzte halbwegs stabile Version, nur die ISR vom PID Regler ist inzwischen etwas optimiert. Einmal löste der Watchdog nach ein paar Minuten aus, jetzt ist er grade >2h ohne Fehlfunktion gefahren.
Ich hatte auch mal den Watchdog deaktiviert, aber dann macht im Fehlerfall das Programm was es will, da ist es besser wenn der Watchdog mal die Notbremse zieht. Ist mit 4s auch großzügig einstellt.

Sieht also nach Stackproblem aus, nur wie findet man den Fehler?

LG!

Vitis
05.09.2011, 18:53
Zum Einen sind Variablennamen wie xx xy yyxx etc. nur sehr übel zu debuggen,
eindeutigere Namen helfen da mitunter schon den Baum im Wald besser zu sehen ...
ich verwende z.B. in Variablennamen auch häufig gleich das jeweilige Format mit im Namen z.B.
x_pos_1_byte,
dann kann ich in Rechenoperationen gleich
"abschätzen" ob der Wert oder die Berechnung in die Variable passen kann.

markusj
05.09.2011, 19:44
A* und Navigation deaktiviert (Funktionen gelassen, Inhalt auskommentiert): Absturz innerhalb 1 min.
Wunderbar, das ist eine brauchbare Grundlage für den später beschriebenen Test.


Brownout aktiviert, jetzt gibt es eher das Problem dass dieser gleich beim einschalten aktiviert wird.
Doch Spannungsprobleme? So wie die eingestellte Spannung überschritten wird, sollte der AVR loslaufen ...


ebenso versucht das Register vom Power on Reset auszuwerten, aber damit bekommt man den Kontroller gleich gar nicht zum laufen. Wollte damit einen eventuellen schlechten Kontakt der Steckverbindungen erkennen.
Warum läuft er da nicht an? Da würde ich mich Mal dahinter klemmen, das klingt ... komisch.


Sieht also nach Stackproblem aus, nur wie findet man den Fehler?
Es gibt einen Trick um die Speichernutzung zu betrachten: Den kompletten Speicher mit einem bestimmten Wert beschreiben und dann später nachsehen, wieviel von diesem Wert/Muster noch vorhanden ist. Sieh dir Mal den RN-Wissen Artikel Speicherverbrauch bestimmen mit avr-gcc (http://www.rn-wissen.de/index.php/Speicherverbrauch_bestimmen_mit_avr-gcc) an.
Mit der o.g. Variante die schon nach einer Minute abschmiert kannst du so schnell rauskriegen, wie sich der Speicherverbrauch entwickelt.

mfG
Markus

damfino
05.09.2011, 22:24
Hi,

die uninspiriten Variablennamen wie xx werden nur als einfache Zähler innerhalb einer Funktion verwendet, wichtige Zwischenergebnisse haben normalerweise sinnvolle Bezeichnungen.
Ein Überlauf könnte aber nur ein falsches Ergebnis, aber keine fehlerhafte Ausführung des Programmes bewirken, oder? Wenn die Positionsbestimmung falsch läuft, muss er zB trotzdem die Bumper beachten.

Die Speichernutzung habe ich eingebaut, wird laufend statt der Pos_x im LCD angezeigt, es gibt also keine größere Änderung im Programmablauf. Morgen Abend kann ich wieder testen.

Die Einschaltprobleme könnten vom Stepdown Regler (http://www.elv.at/Step-down-Spannungswandler-SDW-35,-2-A,-Komplettbausatz-%28ohne-Gehauml;use%29/x.aspx/cid_74/detail_10/detail2_24372/flv_/bereich_/marke_) kommen, ich muss die 5V Seite schalten und nicht die 12V damit die Kontroller richtig starten. Aber ohne Oszi wird eine Diagnose schwierig. Vorm Wandler ist ein 470µF Elko, die Kontroller haben alle Abblockkondensatoren und 10k Pullup am Reset. Der 1284 hat zusätzlich einen 100nF am Reset. Der Atmega32 fürs GPS und Display läuft ohne Probleme, die größeren 644 und 1284 sind anscheinend empfindlicher, das musste ich letztes Jahr schon feststellen. Deshalb auch der 2A Step down Regler anstatt eines heisslaufenden 7805.

LG!

markusj
06.09.2011, 07:05
Die Einschaltprobleme könnten vom Stepdown Regler (http://www.elv.at/Step-down-Spannungswandler-SDW-35,-2-A,-Komplettbausatz-%28ohne-Gehauml;use%29/x.aspx/cid_74/detail_10/detail2_24372/flv_/bereich_/marke_) kommen, ich muss die 5V Seite schalten und nicht die 12V damit die Kontroller richtig starten. Aber ohne Oszi wird eine Diagnose schwierig. Vorm Wandler ist ein 470µF Elko, die Kontroller haben alle Abblockkondensatoren und 10k Pullup am Reset. Der 1284 hat zusätzlich einen 100nF am Reset. Der Atmega32 fürs GPS und Display läuft ohne Probleme, die größeren 644 und 1284 sind anscheinend empfindlicher, das musste ich letztes Jahr schon feststellen. Deshalb auch der 2A Step down Regler anstatt eines heisslaufenden 7805.
Dennoch, der Brown-Out müsste nach erreichen einer stabilen Spannung über dem Schwellenwert den AVR loslaufen lassen. Da dem nicht so ist, scheint was mit der Versorgungsspannung im Argen zu liegen. Evtl. möchtest du testweise hinter den Wandler auch nen Elko setzen.

mfG
Markus

damfino
06.09.2011, 21:34
Der Speichertest hat folgendes ergeben:
normale Fahrt: 15129Bytes frei
bei Navigation mit A*: 12330 Bytes frei.

Ein Ergebnis wie erwartet, das Programm war für die 4k RAM vom Atmega644 ausgelegt.

Neu war neben einem normalen Absturz über den Watchdog, dass er 4x wegen Tiefentladung des Akkus gestoppt hatte. Dazu muss aber 50x in Folge eine Zellenspannung <2.9V sein, die Zellen haben aber alle noch 3.3V, und nach Neustart ist er wieder losgefahren.

Eine lange Recherche im Internet hat eine weitere Möglichkeit gezeigt: es gibt Atmega1284p bei denen über den UART das RAM verändert wird, mit genau diesen unerwarteten Folgen wie bei mir. Auch wenn das UART gar nicht verwendet wird. Dort gab es den Fehler aber nur bei 20Mhz Takt, nicht bei 16Mhz. Ich hab jetzt die UART Pins auf GND gelegt, und einen bisher verwendeten Eingang auf einen anderen PIN umgeleitet. Mal sehen ob das was bringt.

Die Spannungsversorgung ist mit ein paar kleinen Kondensatoren verbessert worden, passenden Elko muss ich erst besorgen.

LG!

markusj
06.09.2011, 22:52
Interessant, oder besser gesagt: Nicht gut. Es wäre interessant zu wissen, wann dein ATMega produziert wurde, scheinbar ist das ein Fehler von Vorserienmodellen.
Für die Akten hier noch zwei Links dazu (die du vermutlich gemeint hast): ATmega1284P memory problem/fix (http://www.seanet.com/~karllunt/1284pmemprob.html) und avrfreaks.net - atmega1284p UART Rx glitch (http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=82014).

mfg
Markus

damfino
10.09.2011, 12:25
Also, das Stillegen des UART hat definitiv das Verhalten verbessert, aber es gibt immer noch (jetzt seltenere) Fälle wo der Watchdog auslöst.

damfino
13.09.2011, 20:06
Der Robi war jetzt ein paar Stunden im Einsatz:
UART deaktiviert: eine große Verbesserung, es gibt nur mehr seltene Resets durch den Watchdog.
Als weitere Ursache habe ich den TWI Bus in Verdacht, starte Kommunikation jetzt immer mit zB if(!(i2c_start(0xd0))) ..., und nicht mehr mit i2c_start(_wait). Seitdem löst der Watchdog nicht mehr aus, aber man merkt dass der Bus sich immer wieder aufhängt und Daten verloren gehen. Anscheinend hat vorher der blockierte Bus gleich den Kontroller mit blockiert.
Immerhin ein paar neue Erkenntnisse....

LG!