Forum: Mikrocontroller und Digitale Elektronik Unerklärlicher Reset, ATmega16


von Frank K. (verpeilt)


Lesenswert?

Hallo,
habe den folgenden Code:
1
#include <stdlib.h>
2
#include <inttypes.h>
3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5
#include <util/delay.h>
6
#include "lcd.h"
7
#include "menu.h"
8
9
#define ENTER   (1<<PA0)
10
#define FIRE    (1<<PA3)
11
12
13
14
/*int8_t errorHandler(int8_t error_code) {
15
  switch (error_code) {
16
  case 0: // OK, nothing to do
17
    lcd_puts("!OK!");
18
    break;
19
  case 1: // servo is not ready
20
    lcd_clrscr();
21
    lcd_gotoxy(4, 0);
22
    lcd_puts("ERROR 1");
23
    lcd_gotoxy(0, 1);
24
    lcd_puts("Motor nicht");
25
    lcd_gotoxy(0, 2);
26
    lcd_puts("bereit!");
27
    break;
28
  case 2: // Servo alert
29
    lcd_clrscr();
30
    lcd_gotoxy(4, 0);
31
    lcd_puts("ERROR 2");
32
    lcd_gotoxy(0, 1);
33
    lcd_puts("Servo Alarm!");
34
    break;
35
  case 3: // Break should not be open
36
    lcd_clrscr();
37
    lcd_gotoxy(4, 0);
38
    lcd_puts("ERROR 3");
39
    lcd_gotoxy(0, 1);
40
    lcd_puts("Keine Brems-");
41
    lcd_gotoxy(0, 2);
42
    lcd_puts("freigabe!");
43
    break;
44
  case 4: // Sled is not in home position
45
    lcd_clrscr();
46
    lcd_gotoxy(4, 0);
47
    lcd_puts("ERROR 4");
48
    lcd_gotoxy(0, 1);
49
    lcd_puts("Schlitten nicht");
50
    lcd_gotoxy(0, 2);
51
    lcd_puts("auf Startpositon");
52
    break;
53
  case 5: // home position marker malfunction
54
    lcd_clrscr();
55
    lcd_gotoxy(4, 0);
56
    lcd_puts("ERROR 5");
57
    lcd_gotoxy(0, 1);
58
    lcd_puts("HomPos Marker");
59
    lcd_gotoxy(0, 2);
60
    lcd_puts("Fehlfunktion!");
61
    break;
62
  case 6: // near home position marker malfunction
63
    lcd_clrscr();
64
    lcd_gotoxy(4, 0);
65
    lcd_puts("ERROR 6");
66
    lcd_gotoxy(0, 1);
67
    lcd_puts("NerHomPos Marker");
68
    lcd_gotoxy(0, 2);
69
    lcd_puts("Fehlfunktion!");
70
    break;
71
  case 7: // end position marker malfunction
72
    lcd_clrscr();
73
    lcd_gotoxy(4, 0);
74
    lcd_puts("ERROR 7");
75
    lcd_gotoxy(0, 1);
76
    lcd_puts("EndPos Marker");
77
    lcd_gotoxy(0, 2);
78
    lcd_puts("Fehlfunktion!");
79
    break;
80
  }
81
  while (!(ENTER & PINA)) {
82
  }
83
  _delay_ms(100);
84
  return error_code;
85
}//errorHandler(int8_t error_code)
86
*/
87
88
int main(void) {
89
  MENU* m = newNode(NULL, "Kalibrierung", "Einstellungen", "Messwerte",
90
      "Status", NULL);
91
92
  m->subs[0] = newNode(m, "Start", "Ergebnis", NULL, NULL, NULL);
93
  m->subs[0]->subs[0] = newNode(m->subs[0], NULL, NULL, NULL, NULL,
94
      startKalib);
95
  m->subs[0]->subs[1]
96
      = newNode(m->subs[0], NULL, NULL, NULL, NULL, showKalib);
97
98
  m->subs[1] = newNode(m, "Messfahrt", "Rueckfahrt", NULL, NULL, NULL);
99
  m->subs[1]->subs[0] = newNode(m->subs[1], "1.Rampe", "2.Rampe", "Messzeit",
100
      "Beschleunigung", NULL);
101
  m->subs[1]->subs[0]->subs[0] = newNode(m->subs[1]->subs[0], NULL, NULL,
102
      NULL, NULL, set1ramp);
103
  m->subs[1]->subs[0]->subs[1] = newNode(m->subs[1]->subs[0], NULL, NULL,
104
      NULL, NULL, set2ramp);
105
  m->subs[1]->subs[0]->subs[2] = newNode(m->subs[1]->subs[0], NULL, NULL,
106
      NULL, NULL, setTime);
107
  m->subs[1]->subs[0]->subs[3] = newNode(m->subs[1]->subs[0], NULL, NULL,
108
      NULL, NULL, setAcc);
109
110
  m->subs[1]->subs[1] = newNode(m->subs[1], NULL, NULL, NULL, NULL,
111
      setBackSettings);
112
113
  m->subs[2] = newNode(m, "Kalib Faktor", "Gewicht", NULL, NULL, NULL);
114
  m->subs[2]->subs[0]
115
      = newNode(m->subs[2], NULL, NULL, NULL, NULL, showKalib);
116
  m->subs[2]->subs[1] = newNode(m->subs[2], NULL, NULL, NULL, NULL, showMass);
117
118
  m->subs[3] = newNode(m, "Leer", NULL, NULL, NULL, NULL);
119
120
  char acc_line = 1;
121
  int temp;
122
  MENU *act = m;
123
124
  DDRA = 0x00;
125
  PORTA = 0xFF;
126
  encode_init();
127
  lcd_init(LCD_DISP_ON);
128
  lcd_puts("     TEST");
129
  _delay_ms(500);
130
  lcd_clrscr();
131
  lcd_command(LCD_DISP_ON_BLINK);
132
  showPage(m);
133
  while (1) {
134
    temp = PINA;
135
    _delay_ms(50);
136
    temp |= PINA;
137
138
    if (!(ENTER & temp)) {
139
      doNode(&act, acc_line, 0);
140
      acc_line = 1;
141
      //showPage(act);
142
      _delay_ms(50);
143
    }
144
    if (!(FIRE & temp)) {
145
      doNode(&act, 0, 0);
146
      _delay_ms(50);
147
    }
148
    temp = getScr();
149
    if (temp < 0) {
150
      if (acc_line < numberOfSubs(act))
151
        acc_line++;
152
    }
153
    if (temp > 0) {
154
      if (acc_line > 0)
155
        acc_line--;
156
      if (acc_line == 0) {
157
        doNode(&act, 0, 0);
158
        acc_line = 1;
159
      }
160
    }
161
    lcd_gotoxy(0, acc_line - 1);
162
  }
163
  return 0;
164
}

