PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Programmabstürze



PCMan
26.01.2009, 08:12
Hallo Leute, ich bin mal wieder am Ende meiner Ideen.
Ich habe ein Programm, dass in festen Intervallen (sagen wir mal 15 min) eine Aktion ausgeführt. Genauergesagt soll alle 15 min eine Pumpe in betrieb genommen werden, eine ADC-Messung durchgeführt werden und fertig. ein einfaches Messystem also. Das System funktioniert auch vom Prinzip, nur stürzt es irgendwann ab. Wie macht sich das bemerkbar? Nun das System reagiert auf keine UART Signale mehr oder auch nicht auf Tastendrücke. Ich bin meinen Code schon einige male durchgegangen, aber ich kann den Fehler einfach nicht finden. Daher nun meine Frage: kann man irgendwie herausfinden, wieso ein Programm stehen bleibt?
Dann wollte ich euch noch fragen, wie kritisch globale structs sind: ich habe da eine globale struct variable, die sich system nennt. Sie vereint verschiedene Typen, z.b. einen Pointer, ein paar Bitfelder, uint8_ts oder uint16_ts aber auch eine float. Müssen diese Structs eigentlich immer ein ganzzahliges von einem Byte an Größe haben?
Grüße Simon

PCMan
26.01.2009, 10:00
Nachtrag: ich würde gerne feststellen, ob es sich um ein Speicherproblem handelt. Gibt es eine Möglichkeit das festzustellen?
Die Ausgabe erhalte ich nach dem Compilieren:


avr-size -C --mcu=atmega32 main.elf

AVR Memory Usage
----------------
Device: atmega32

Program: 21518 bytes (65.7% Full)
(.text + .data + .bootloader)

Data: 330 bytes (16.1% Full)
(.data + .bss + .noinit)


Das sagt aber noch nicht aus, ob mein Speicher zur Laufzeit voll wird oder?

Grüße Simon

Hubert.G
26.01.2009, 11:42
Solche Abstürze können auch von aussen kommen, ein Hacker in der Stromversorgung, ein Gerät, Leuchstoffröhre und dergleichen das schaltet.
Eventuell den Watchdog aktivieren.

PCMan
26.01.2009, 12:54
Hi,
hm ja an soetwas habe ich auch gedacht, weil wie gesagt, das Programm funktioniert und stürzt völlig willkürlich ab - nicht immer an der gleichen stelle.
Watchdog ist gut, kann ich aber dann das Programm in den Zustand vor dem Absturz zurücksetzen?

Grüße Simon

Hubert.G
26.01.2009, 14:25
Ich habe den Watchdog bisher nur so genutzt das das Programm einen Reset ausgeführt hat, vielleicht gibt es noch andere Möglichkeiten, aber zurückversetzen wird sicher nicht gehen.

BurningWave
26.01.2009, 16:46
vielleicht gibt es noch andere Möglichkeiten, aber zurückversetzen wird sicher nicht gehen.

Vielleicht mit einem externen RAM, auf dem man immer den jeweiligen Zustand speichert und ihn das Programm bei einem Reset ausliest und zur entsprechenden Stelle springt. Das dürfte aber kompliziert werden.

mfg

PCMan
27.01.2009, 08:21
Hm okay danke schonmal für eure anreize. Ich hatte früher eine andere "Firmware" auf dem AVR und mir ist das teil nicht abgestürzt. Mein Bauch sagt mir irgendwie, dass es sich eher um ein Softwareproblem handelt. Das dumme ist nur, ich kann einfach nicht herausfinden *wo* sich der Feler befindet. Ich lasse das gerät jetzt ein paar mal den gleichen Lauf machen und dann schaue ich, ob es immer zur gleichen Zeit abstürzt.

Ich habe auch die ganzen ISRs soweit geleert, dass da nur Flags gesetzt werden. Es gibt jedoch einen Unterschied zur vorherigen Version, nämlich das der UART permanent überwacht wird. Eine Frage ist auch noch unbeantwortet, nämlich wie das mit globalen structs ist, die sich aus verschiedenen Typen zusammensetzen. Mag das z.B. der Controller nicht, wenn das Struct eine Feldgröße von sagen wir mal 29 Bytes hat oder so?

Viele Grüße und Danke für's Helfen,
Simon

Besserwessi
27.01.2009, 17:22
Dem Controller ist es egal welche größe die Struct elemente habe. Es könnte aber sein das der Compiler bei einigen größen weniger effectiven Code erzeugt.

Software-Fehler sind manchmal schwer zu finden, besonders sowas wie Bufferoverflows oder ein Heap-overflow. Bei gut 20 K code kann man da nur viel Spass beim suchen wünschen. Dabei frage ich mich wo der ganze Code herkommt für so eine einfache Aufgabe.

