Forum: Mikrocontroller und Digitale Elektronik Stackprobleme Mega2560


von Thomas B. (nichtessbar)


Lesenswert?

Hallo,

bin mittlerweile nahezu am verzweifeln und bräuchte bitte dringend ein 
nicht vorbelastetes Auge, ich hoffe ihr könnt mir helfen.

Ich habe einen simplen Funktionsaufruf aus der main() in eine andere 
Funktion in einer anderen Datei des Projekts.

Es handelt sich um die uart2_s_pro3(unsigned char), uart2_s_pro1 und 
uart2_s_pro2 funktionieren tadellos.

Per Debugging habe ich festgestellt, dass die Funktion richtig 
abgearbeitet wird (auch die Hardware reagiert richtig) aber anstatt beim 
return an die richtige Adresse zurückzuspringen landet der uC im leeren 
Speicherbereich.

main.c, Endlosschleife
1
while(1)
2
  {
3
    wdt_reset();
4
5
    // Eingänge invertieren, Achtung: ~ nur für 8 Bit!!
6
    cod_switch = 0;
7
    cod_buffer = 0;
8
9
    cod_buffer = ~PINL;
10
    cod_switch |= (WORD)(cod_buffer);
11
12
    cod_buffer = (~(PIND)) & 0x03;
13
    cod_switch |= (WORD)((cod_buffer)<<8);    
14
    
15
    DmxAddress = (uint16_t) cod_switch;        
16
17
    // DMX READOUT
18
    DmxProtokoll = DmxRxField[0];    // Modus / Symbolnummer
19
20
    color_t.red = DmxRxField[1];    
21
    color_t.green = DmxRxField[2];
22
    color_t.blue = DmxRxField[3];    
23
24
    color_b.red = DmxRxField[4];
25
    color_b.green = DmxRxField[5];
26
    color_b.blue = DmxRxField[6];
27
28
    white_calc(&color_b);
29
    white_calc(&color_t);        // Es werden RGB-Werte übermittelt, weiß herausgerechnet    
30
    
31
    // Dimmen wegen Wärme, Einstellungen siehe global.h
32
    rgbw_dimm(&color_b);
33
    rgbw_dimm(&color_t);
34
35
36
     for(m=0;m<WORKING_DELAY;m++)        // dem BUS ein bisschen erholzeit verschaffen
37
      for(n=0;n<WORKING_DELAY;n++);
38
39
    cli();  
40
      
41
    if(DmxProtokoll == 1) // code nummer 1, fixfarbe
42
    {
43
      for(c_address = 1; c_address <= 7; c_address++) 
44
      { 
45
        uart2_s_pro1(c_address); 
46
        for(c_pro2_delay = 0; c_pro2_delay < 200; c_pro2_delay++);        
47
      }
48
    }
49
    
50
    
51
    else if(DmxProtokoll == 2) // code nummer 2, farbverlauf
52
    {
53
      for(c_address = 1; c_address <= 7; c_address++) 
54
      { 
55
        uart2_s_pro2(c_address); 
56
        for(c_pro2_delay = 0; c_pro2_delay < 200; c_pro2_delay++);        
57
      }
58
    }
59
60
    else if(DmxProtokoll > 2 && DmxProtokoll < 39) // Zeichen
61
    {      
62
      uart2_s_pro3((BYTE)(DmxProtokoll-3));      
63
    }
64
65
    else // Karomuster, 0 und alle nicht genutzten Werte
66
    {      
67
      DmxAddress = DmxAddress;               // für Breakpoint setzen
68
      uart2_s_pro3(0x00); // Symbol für Karomuster      
69
    }
70
71
    sei();
72
  }

Erklärung: per Dmx werden Steuerbytes eingelesen und entsprechend 
ovrgegangen. Protokoll 1 + 2 funktioniert tadellos, nur beim Protokoll 3 
habe ich das Problem dass beim Return vom Stack offensichtlich alles 
andere nur nicht die Rücksprungadresse gepoppt wird.

