mikrocontroller.net

Forum: Compiler & IDEs Funktionsaufruf mal gehts, mal nicht?


Autor: Malte (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute,

ich rufe eine Funktion in zwei unterschiedlichen Funktionen auf. In dem 
einen Fall verhält sich die Funktion wie erwartet, in dem anderen Fall 
nicht. Das äußert sich in undefinierten Verhalten des Programms 
einschließlich Reset.

... ziemlich ratlos ...
Malte

  --- file.h ---
void LiPoOptions(struct sMenu* pMenu);
void func2(void);

  --- use1.c ---

main(){
  printf("%p", &LiPoOptions);        // --> 0x3694
  LiPoOptions();                     // geht
  func2();
}

func2(){
  printf("%p", &LiPoOptions);        // --> 0x3694
  LiPoOptions();                     // geht nicht (s.u.)
.... bla bla ...
}
void LiPoOptions() {
  lcd_clr();                         // geht
  LCDSoftChar('a', 0, 0);            // geht
  printf("\nOptions\n");             // geht nicht
}

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Malte wrote:
> void LiPoOptions(struct sMenu* pMenu);
>
> main(){
>   printf("%p", &LiPoOptions);        // --> 0x3694
>   LiPoOptions();                     // geht

Wundert mich, dass das geht. Es fehlt doch das Funktionsargument aus dem 
Funktionsprototypen.

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

Bewertung
0 lesenswert
nicht lesenswert
Bitte poste dein wirkliches Programm und nicht ein extra
für dieses Forum zurechtgestricktes Beispiel. Zu deinem
Problem gibt es 100-erte Möglichkeiten was da schief
gelaufen sein kann. Da brauchen wir nicht auch noch Fehler
die du beim Tippen in diesem Forum eingefügt hast.

Wenn du denkst, dass dein Programm zu lang ist, dann specke es
ab. Stell aber sicher, dass der Fehler noch im Programm ist.
Aber: Auf keinen Fall, auf gar keinen Fall solltest du ein
Programm hier eintippen sondern immer den tatsächlichen
Quelltext veröffentlichen. Entweder indem du die Dateien anhängst,
oder indem du mittels Cut&Paste den Code einstellst.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die erste Vermutung dabei wäre übrigens ein Stacküberlauf.

Autor: Malte (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Erst mal sorry, ich wollte euch nicht mit dem gesamtem Code belästigen. 
Habe den Beitrag dann beim Testen gestern mehrfach überarbeitet und 
offenbar Fehler eingebaut...

Das mit dem Stacküberlauf kam mir dann auch heute Nacht. Ich habe eben 
mal den freien Speicher bestimmt. Dieser liegt zunächst bei 438 Byte.
Was mir dabei auffällt ist das der Funtktionsaufruf (jeweile) eine Menge 
Stack verbraucht. Soviel das dabei (sehr wahrscheinlich) ein Stack 
overflow auftritt. Der Stackverbrauch für den Funktionsaufruf ( Funktion 
s.u. ) liegt so bei 65 Byte wobei mir die Quelle dafür unklar ist.
(Die Funktion ist etwas gestripped und enhält normalerweise mehrere 
Menuelemente. Jedes scheint auf dem Stack zu landen - d.h. der 
Speicherverbrauch ist im Regelfall höher)



Verwendet habe ich folgende Methode um den freien Speicher zu bestimmen.
http://www.roboternetz.de/wissen/index.php/Speiche...

Codeschnipsel (kopiert)

typedef struct {
  enum eElementType ElementType;
} tElement;

typedef struct sMenu {
  int  v;
  int  numEl;
  tElement** el;
} tMenu;

typedef struct {
  enum  eElementType ElementType;
  char text[LCD_DISP_LENGTH];
  float v;
  float min;
  float max;
  float gran;
} tFloatParameter;


void LiPoOptions (void) {
  uint8_t mmEntries = 0;
  tElement* MenuElements[MAX_OPT_MENU_ENTRIES];

   tFloatParameter DisChgCellVlim      = {FLOAT_PARAM, "Entl. Sp. %4.1f 
V", 2.5, 4.2, 3.0};
   MenuElements[mmEntries++] = (tElement*)&DisChgCellVlim;

  tMenu Menu = {0, mmEntries, MenuElements};
  sub_menu(&Menu);
}

Autor: Malte (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Huch da ist noch ein Fehler

tFloatParameter DisChgCellVlim      = {FLOAT_PARAM, "Entl. Sp. %4.1f
V", 2.5, 4.2, 3.0};

muss heißen:

tFloatParameter DisChgCellVlim      = {FLOAT_PARAM, "Entl. Sp. %4.1f
V",3.0, 2.5, 4.2, 0.1};

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

Bewertung
0 lesenswert
nicht lesenswert
> 65 Byte wobei mir die Quelle dafür unklar ist
Wie gross ist LCD_DISP_LENGTH und wieviele Texte hast du
so in etwa pro Funktion.

Stack Overflow könnte sein.
Als erstes würde ich mal die Texte komplett aus dem
SRAM verbannen und im Flash belassen. Das sollte dann
schon einiges an SRAM zurückbringen.

http://www.mikrocontroller.net/articles/AVR-GCC-Tu...

Deine Struktur sieht dann so aus
typedef struct {
  enum  eElementType ElementType;
  const char* text;
  float v;
  float min;
  float max;
  float gran;
} tFloatParameter;

char DisChgCellVlimTxt[] PROGMEM = "Entl. Sp. %4.1fV"; 
tFloatParameter DisChgCellVlim      = {FLOAT_PARAM, DisChgCellVlimTxt, 3.0, 2.5, 4.2, 0.1};

Beim Zugriff auf den Text dann die pgm_readxxxx bzw. (der Text sieht
mir danach aus, als ob er direkt für printf benutzt wird) printf_p
benutzen. printf_p erwartet den Formatstring im Flash.

Autor: Malte (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
LCD_DISP_LENGTH ist 21
sizeof(tFloatParameter) ist 39.

Mir ist klar das ich mit dem SRAM sehr "großzügig" umgehe und das es 
bessere Methoden gibt hier solche Daten zu speichern.
Nicht klar ist mir warum die Struktur DisChgCellVlim auf dem Stack zu 
landen scheint. Die Funktion hat normalerweise 3 Menuelemente und 
verbraucht dann 147 bytes auf dem Stack. Das ganze geht in dem Programm 
bis 10 Menuelemente. Das sind dann >390byte auf dem Stack. Dazu kommt 
das es Untermenus gibt, sich das ganze also addiert.

Warum?

Autor: Malte (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Noch ein Nachtrag:

Mache ich die struktur tFloatParameter DisChgCellVlim global dann 
schrumpft der Stack um eine zu erwartende Grösse. Die Section .data wird 
um 38 Byte grösser. Könnte also passen. Das würde, mein Verständniss 
vorausgesetzt, bedeuten das das struct DisChgCellVlim wirklich im Stack 
liegt.
Klingt fast wie die Verwendung von __builtin_alloca

Ich habe mir das Assemblerlisting angesehen, bin aber da zu wenig 
bewandert um das wirklich zu verstehen.

Gruß
Malte

Autor: Malte (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Noch ein Nachtrag, dann geh ich ins Bett:

so siehts im Assemblerlisting aus, wenn mich nicht alles täuscht wird da 
Platz vom Stack abgezogen und dann für das Struct verwendet.

Also Platz im SRAM schaffen. Naja morgen gehts weiter.

 150                 /* prologue: frame size=71 */
 151 0000 CF93          push r28
 152 0002 DF93          push r29
 153 0004 CDB7          in r28,__SP_L__
 154 0006 DEB7          in r29,__SP_H__
 155 0008 C754          subi r28,lo8(71)
 156 000a D040          sbci r29,hi8(71)
 157 000c 0FB6          in _tmp_reg_,__SREG__
 158 000e F894          cli
 159 0010 DEBF          out _SP_H_,r29
 160 0012 0FBE          out _SREG_,__tmp_reg__
 161 0014 CDBF          out _SP_L_,r28
 162                 /* prologue end (size=11) */
  20:xtc_src/BattOptions.c ****   uint8_t mmEntries = 0;
 163                   .stabn  68,0,20,.LM1-.LFBB1
 164                 .LM1:
 165 0016 1B82          std Y+3,__zero_reg__
  21:xtc_src/BattOptions.c ****
  22:xtc_src/BattOptions.c ****   tElement* 
MenuElements[MAX_OPT_MENU_ENTRIES];
  23:xtc_src/BattOptions.c ****
  24:xtc_src/BattOptions.c ****   tBatteryOptions* pBatteryOptions = 
Battery[LI37].pBatteryOptions;
 166                   .stabn  68,0,24,.LM2-.LFBB1
 167                 .LM2:
 168 0018 8091 0000     lds r24,Battery+32
 169 001c 9091 0000     lds r25,(Battery+32)+1
 170 0020 9A83          std Y+2,r25
 171 0022 8983          std Y+1,r24
  25:xtc_src/BattOptions.c ****
  26:xtc_src/BattOptions.c ****
  27:xtc_src/BattOptions.c ****   tFloatParameter DisChgCellVlim      = 
{FLOAT_PARAM, "Entl. Sp. %4.1f V", pBatteryOptions->DisChgC
 172                   .stabn  68,0,27,.LM3-.LFBB1
 173                 .LM3:
 174 0024 E981          ldd r30,Y+1
 175 0026 FA81          ldd r31,Y+2
 176 0028 8081          ld r24,Z
 177 002a 9181          ldd r25,Z+1
 178 002c A281          ldd r26,Z+2
 179 002e B381          ldd r27,Z+3
 180 0030 2396          adiw r28,63-60
 181 0032 8CAF          std Y+60,r24
 182 0034 9DAF          std Y+61,r25
 183 0036 AEAF          std Y+62,r26
 184 0038 BFAF          std Y+63,r27
 185 003a 2397          sbiw r28,63-60
 186 003c 87E2          ldi r24,lo8(39)
 187 003e FE01          movw r30,r28
 188 0040 7296          adiw r30,18
 189 0042 DF01          movw r26,r30
 190 0044 982F          mov r25,r24
 191 0046 1D92          st X+,__zero_reg__
 192 0048 9A95                dec r25
 193 004a 01F4          brne .-6
 194 004c 82E0          ldi r24,lo8(2)
 195 004e 90E0          ldi r25,hi8(2)
 196 0050 9B8B          std Y+19,r25
 197 0052 8A8B          std Y+18,r24

...

 337                 /* epilogue: frame size=71 */
 338 015a C95B          subi r28,lo8(-71)
 339 015c DF4F          sbci r29,hi8(-71)
 340 015e 0FB6          in _tmp_reg_,__SREG__
 341 0160 F894          cli
 342 0162 DEBF          out _SP_H_,r29
 343 0164 0FBE          out _SREG_,__tmp_reg__
 344 0166 CDBF          out _SP_L_,r28
 345 0168 DF91          pop r29
 346 016a CF91          pop r28
 347 016c 0895          ret
 348                 /* epilogue end (size=10) */

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Erst mal sorry, ich wollte euch nicht mit dem gesamtem Code belästigen.

Das ist ja im Prinzip eine gute Idee, aber man sollte nie als Teil der 
Fehlerbeschreibung Code angeben, der nur für das Posting neu eingetippt 
wurde. Der enthält erfahrungsgemäß oft nicht den Fehler, um den es geht, 
dafür aber jede Menge andere Fehler. Also immer Code posten, den du auch 
tatsächlich mal so durch den Compiler hast laufen lassen.

> Nicht klar ist mir warum die Struktur DisChgCellVlim auf dem Stack zu
> landen scheint.

Lokale Variablen werden eben (so sie zu groß für Register sind) im Stack 
angelegt. Wo hättest du sie erwartet?

Autor: OliverSo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eigentlich ist es auch egal, ob die Variablen auf dem Stack oder sonstwo 
im SRAM landen - es gibt nur ein SRAM, und ob das nun von oben nach 
unten, oder von unten nach oben überläuft, ändert am Ergebnis nichts.

Oliver

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.