mikrocontroller.net

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


Autor: Frank Kalka (verpeilt)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
habe den folgenden Code:
#include <stdlib.h>
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "lcd.h"
#include "menu.h"

#define ENTER   (1<<PA0)
#define FIRE    (1<<PA3)



/*int8_t errorHandler(int8_t error_code) {
  switch (error_code) {
  case 0: // OK, nothing to do
    lcd_puts("!OK!");
    break;
  case 1: // servo is not ready
    lcd_clrscr();
    lcd_gotoxy(4, 0);
    lcd_puts("ERROR 1");
    lcd_gotoxy(0, 1);
    lcd_puts("Motor nicht");
    lcd_gotoxy(0, 2);
    lcd_puts("bereit!");
    break;
  case 2: // Servo alert
    lcd_clrscr();
    lcd_gotoxy(4, 0);
    lcd_puts("ERROR 2");
    lcd_gotoxy(0, 1);
    lcd_puts("Servo Alarm!");
    break;
  case 3: // Break should not be open
    lcd_clrscr();
    lcd_gotoxy(4, 0);
    lcd_puts("ERROR 3");
    lcd_gotoxy(0, 1);
    lcd_puts("Keine Brems-");
    lcd_gotoxy(0, 2);
    lcd_puts("freigabe!");
    break;
  case 4: // Sled is not in home position
    lcd_clrscr();
    lcd_gotoxy(4, 0);
    lcd_puts("ERROR 4");
    lcd_gotoxy(0, 1);
    lcd_puts("Schlitten nicht");
    lcd_gotoxy(0, 2);
    lcd_puts("auf Startpositon");
    break;
  case 5: // home position marker malfunction
    lcd_clrscr();
    lcd_gotoxy(4, 0);
    lcd_puts("ERROR 5");
    lcd_gotoxy(0, 1);
    lcd_puts("HomPos Marker");
    lcd_gotoxy(0, 2);
    lcd_puts("Fehlfunktion!");
    break;
  case 6: // near home position marker malfunction
    lcd_clrscr();
    lcd_gotoxy(4, 0);
    lcd_puts("ERROR 6");
    lcd_gotoxy(0, 1);
    lcd_puts("NerHomPos Marker");
    lcd_gotoxy(0, 2);
    lcd_puts("Fehlfunktion!");
    break;
  case 7: // end position marker malfunction
    lcd_clrscr();
    lcd_gotoxy(4, 0);
    lcd_puts("ERROR 7");
    lcd_gotoxy(0, 1);
    lcd_puts("EndPos Marker");
    lcd_gotoxy(0, 2);
    lcd_puts("Fehlfunktion!");
    break;
  }
  while (!(ENTER & PINA)) {
  }
  _delay_ms(100);
  return error_code;
}//errorHandler(int8_t error_code)
*/

int main(void) {
  MENU* m = newNode(NULL, "Kalibrierung", "Einstellungen", "Messwerte",
      "Status", NULL);

  m->subs[0] = newNode(m, "Start", "Ergebnis", NULL, NULL, NULL);
  m->subs[0]->subs[0] = newNode(m->subs[0], NULL, NULL, NULL, NULL,
      startKalib);
  m->subs[0]->subs[1]
      = newNode(m->subs[0], NULL, NULL, NULL, NULL, showKalib);

  m->subs[1] = newNode(m, "Messfahrt", "Rueckfahrt", NULL, NULL, NULL);
  m->subs[1]->subs[0] = newNode(m->subs[1], "1.Rampe", "2.Rampe", "Messzeit",
      "Beschleunigung", NULL);
  m->subs[1]->subs[0]->subs[0] = newNode(m->subs[1]->subs[0], NULL, NULL,
      NULL, NULL, set1ramp);
  m->subs[1]->subs[0]->subs[1] = newNode(m->subs[1]->subs[0], NULL, NULL,
      NULL, NULL, set2ramp);
  m->subs[1]->subs[0]->subs[2] = newNode(m->subs[1]->subs[0], NULL, NULL,
      NULL, NULL, setTime);
  m->subs[1]->subs[0]->subs[3] = newNode(m->subs[1]->subs[0], NULL, NULL,
      NULL, NULL, setAcc);

  m->subs[1]->subs[1] = newNode(m->subs[1], NULL, NULL, NULL, NULL,
      setBackSettings);

  m->subs[2] = newNode(m, "Kalib Faktor", "Gewicht", NULL, NULL, NULL);
  m->subs[2]->subs[0]
      = newNode(m->subs[2], NULL, NULL, NULL, NULL, showKalib);
  m->subs[2]->subs[1] = newNode(m->subs[2], NULL, NULL, NULL, NULL, showMass);

  m->subs[3] = newNode(m, "Leer", NULL, NULL, NULL, NULL);

  char acc_line = 1;
  int temp;
  MENU *act = m;

  DDRA = 0x00;
  PORTA = 0xFF;
  encode_init();
  lcd_init(LCD_DISP_ON);
  lcd_puts("     TEST");
  _delay_ms(500);
  lcd_clrscr();
  lcd_command(LCD_DISP_ON_BLINK);
  showPage(m);
  while (1) {
    temp = PINA;
    _delay_ms(50);
    temp |= PINA;

    if (!(ENTER & temp)) {
      doNode(&act, acc_line, 0);
      acc_line = 1;
      //showPage(act);
      _delay_ms(50);
    }
    if (!(FIRE & temp)) {
      doNode(&act, 0, 0);
      _delay_ms(50);
    }
    temp = getScr();
    if (temp < 0) {
      if (acc_line < numberOfSubs(act))
        acc_line++;
    }
    if (temp > 0) {
      if (acc_line > 0)
        acc_line--;
      if (acc_line == 0) {
        doNode(&act, 0, 0);
        acc_line = 1;
      }
    }
    lcd_gotoxy(0, acc_line - 1);
  }
  return 0;
}

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.