der mir ein Menü auf nem LCD ausgiebt. Die Navigation erfolgt mittels 
Scrollrad und einem Taster. Alles funktionierte problemlos. Binde ich 
nun aber die errorHandler() zusätzlich ein, bekomme ich ständig einen 
Reset beim Eintritt in die Hauptschleife. Das ist unabhängig davon, ob 
ich die Funktion wirklich aufrufe oder nicht!

Hat jemand ne Idee woran das liegen könnte?

Ich bin mit meinem Latein langsam am Ende.

von Arne (Gast)


Lesenswert?

Ich weiss jetzt nicht, was die ganzen lcd_* funktionen für einen 
Stackverbrauch haben und was sonst noch in dem Programm läuft, tippe 
aber mal drauf, dass der Stack ins DATAT/BSS Segment bzw. Heap 
hineinwächst und Dir da etwas schrottet.
Da würde ich zuerst nachhaken. Watchdog-Reset ist aus?

von Peter D. (peda)


Lesenswert?

Durch die zusätzlichen Strings läuft Dein SRAM über.
Du mußt Strings im Flash plazieren (progmem.h).


Peter

von Stefan B. (stefan) Benutzerseite


Lesenswert?

> Binde ich nun aber die errorHandler() zusätzlich ein, bekomme
> ich ständig einen Reset beim Eintritt in die Hauptschleife.
> Das ist unabhängig davon, ob ich die Funktion wirklich aufrufe
> oder nicht!

Speicher (SRAM) voll und daher Stack zerschossen?

von Frank K. (verpeilt)


Lesenswert?