Sendefunktion
uart2.c
1
char uart2_s_pro3(BYTE symbolnr)
2
{
3
  volatile BYTE adr_count = 1;
4
  volatile WORD u2_count = 0;
5
6
  PORTB |= (1 << R_W_2);          // Auf senden umstellen
7
    
8
  for(adr_count = 1; adr_count <= 7; adr_count++)
9
  {
10
    while (!(UCSR2A & (1<<UDRE2))) {} 
11
    UDR2     = adr_count;            
12
    u2_crc_c    = adr_count;          // Zieladresse
13
    while (!(UCSR2A & (1<<UDRE2))) {} 
14
    UDR2     = 0x03;            
15
    u2_crc_c   ^= 0x03;            // Protkollnummer
16
    while (!(UCSR2A & (1<<UDRE2))) {} 
17
    UDR2     = color_t.red;
18
    u2_crc_c   ^= color_t.red;
19
    while (!(UCSR2A & (1<<UDRE2))) {} 
20
    UDR2     = color_t.green;
21
    u2_crc_c   ^= color_t.green;
22
    while (!(UCSR2A & (1<<UDRE2))) {} 
23
    UDR2     = color_t.blue;
24
    u2_crc_c   ^= color_t.blue;
25
    while (!(UCSR2A & (1<<UDRE2))) {} 
26
    UDR2     = color_t.white;
27
    u2_crc_c   ^= color_t.white;
28
    while (!(UCSR2A & (1<<UDRE2))) {} 
29
    UDR2     = color_b.red;
30
    u2_crc_c   ^= color_b.red;
31
    while (!(UCSR2A & (1<<UDRE2))) {} 
32
    UDR2     = color_b.green;
33
    u2_crc_c   ^= color_b.green;
34
    while (!(UCSR2A & (1<<UDRE2))) {} 
35
    UDR2     = color_b.blue;
36
    u2_crc_c   ^= color_b.blue;
37
    while (!(UCSR2A & (1<<UDRE2))) {} 
38
    UDR2     = color_b.white; 
39
    u2_crc_c   ^= color_b.white;
40
41
    while (!(UCSR2A & (1<<UDRE2))) {} 
42
    UDR2     = (BYTE) (symbol[symbolnr][adr_count-1]);
43
    u2_crc_c   ^= (BYTE) (symbol[symbolnr][adr_count-1]);
44
    while (!(UCSR2A & (1<<UDRE2))) {} 
45
    UDR2     = (BYTE) (symbol[symbolnr][adr_count-1] >> 8);
46
    u2_crc_c   ^= (BYTE) (symbol[symbolnr][adr_count-1] >> 8);
47
    while (!(UCSR2A & (1<<UDRE2))) {} 
48
    UDR2     = (BYTE) (symbol[symbolnr][adr_count-1] >> 16);
49
    u2_crc_c   ^= (BYTE) (symbol[symbolnr][adr_count-1] >> 16);
50
51
    while (!(UCSR2A & (1<<UDRE2))) {} 
52
    UDR2     = u2_crc_c;
53
54
    for(u2_count = 0; u2_count<200; u2_count++); // wait 200u
55
  } 
56
  
57
  return(0x02);
58
}

Unterprogrammaufruf Disassemblerwindow:
1
289:            DmxAddress = DmxAddress;               // für Breakpoint setzen
2
+0000062C:   91800614    LDS       R24,0x0614     Load direct from data space
3
+0000062E:   91900615    LDS       R25,0x0615     Load direct from data space
4
+00000630:   93900615    STS       0x0615,R25     Store direct to data space
5
+00000632:   93800614    STS       0x0614,R24     Store direct to data space
6
290:            uart2_s_pro3(0x00); // Symbol für Karomuster      
7
+00000634:   E080        LDI       R24,0x00       Load immediate
8
+00000635:   940E01A4    CALL      0x000001A4     Call subroutine
9
293:          sei();
10
11
{

Start der Funktion uart2_s_pro3(BYTE). 10xpush
1
+000001A4:   92AF        PUSH      R10            Push register on stack
2
+000001A5:   92BF        PUSH      R11            Push register on stack
3
+000001A6:   92CF        PUSH      R12            Push register on stack
4
+000001A7:   92DF        PUSH      R13            Push register on stack
5
+000001A8:   92EF        PUSH      R14            Push register on stack
6
+000001A9:   92FF        PUSH      R15            Push register on stack
7
+000001AA:   930F        PUSH      R16            Push register on stack
8
+000001AB:   931F        PUSH      R17            Push register on stack
9
+000001AC:   93DF        PUSH      R29            Push register on stack
10
+000001AD:   93CF        PUSH      R28            Push register on stack



Im Disassemblerwindow sieht der Return-Teil so aus (13x pop?!)
1
:         for(adr_count = 1; adr_count <= 7; adr_count++)
2
+000002DA:   8189        LDD       R24,Y+1        Load indirect with displacement
3
+000002DB:   5F8F        SUBI      R24,0xFF       Subtract immediate
4
+000002DC:   8389        STD       Y+1,R24        Store indirect with displacement
5
+000002DD:   8189        LDD       R24,Y+1        Load indirect with displacement
6
+000002DE:   3088        CPI       R24,0x08       Compare with immediate
7
+000002DF:   F408        BRCC      PC+0x02        Branch if carry cleared
8
+000002E0:   CEF4        RJMP      PC-0x010B      Relative jump
9
144:      }
10
+000002E1:   E082        LDI       R24,0x02       Load immediate
11
+000002E2:   900F        POP       R0             Pop register from stack
12
+000002E3:   900F        POP       R0             Pop register from stack
13
+000002E4:   900F        POP       R0             Pop register from stack
14
+000002E5:   91CF        POP       R28            Pop register from stack
15
+000002E6:   91DF        POP       R29            Pop register from stack
16
+000002E7:   911F        POP       R17            Pop register from stack
17
+000002E8:   910F        POP       R16            Pop register from stack
18
+000002E9:   90FF        POP       R15            Pop register from stack
19
+000002EA:   90EF        POP       R14            Pop register from stack
20
+000002EB:   90DF        POP       R13            Pop register from stack
21
+000002EC:   90CF        POP       R12            Pop register from stack
22
+000002ED:   90BF        POP       R11            Pop register from stack
23
+000002EE:   90AF        POP       R10            Pop register from stack
24
+000002EF:   9508        RET                      Subroutine return