Autor: Arne (Gast)
Datum:

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

Autor: Peter Dannegger (peda)
Datum:

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


Peter

Autor: Stefan B. (stefan) Benutzerseite
Datum:

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

Autor: Frank Kalka (verpeilt)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, das werd ich mir mal anschaun.

Danke für die Tips.

Autor: Arne (Gast)
Datum:

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

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

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

Autor: Frank Kalka (verpeilt)
Datum:

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

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

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

Bewertung
0 lesenswert
nicht lesenswert
Frank Kalka schrieb:
> Kann gut sein, dass nicht nur die Strings das Problem sind, sonder auch
> das Menükonstrukt.
>
>
> typedef struct menu {
>   struct menu *father;
>   struct menu *subs[4];
>   char *zeile[16];
>   int (*func)(int);
> } MENU;
> 
>
> 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.

Autor: Frank Kalka (verpeilt)
Datum:

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

Autor: Oliver (Gast)
Datum:

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

Autor: Arne (Gast)
Datum:

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

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

Bewertung
0 lesenswert
nicht lesenswert
Frank Kalka schrieb:

>
> typedef struct menu {
>   struct menu *father;
>   struct menu *subs[4];
>   char *zeile[16];
>   int (*func)(int);
> } MENU;
> 

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)

Autor: Frank Kalka (verpeilt)
Datum:

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

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

Bewertung
0 lesenswert
nicht 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
  MENU* m = newNode(NULL, "Kalibrierung", "Einstellungen", "Messwerte",
      "Status", NULL);

im Speicher sowas konstruiert
                   +-------------------------------------+
  m                v                                     |
  +-----+         +-----------+                          |
  |  o----------->| NULL      |                          |
  +-----+         +-----------+                     +----|---+
                  |    o--------------------------->|    o   |
                  +-----------+                     +--------+
                  |    o------------------------+   | NULL   |
                  +-----------+                 |   +--------+
                  |    o----------------+       |   | NULL   |
                  +-----------+         |       |   +--------+
                  |    o---------+      |       |   | NULL   |
                  +-----------+  |      |       |   +--------+
                  | NULL      |  |      |       |   | NULL   |
                  +-----------+  |      |       |   +--------+
                  | NULL      |  |      |       |   +   o--------->"Kalibrierung"
                  +-----------+  |      |       |   +--------+
                                 |      |       |   | NULL   |
                                 |      |       |   +--------+
                                 |      |       |
                                 |      |       |   +--------+    |
                                 |      |       +-->|   o---------+
                                 |      |           +--------+
                                 |      |           | NULL   |
                                 |      |           +--------+
                                 |      |           | NULL   |
                                 |      |           +--------+
                                 |      |           | NULL   |
                                 |      |           +--------+
                                 |      |           | NULL   |
                                 |      |           +--------+
                                 |      |           |   o---------->"Einstellungen"
                                 |      |           +--------+
                                 |      |           | NULL   |
                                 |      |           +--------+
                               ....   ....

Alleine dieses Hauptmenü kostet dir schon Unmengen an Speicher

Autor: Frank Kalka (verpeilt)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hmm, was ich beabsichtigt habe war eigentlich mehr sowas:
                  
  m                                                     
  +-----------+                          
  | NULL      |
  +-----------+
  |    o------------------------> struct *subs[4]                                 
  +-----------+                          
  |    o--------------> "Kalibrierung"
  +-----------+                     
  |    o--------------> "Einstellungen"
  +-----------+                 
  |    o--------------> "Messwerte"
  +-----------+         
  |    o-------------->  "Status" 
  +-----------+ 
  | NULL      | 
  +-----------+  
                                 
                                 

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

Bewertung
0 lesenswert
nicht 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
typedef struct menu;

typedef struct menuEntry {
  char        *text;
  struct menu *sub;
};

typedef struct menu {
  struct menu      *father;
  struct menuEntry entries[4];
  int (*func)(int);
} 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)
typedef struct menu;

typedef struct menuEntry {
  char        *text;
  struct menu *sub;
};

typedef struct menu {
  struct menu      *father;
  int (*func)(int);
  unsigned char    nrEntries;
  struct menuEntry entries[];
} 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.

Autor: gast (Gast)
Datum:

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

Autor: Frank Kalka (verpeilt)
Datum:

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

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.