Ok, das werd ich mir mal anschaun.

Danke für die Tips.

von Arne (Gast)


Lesenswert?

@Peter Dannegger

der Mega16 hat 1kB SRAM... meinst Du nicht, dass das für die paar 
Strings reichen sollte? Wobei die Lösung mit den Strings im Flash 
sowieso die bessere Alternative wäre...

von Karl H. (kbuchegg)


Lesenswert?

Arne schrieb:
> @Peter Dannegger
>
> der Mega16 hat 1kB SRAM... meinst Du nicht, dass das für die paar
> Strings reichen sollte?

Schau dir an, was da sonst noch passiert.
Offenbar gibt es eine dynamische Allokierung der Menüstruktur. Und sooo 
wenige Strings sind das gar nicht. Mit den ganzen Menütexten und 
Fehlertexten kommt da schon einiges zusammen. Dazu dann noch die 
Menüknoten im SRAM ... (wie gross die Textfelder in den Menüknoten sind, 
wissen wir leider nicht)

> Wobei die Lösung mit den Strings im Flash
> sowieso die bessere Alternative wäre...

Yep.
Und die Menüstruktur nicht dynamisch zusammenbauen. Das kann man auch 
statisch machen (und bei der Gelegenheit ebenfalls nach und nach ins 
Flash verbannen). Aber auf jeden Fall im ersten Schritt soviel wie 
möglich statisch allokieren, damit der SRAM Verbrauch, den der Compiler 
ausrechnet so nah wie möglich am SRAM Verbrauch zur Laufzeit liegt und 
daher auch aussagekräftig wird. Je mehr man dynamisch allokiert, desto 
weniger hilft einem die Speicher Summary, die der Compiler berechnet.

von Frank K. (verpeilt)


Lesenswert?

Kann gut sein, dass nicht nur die Strings das Problem sind, sonder auch 
das Menükonstrukt.
1
typedef struct menu {
2
  struct menu *father;
3
  struct menu *subs[4];
4
  char *zeile[16];
5
  int (*func)(int);
6
} MENU;

Hatte bis jetzt noch nie Probleme mit dem Speicherplatz. In das 
Themengebiet muss ich mich erstmal noch einarbeiten.

von Karl H. (kbuchegg)


Lesenswert?

Frank Kalka schrieb:
> Kann gut sein, dass nicht nur die Strings das Problem sind, sonder auch
> das Menükonstrukt.
>
>
1
> typedef struct menu {
2
>   struct menu *father;
3
>   struct menu *subs[4];
4
>   char *zeile[16];
5
>   int (*func)(int);
6
> } MENU;
7
>
>
> Hatte bis jetzt noch nie Probleme mit dem Speicherplatz. In das
> Themengebiet muss ich mich erstmal noch einarbeiten.

Sowas kannst du auf einem PC mit praktisch unbegrenztem Speicher machen. 
Aber in einem µC mit limitierten Resourcen ist das unklug. Ebenso die 
dynamische Allokierung.

Jeder Menüknoten belegt 44 Bytes.
Ich hab mir deinen Menübaum nicht komplett aufgezeichnet. Aber der Teil 
den ich aufgemalt habe, sind bereits 10 Knoten. Macht 440 Bytes. Und das 
sind nur die Knoten, keine Texte! Du hast aber nur 1024 Bytes!

Das ist alles viel zu verschwenderisch gemacht.

von Frank K. (verpeilt)


Lesenswert?

Ja, das Menü hatte ich auch ursprünglich bei nem kleine Programm für PC 
benutzt. Dachte ich könnte es mit einigen kleinen Modifikationen auch 
auf dem Controller nutzen.
Dann werd ich mir mal die Speicherverwaltung genauer ansehen müssen und 
das Ganze doch neu schreiben.

Danke für die schnelle Hilfe. Jetzt hab ich nen Ansatzpunkt.
Gruß
Frank

von Oliver (Gast)


Lesenswert?

>der Mega16 hat 1kB SRAM...

wovon grob geschätzt 400 Byte für die Stringkonstanten verbraucht 
werden, dazu landen die Strings der Menutext zweimal im SRAM, in Summe 
also ca. 500 Byte. Das alleine bringt das SRAM noch nicht zum 
überlaufen.