Diverse Optimierungsparameter hab ich durchprobiert, immer das selbe 
Problem. Auffällig ist, dass der Stackpointer zum Zeitpunkt des 
Programmaufrufs bei 0x21F0 ist. Ziemlich hoch oder?


Hat jemand eine Ahnung?

Danke
Thomas

von Stefan E. (sternst)


Lesenswert?

> Start der Funktion uart2_s_pro3(BYTE)

Aber sicher nicht der komplette Start. Was kommt nach dem "PUSH 28"? 
Vielleicht ein RCALL?

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


Lesenswert?

Thomas Bergmüller schrieb:
> Auffällig ist, dass der Stackpointer zum Zeitpunkt des
> Programmaufrufs bei 0x21F0 ist. Ziemlich hoch oder?

Nein, völlig in Ordnung.  Der interne SRAM geht bis 0x21FF, und
der Stackpointer wird folglich darauf initialisiert.  Ein
paar Byte sind also bereits auf dem Stack, aber nicht viel.

Mit welchen genauen Kommandos hast du denn den Linker angeworfen?

von spess53 (Gast)


Lesenswert?

Hi

>Auffällig ist, dass der Stackpointer zum Zeitpunkt des
>Programmaufrufs bei 0x21F0 ist. Ziemlich hoch oder?

Der Stack startet normalerweise bei $21FF und wächst nach unten. Also 
befinden sich gerade mal 15 Bytes auf dem Stack.

MfG Spess

von Peter (Gast)


Lesenswert?

1
  volatile BYTE adr_count = 1;
2
  volatile WORD u2_count = 0;

Das volatile für lokale Funktionsvariabeln macht normalreweise keinen 
Sinn, es sei denn man tut so gruselige Sachen wie:
1
 for(u2_count = 0; u2_count<200; u2_count++); // wait 200u

=> Benutze lieber die _delay_us() Funktion der AVR-Lib und lass dafür 
das volatile weg. (Auch wenn es vermutlich nicht die Ursache für Dein 
Problem ist.
1
+000002E2:   900F        POP       R0             Pop register from stack
2
+000002E3:   900F        POP       R0             Pop register from stack
3
+000002E4:   900F        POP       R0             Pop register from stack

Wieso?

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


Lesenswert?

Btw., statt des blöden AVR-Studio-Disassemblers (warum muss man
13x "Pop register from stack" neben die POP-Befehle als
Kommentar schreiben?), gib uns lieber compilierbaren Sourcecode.
Ich schau mir persönlich ohnehin viel lieber den generierten
Assemblercode statt dieses Disassembler-Gewurschtels an.

von Thomas B. (nichtessbar)


Lesenswert?

Peter schrieb:
> Wieso?

AVR-GCC ;)


hmpf... Sorry für eure verschwendete Zeit.. Man sollte wenn man am 2560 
programmiert nicht als Gerät den Atmega1280 bei den Projektoptionen 
(AVR-Studio) ausgewählt haben.

Faszinierend dass die gesamte restliche Software - auf den falschen 
Prozessor compiliert - funktionierte. Scheint intern wohl bis auf die 
Speichergröße der Großteil gleich aufgebaut zu sein...

Danke jedenfalls für die Anmerkungen, und ja, die delay-funktionen 
kommen noch. Hab da nur immer meine liebe Not wenn vor dem entgültigem 
Produkt der Quarz gewechselt wird und ich dann bei einigen delays über 
den Bereich des Makros hinauskomme - gibt keine Fehlermeldung und 
nichts, tut was es will. Und bei größeren Projekten übersieht man das 
leicht, hab mir angewohnt alles mit Schleifen zu machen und wenn die 
Software fertig ist, jede dieser Schleifen durch das entsprechende Delay 
zu ersetzen ;) Vielleicht nicht der beste Workflow aber ich hab mich 
dran gewöhnt und überseh so viel weniger.

hm... wegem dem Stack: Ich muss zugeben dass ich das letzte mal 
Assembler auf dem 8051 programmiert habe, und da wächst der Stack hinter 
den Registerbänken hoch wenn ich mich nicht irre... Leider / zum Glück 
hab ich bis dato am AVR fast alles in C geschrieben und somit mit Stack 
 PC  ... relativ wenig zu tun gehabt

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


Lesenswert?

Thomas Bergmüller schrieb:

> Faszinierend dass die gesamte restliche Software - auf den falschen
> Prozessor compiliert - funktionierte. Scheint intern wohl bis auf die
> Speichergröße der Großteil gleich aufgebaut zu sein...

Insbesondere bedingt die Speichergröße einen 3-Byte-PC beim
ATmega2560.  Ja, ansonsten sind die sehr ähnlich.

> ... und ich dann bei einigen delays über
> den Bereich des Makros hinauskomme - gibt keine Fehlermeldung und
> nichts, tut was es will.

Tut schon seit 2 Jahren (oder so) was es soll, nur nicht so genau.

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.