Forum: Compiler & IDEs Stackproblem ATMEGA128 und GCC


von Andreas Paulin (Gast)


Lesenswert?

Hallo, liebe Gemeinde,

ich habe hier ein Problem in einem größeren SW-Projekt, das mich in den 
Wahnsinn treibt. Sonntagabend arbeiten...
- System ist auf einem ATMEGA128 mit 64k ext. RAM aufgebaut
- AVR-GCC und AVRStudio 4.14

Mein Debug/Testprogramm besteht aus einer Menge kleiner Funktionen, die
durch Bytes aufgerufen werden, die via Bluetooth und UART1 vom PC 
kommen, nach dem Motto

switch (token)
{
case TUDIES:
    ...dies tun
break;
case TUDAS:
    ...das tun
break;
...etcetc
}

Soweit, so gut. 70kB Code laufen einwandfrei. Plötzlich aber........
schmiert mir der AVR bei einer neu eingebauten Funktion ab.
Nach langer Suche ohne erkennbaren Fehler habe ich ein Stackproblem 
lokalisiert. Habe Stück für Stück alles auskommentiert bis...

Um Euch nicht zu verwirren, habe ich allen auskommentierten Code 
weggelassen, und hier nur die 'abgestrippte' Routine mit dem Stackcheck 
gepostet.
1
      case 140:
2
        {
3
        uint16_t sv; // Stack vorher
4
        uint16_t sn; // Stack nachher
5
        uint16_t uiCounter=0;  
6
      
7
        sv=SP;  // Stackpointer vorher merken        
8
        
9
        // hier die EIGENTLICHE Funktion, ist aber auskommentiert
10
        
11
        sprintf_P(cString,PSTR("\n%d Zeichen gelesen"),uiCounter);
12
        LCD240_PutString (cString);
13
      
14
        sn=SP; // Stackpointer nachher merken
15
        
16
        sprintf_P (cString,PSTR("\nStackDiff: %d Byte"),sn-sv);
17
        LCD240_PutString (cString);
18
        }
19
      break;

So, und wenn der Kram Durchgelaufen ist erhalte ich auf meinem LCD die 
Meldung:
1
StackDiff: -6Byte

Deshalb schmiert die Kiste ab. Da DARF keine Differenz sein.
Was verbiegt mir hier den Stackpointer?
Irgendwelche Stack-Checker hier, die sowas mal gehabt haben?

Es liegt scheinbar an der sprintf_P Funktion, denn wenn ich die 
rausnehme und durch
1
        //sprintf_P(cString,PSTR("\n%d Zeichen gelesen"),uiCounter);
2
        strcpy(cString,"Test");
3
        LCD240_PutString (cString);
ersetze, kriege ich artig:
1
StackDiff: 0 Byte
1
LCD240_PutString
 scheidet also aus
sprintf_P wird aber sonst überall STÄNDIG verwendet und läuft prima.
nur in diesem
1
case 140:
 läufts nicht.
Das ist doch nicht normal, oder?
Bin ich blind oder brauche ich einen Exorzist?

Irgendwelche Anregungen für nen gehetzten Entwickler, was das sein 
könnte?

Gruß

Andi
~~~~

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Andreas Paulin wrote:

> Deshalb schmiert die Kiste ab. Da DARF keine Differenz sein.

Das kannst du mit dieser Bestimmtheit erst behaupten, wenn du dir
auch den generierten Assemblercode angesehen hast.  Es ist
durchaus nicht unüblich, das relativ aufwändige Aufräumen des
Stacks (man müsste ja 6 x POP aufrufen oder Verrenkungen mit dem
Stackpointer machen) bis zum Austritt aus der Funktion zu
verzögen.

Während die überwiegende Anzahl der Funktionsaufrufe beim AVR-GCC
die Parameter in Registern übergibt, geht das bei der printf-Familie
für die variable Parameterliste nicht, diese Parameter werden immer
auf dem Stack übergeben.  Damit ist diese Funktion natürlich ein
Kandidat, Stackprobleme sichtbar zu machen, die man sonst u. U. nicht
sieht.

von Andreas Paulin (Gast)


Lesenswert?

OK, thanks. Ist aber komischerweise nur in diesem 'case 140:' so.

Ich schmeiß mal ALLE Optimierungen raus, dann müsste es... 
vielleicht.... tbc....

von Michael D. (andromeda)


Lesenswert?

Em...

Was mir auffällt ist, dass Du den Funktionsaufruf durch den Aufruf von 
sprintf usw. ersetzt . Das halte ich, in dem Zusammenhang für nicht 
zielführend. Ich verstehe Dich so, das im normalen Code diese printfs 
nicht auftauchen. Das der Überlauf durch die hier auskommentierte 
Funktion erzeugt wird. Richtig?