Allerdings sieht mit die Funktion newNode() sehr nach dynamischer 
Speicherverwaltung aus. Je nachdem, wie die implementiert ist, und was 
noch alles in menu.c passiert, wird es dann doch eng im SRAM.

Oliver

von Arne (Gast)


Lesenswert?

Ohhh ja.... bei dem struct komme ich auf 44Byte je Instanz!
Da hat Karl-Heinz Recht: da solltest (musst) Du umstricken.
Aber in die Falle sind wohl die meisten von uns am Anfang gelaufen ;)

von Karl H. (kbuchegg)


Lesenswert?

Frank Kalka schrieb:

>
1
> typedef struct menu {
2
>   struct menu *father;
3
>   struct menu *subs[4];
4
>   char *zeile[16];
5
>   int (*func)(int);
6
> } MENU;
7
>

Der Rest deiner Menüstruktur ist mir klar, aber wozu brauchst du zeile?
Von den 44 Bytes pro Knoten gehen immerhin 32 nur für diese 16 Pointer 
drauf. Und so richtig ist mir nicht klar, worauf diese 16 Pointer zeigen 
könnten. Dein Menü kann offenbar pro Knoten 4 Submenüs enthalten. Ich 
würde mal erwarten, dass für jeden Menüpunkt 1 char Pointer für den 
Menütext vorhanden ist. Aber nicht 16.

(Ok, du hast im LCD offenbar 4 Zeilen. 4*4 macht 16. Nur seh ich den 
Zusammenhang immer noch nicht)

von Frank K. (verpeilt)


Lesenswert?

@Karl heinz Buchegger

Bei den Pointern für die Zeilen hast du natürlich recht. Das war ein 
Denkfehler von mir. Das sollte ein Pointer auf einen 16 Zeichen String 
sein, weil mein LCD 16 Zeichen pro Zeile hat. Is so natürlich falsch.

von Karl H. (kbuchegg)


Lesenswert?

Frank Kalka schrieb:
> @Karl heinz Buchegger
>
> Bei den Pointern für die Zeilen hast du natürlich recht. Das war ein
> Denkfehler von mir. Das sollte ein Pointer auf einen 16 Zeichen String
> sein, weil mein LCD 16 Zeichen pro Zeile hat. Is so natürlich falsch.

Ui. Dann bin ich beim Aufzeichnen der Datenstruktur noch viel zu 
optimistisch vorgegangen

D.h. dann, dass das hier
1
  MENU* m = newNode(NULL, "Kalibrierung", "Einstellungen", "Messwerte",
2
      "Status", NULL);

im Speicher sowas konstruiert
1
                   +-------------------------------------+
2
  m                v                                     |
3
  +-----+         +-----------+                          |
4
  |  o----------->| NULL      |                          |
5
  +-----+         +-----------+                     +----|---+
6
                  |    o--------------------------->|    o   |
7
                  +-----------+                     +--------+
8
                  |    o------------------------+   | NULL   |
9
                  +-----------+                 |   +--------+
10
                  |    o----------------+       |   | NULL   |
11
                  +-----------+         |       |   +--------+
12
                  |    o---------+      |       |   | NULL   |
13
                  +-----------+  |      |       |   +--------+
14
                  | NULL      |  |      |       |   | NULL   |
15
                  +-----------+  |      |       |   +--------+
16
                  | NULL      |  |      |       |   +   o--------->"Kalibrierung"
17
                  +-----------+  |      |       |   +--------+
18
                                 |      |       |   | NULL   |
19
                                 |      |       |   +--------+
20
                                 |      |       |
21
                                 |      |       |   +--------+    |
22
                                 |      |       +-->|   o---------+
23
                                 |      |           +--------+
24
                                 |      |           | NULL   |
25
                                 |      |           +--------+
26
                                 |      |           | NULL   |
27
                                 |      |           +--------+
28
                                 |      |           | NULL   |
29
                                 |      |           +--------+
30
                                 |      |           | NULL   |
31
                                 |      |           +--------+
32
                                 |      |           |   o---------->"Einstellungen"
33
                                 |      |           +--------+
34
                                 |      |           | NULL   |
35
                                 |      |           +--------+
36
                               ....   ....