PCMan
27.01.2009, 20:29
Na du bist lustig, aus meiner Beschreibung kann man doch garnicht wissen wie umfangreich das Ganze ist :)
Naja immerhin ist eine uart schnittstelle und entsprechende Befehlsabarbeitung implementiert, ein Menü mit Navigation (dazu halt eben das Klimbim für's Display), eine kleine Sammlung zum ablegen von Daten auf externe EEPROMS, Ansteuerung zweier Schrittmotoren, bissl ADC-Krams für die Messung. Naja da kommt halt mit der Zeit einiges zusammen. KLAR: man kann den Code sicherlich noch viel weiter optimieren und verkleinern, deswegen bin ich ja auch kein "Robotk Einstein" wie Besserwessi. Der Punkt ist jedenfalls, dass ein Großteil der Routinen auf anderen Systemen von mir im Einsatz waren und keine Instabilitäten verursacht haben und noch viel weniger sehe ich garkeinen logischen Zusammenhang, wann das Programm "stehen" bleibt. Mal passiert das nach 10min, dann mal nach 500min, das ist total unterschiedlich. Deswegen dachte ich es gäbe da evtl ein paar Tipps, wo man mit der Fehlersuche anfangen könnte - zB Spannungsversorgung.
Daher versuche ich jetzt mal nach und nach eine Fehlerquelle nach der anderen auszuschließen, bevor ich wirklich zuletzt wohl die ganze Software ummodeln darf ohne wirklich den Fehler gefunden zu haben.
Es scheint auch tatsächlich so zu sein, dass die ISRs auch nicht mehr ausgeführt werden - also eine art DeadLock.

Besserwessi
27.01.2009, 22:48
Die Fehler suche ist wirklich nicht einfach. Ein erster Test wäre eventuell mal eine relativ einfaches Programm wo hoffentlich dann kein Fehler mehr drin ist laufen zu lassen, um Hardwarefehler weitgehend auszuschsließen. Das Programm muß da eigentlich nur feststellen ob der Controller sauber druchläuft ohne Aussetzer.

Bei der Hardware ist die Spannungsversorgung sicher eine Fehlerquelle. Eventuell gibt es auch Störungen auf Externen Interrupt pins, die wieder erwarten doch aktiv sind ? Gefährich ist auch immer eine Rückwirkung der Motoren auf die Spannungsversorgung des µC. Hardware Fehler zu finden, die nur sehr selten auftreten ist aber wirklich schwer. Das ist die unangenehmste Sorte.
Hänger durch Hardware Fehler sind aber eher schwer vorstellbar. Meistens geht dann gar nichts mehr, oder das Programm startet einfach wieder von vorne.

Bei Software-problemen sollte man mal mit einer Version vergleichen, die noch ohne Hänger lief.

Kann es bei mehreren ISRs eventuell dazu kommen, das eine ISR gar nicht mehr ausgeführt wird, oder ist die ISR belastung eher gering ?
So tückische Sachen wie ISRs die den Interrupt wieder freigeben sind doch hoffentlich nicht drin oder ? Die sind nämlich sehr Fehleranfällig. Zu debugzwecken kann es Hilfreich sein wenn man den Anfang einer ISR von Außen erkennen kann (z.B. LED aufblinken). Mit der UART könnte man auch an makanten Punkten im Programm jeweils einen Buchstaben schicken und das dann in ein File Speichern. So kann man eventeulle grob einkreisen was zuletzt gemacht wurde. Man braicht sich von dem möglicherweise riesigen File ja in der Regel nur das Ende ansehen. Ist aber auch eine Menge Aufwand, wenn man das nicht sowieso noch drin hat.

Wie sieht es denn mit dem dynamischen Speicherverbrauch aus ? Besteht die Gefahr, das das RAM voll wird ?

sast
28.01.2009, 07:34
Guten Morgen PCMan,

wie Besserwessi im letzten Satz schreibt, solltest du die mal deinen Speicher etwas genauer ansehen.
Deine Aussage: vorher ging das immer alles, deutet da doch auf ein hineinlaufen des Stackpointers in den Heap hin.
Da gibts einen recht brauchbaren Tipp hier im rn wissen

// __heap_start is declared in the linker script
extern unsigned char __heap_start;
...
uint16_t momentan_frei = SP - (uint16_t) &__heap_start;

Hatte auch mal einen ähnlichen Fall, in dem an völlig unerklärlichen Stellen das Programm ausgestiegen ist. Geholfen hat dann am Ende, dass ich nun die ganzen Menüstrings und Errorcodes aus dem Flash hole und nicht mehr im Programm abgespeichert habe.

sast

PCMan
28.01.2009, 08:14
Hi Besserwessi und sast,
danke für eure Beteiligung. Gut ich gebe zu, Aussagen wie "es ging ja schonmal" sind in der Technik wohl fehl am Platze. Ich habe das Programm über Nacht wieder laufen lassen und diesmal hat sich der µC nach 1100min resettet.
Aber zunächst zu den vielen Denkanstößen:

1) Ich habe die Motoren abgesteckt, es gibt also keine Aktivität diesbezüglich. Das Programm bleibt trotzdem "hängen". Ich habe einen Taster am INT2, der dann eine Aktion hervorrufen sollte (legt den contrast pin des Displays auf High). Das passiert aber nicht, also wird auf dieses Interrupt garnicht reagiert.