Wie schon Jörg Wunsch schrieb sind unbalanzierte Stacks durchaus nicht 
wirklich ungewöhnlich. Auch eine Mögliche Nicht-Optimierung sollte daran 
im Prinzip nichts ändern. (Was nicht ausschliesst, das es in diesem Fall 
eine Veränderung bewirkt).

Die Frage wäre doch vielmehr, ob der Stack unmittelbar nach dem 
Funktionsaufruf unbalanziert ist. Das aber könnte man doch eher mit:
1
      case 140:
2
        {
3
        uint16_t sv; // Stack vorher
4
        uint16_t sn; // Stack nachher
5
        uint16_t uiCounter=0;  
6
      
7
        sv=SP;  // Stackpointer vorher merken        
8
        
9
        // hier die EIGENTLICHE Funktion, wieder reinnehmen
10
        sn=SP; // Stackpointer nachher merken
11
     
12
        sprintf_P(cString,PSTR("\n%d Zeichen gelesen"),uiCounter);
13
        LCD240_PutString (cString);
14
15
        sprintf_P (cString,PSTR("\nStackDiff: %d Byte"),sn-sv);
16
        LCD240_PutString (cString);
17
        }
18
      break;
herausfinden. Meinst Du nicht auch?

Das setzt aber voraus, das die Funktion keine variable Parameterliste 
hat.

Vielleicht hast Du das ja schon berücksichtigt, aber möglicherweise 
hilft Dir das doch weiter.

Gruss

von Andreas Paulin (Gast)


Lesenswert?

Also... ich hab die Optimierung rausgenommen, daraufhin
bekomme ich geliefert:
"StackDiff: 0 Byte"

Schön, aaaaaaaaaber, das wars nicht. Kiste schmiert immer noch ab. Jetzt 
wirds echt schwer.......
@ Michael D. (andromeda) :
Nein, ich habe die

"// hier die EIGENTLICHE Funktion, ist aber auskommentiert"

in meinem Problemkind WIRKLICH auskommentiert. Es geht echt nur um den 
geposteten Code. Das ist ja das Bescheuerte an der Sache....

@A. K. (prx):
Glaub nicht:
1
Data:       2204 bytes (53.8% Full)
2
(.data + .bss + .noinit)
Hab noch fast 2k frei....

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Andreas Paulin wrote:

> Also... ich hab die Optimierung rausgenommen, daraufhin
> bekomme ich geliefert:
> "StackDiff: 0 Byte"

Logisch, dann wird diese Optimierung ja auch nicht gemacht.

> Schön, aaaaaaaaaber, das wars nicht. Kiste schmiert immer noch ab.

Was zu befürchten war. :-/

Du benutzt nicht aus Versehen auch noch sprintf irgendwo in einer
ISR?  Kann sein, dass diese Funktionen irgendwo Fallen bezüglich
ihrer Reentranz haben könnten.

von Andreas Paulin (Gast)


Lesenswert?

@ Jörg: Nein, aber es passiert was anderes: Während diese Minifunktion 
läuft, bekommt mein System vom PC noch 100 Byte Testdaten via Bluetooth 
reingeschoben.
Das istn Mordsprotokoll und ständig klimpern die UART-Interrupts. 10 
Byte Overhead für ein Byte Nutzlast. Und DA hakts. Glaub ich. Wenn ich 
nämlich den PC NUR das Funktionstoken senden lasse, ohne die 100 
Testbytes (im Hintergrund) bleibt die Kiste STABIL!.

Schätze, ich war nicht schlecht (stackcheck), aber auf der falschen 
Spur. Es ist nicht der Stack, es ist irgendwo beim "ISR(USART1_RX_vect) 
" und seinen Ausläufern.......

Ich suche morgen weiter, mir fallen jetzt die Augen raus. Vielleicht 
muss ich einige Variable 'volatile' machen oder irgendsowas........ habe 
fertig.
Mittwoch ist Messe.... und nix geht mehr. 's war immer so....

Melde mich morgen wieder.
Jörg, Pirx, Andromeda, .....danke Euch mal.

von Andreas Paulin (Gast)


Lesenswert?

Also, wenn der Stack vor und nach einem Funktionsaufruf unausgeglichen 
ist, ist das schon ein Alarmsignal. Konnte ich nicht wissen, dass der 
Optimierer einem auch noch den Arsch wegoptimiert, wenn man nicht gerade 
draufsitzt *ggg

Aber es war wirklich kein Stackproblem, ganz anders.... das 
Handshakesignal für das Bluetooth-Modul hat sich verklemmt - Daraufhin 
war die Kiste SCHEINBAR tot.

Läuft soweit - Danke Euch mal recht herzlich!

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.