Alleine dieses Hauptmenü kostet dir schon Unmengen an Speicher

von Frank K. (verpeilt)


Lesenswert?

Hmm, was ich beabsichtigt habe war eigentlich mehr sowas:
1
                  
2
  m                                                     
3
  +-----------+                          
4
  | NULL      |
5
  +-----------+
6
  |    o------------------------> struct *subs[4]                                 
7
  +-----------+                          
8
  |    o--------------> "Kalibrierung"
9
  +-----------+                     
10
  |    o--------------> "Einstellungen"
11
  +-----------+                 
12
  |    o--------------> "Messwerte"
13
  +-----------+         
14
  |    o-------------->  "Status" 
15
  +-----------+ 
16
  | NULL      | 
17
  +-----------+

von Karl H. (kbuchegg)


Lesenswert?

Frank Kalka schrieb:
> Hmm, was ich beabsichtigt habe war eigentlich mehr sowas:

Mag sein.
Aber das ist mit deiner jetzigen Struktur nicht machbar :-)

Tip:
Füg dir noch eine Struktur ein. Die speichert einen Menüpunkt, also die 
Kombination aus Text(-pointer) und Pointer auf das Submenü, dann 
passiert dir sowas nicht
1
typedef struct menu;
2
3
typedef struct menuEntry {
4
  char        *text;
5
  struct menu *sub;
6
};
7
8
typedef struct menu {
9
  struct menu      *father;
10
  struct menuEntry entries[4];
11
  int (*func)(int);
12
} MENU;

Wenn jetzt viele deiner Menüs nur wenige Menüpunkte enthalten, könnte 
man auch überlegen, nicht per Default 4 Einträge pro Menü zu haben, 
sondern diesen Teil dynamisch zu halten (wenns denn unbedingt dynamisch 
bleiben soll)
1
typedef struct menu;
2
3
typedef struct menuEntry {
4
  char        *text;
5
  struct menu *sub;
6
};
7
8
typedef struct menu {
9
  struct menu      *father;
10
  int (*func)(int);
11
  unsigned char    nrEntries;
12
  struct menuEntry entries[];
13
} MENU;

Die Allokierung wird dann ein wenig trickreicher. Aber bei einem Menü 
mit nur 2 Einträgen spart das immerhin 7 Bytes ein. Und deine ganzen 
'Blättermenüpunkte' im Baum haben alle nur wenige Menüpunke.

Auch könnte man darüber nachdenken, ob es unbedingt notwendig ist, einen 
Pointer auf das Vatermenü in der Struktur zu halten. Die maximale 
Verschachtelungstiefe der Menüs ist bekannt und durch die 
Aufrufhierarchie der Menüs kann man auch in einem Stack ganz einfach 
einen Pointer auf den jeweiligen Vater halten. Spart schon wieder 2 
Bytes pro Menü zu Lasten von (wenn ich das richtig gesehen habe) bei dir 
einem globalen Array von 4 Menüpointern und einem 'Stackpointer' der als 
uint8_t ausgeführt sein kann.


-> zurück zu Papier und Bleistift und eine Menüstruktur aufmalen. Bei 
jedem Feld fragen: Brauch ich das unbedingt
Aber auch fragen: Kann ich mit dieser Menüstruktur arbeiten.

von gast (Gast)


Lesenswert?

ich hab mir für strings immer die LCD funktionen gleich als lcd_P() 
gebastelt
aufruf dann lcd_P( PSTR("text") );

oder eben über arrays im flash bei sehr vielen menütexten und einen 
zeiger drauf
aber auch hier brauch man fast nur lcd_P


ebenso UART_P wenn ich strings verschicken will ..
alles so weit es geht in flash werfen

von Frank K. (verpeilt)


Lesenswert?

So, ich hab jetzt alle Strings die ich so hatte in den Flash gepackt und 
jetzt gehts.
Damit ist das Ganze von der Struktur her zwar immer noch suboptimal, 
aber zumindest kann ich damit arbeiten und mich jetzt um den Rest des 
Programms kümmern.
Bei passender Gelegenheit werd ich dann die Struktur nochmal genau 
überdenken und versuchen den Speicherbedarf weiter zu optimieren.

Nochmal herzlichen danke für die schnelle Hilfe!

Gruß
Frank

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.