2) Die ISRs sind soweit abgespeckt, so dass bstenfalls mal eine if abfrage drin ist und ein Flag gesetzt wird. Absolut unkritisch. Es sind auch keine sei() oder cli() oder sonstwas drin (soweit ich das verstanden habe, kann man auf diese Weise ja einen Stack Overflow sogar provozieren)

3) das mit dem Buchstaben schicken habe ich schon probiert. Das Programm befand sich immer in main(), wenn es "abstürzte". Da ich aber inzwischen ein Update durchgeführt habe, sollte ich das nochmal machen.

4) Es gibt bei mir ein paar Dinge in den UART Routinen die malloc verwenden. Dort habe ich Speicherlecks aber schon ausgeschlossen. Ich könnte den Parser aber einfach mal abschalten und gucken, ob es daran liegt. Der Parser wird aber eigentlich erst dann aktiviert, wenn das zeichen 13 empfangen wurde. Hm, könnte sein, dass mir ein Störsignal das induziert, aber dazu brauchts ja auch gleich mal 12V Spannungshub, da glaube ich irgendwie nicht so dran.

5) Alle Strings liegen im Flash und bleiben durch die PROGMEM Direktive auch dort. Also dass der Ram überläuft glaube ich auch eher weniger.

Ich würde gerne den Stack-Pointer überwachen. Wenn ein Stack-Overfloe eintritt, dann sollte der Pointer doch eine bestimmte maximumgrenze überschreiten, oder? Ist das __heap_start? Wenn diese Grenze erreicht wird (oder sagen wir mal 1-Grenze), dann möchte ich eine LED togglen, um zumindest mal das auszuschließen.

Viele Grüße und schönen dank nochmals,
Simon

sast
28.01.2009, 08:53
Zu heap und stackpointer lies dir mal
https://www.roboternetz.de/wissen/index.php/Speicherverbrauch_bestimmen_mit_avr-gcc
durch

Da ist auch noch eine Routine zur Anzeige des maximalen Verbrauchs mit dabei. Ist ja auch gut zu wissen, dass es daran nicht liegt wenn du sowieso schon alles im Flash hast. Aber vielleicht rufst du ja irgend eine Funktion oder ISR rekursiv auf.

sast

PCMan
28.01.2009, 15:56
Update: ich überwache jetzt seit 8 Stunden den Stackpounter (lasse mir ihn über UART alle Sekunde zusenden). Dabei hat er asich bis jetzt nicht verändert: 2141
Blöde Frage: Wenn ich SP direkt umwandle und schicke, da bekomme ich doch den Inhalt des SP, und nicht die Adresse vom Stackpointer oder? (das wäre dabnn wahrscheinlich &SP).
Simon

sast
28.01.2009, 16:29
zur Info aus der common.h



/*
Stack pointer register.

AVR architecture 1 has no RAM, thus no stack pointer.

All other architectures do have a stack pointer. Some devices have only
less than 256 bytes of possible RAM locations (128 Bytes of SRAM
and no option for external RAM), thus SPH is officially "reserved"
for them.
*/
#if __AVR_ARCH__ >= 100
# ifndef SPL
# define SPL _SFR_MEM8(0x3D)
# endif
# ifndef SPH
# define SPH _SFR_MEM8(0x3E)
# endif
# ifndef SP
# define SP _SFR_MEM16(0x3D)
# endif
#elif __AVR_ARCH__ != 1
# ifndef SPL
# define SPL _SFR_IO8(0x3D)
# endif
# if XRAMEND < 0x100 && !defined(__COMPILING_AVR_LIBC__)
# ifndef SP
# define SP _SFR_IO8(0x3D)
# endif
# else
# ifndef SP
# define SP _SFR_IO16(0x3D)
# endif
# ifndef SPH
# define SPH _SFR_IO8(0x3E)
# endif
# endif /* XRAMEND < 0x100 && !defined(__COMPILING_AVR_LIBC__) */
#endif /* __AVR_ARCH__ != 1 */



/* Stack Pointer (combined) Register */
#if defined(SP)
# define AVR_STACK_POINTER_REG SP
# if __AVR_ARCH__ >= 100
# define AVR_STACK_POINTER_ADDR _SFR_MEM_ADDR(SP)
# else
# define AVR_STACK_POINTER_ADDR _SFR_IO_ADDR(SP)
# endif
#endif


Hast du mal die nicht verwendete Speichergröße ermittelt? Wenn du immer das Selbe machst, steht der Stackpointer auch immer an der selben Stelle bei der Abfrage.

sast

PCMan
28.01.2009, 17:03
hi sast.
Ja hast recht, das muss ich jetzt als nächstes mal machen.
Grüßle Simon

PCMan
18.02.2009, 09:33
Hi,
abschließend wollte ich mitteilen, dass jetzt alles stabil läuft. Offensichtlich handelte es sich doch um eine Art DeadLock, da in einer ISR eine LCD-Schreibroutine aufgerufen wird, die aber im Innern auf ein "Pin-Low" wartet. Nachdem ich das alles aus den ISRs rausgemodelt hatte und nur noch Flags gesetzt hatte, gings dann. Man sollte sich wenn, dann richtig an die ratschläge der Profis handeln ;)
Vielen Dank,
Simon