mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Stackprobleme Mega2560


Autor: Thomas Bergmüller (nichtessbar)
Datum:

Bewertung
0 lesenswert
nicht 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
while(1)
  {
    wdt_reset();

    // Eingänge invertieren, Achtung: ~ nur für 8 Bit!!
    cod_switch = 0;
    cod_buffer = 0;

    cod_buffer = ~PINL;
    cod_switch |= (WORD)(cod_buffer);

    cod_buffer = (~(PIND)) & 0x03;
    cod_switch |= (WORD)((cod_buffer)<<8);    
    
    DmxAddress = (uint16_t) cod_switch;        

    // DMX READOUT
    DmxProtokoll = DmxRxField[0];    // Modus / Symbolnummer

    color_t.red = DmxRxField[1];    
    color_t.green = DmxRxField[2];
    color_t.blue = DmxRxField[3];    

    color_b.red = DmxRxField[4];
    color_b.green = DmxRxField[5];
    color_b.blue = DmxRxField[6];

    white_calc(&color_b);
    white_calc(&color_t);        // Es werden RGB-Werte übermittelt, weiß herausgerechnet    
    
    // Dimmen wegen Wärme, Einstellungen siehe global.h
    rgbw_dimm(&color_b);
    rgbw_dimm(&color_t);


     for(m=0;m<WORKING_DELAY;m++)        // dem BUS ein bisschen erholzeit verschaffen
      for(n=0;n<WORKING_DELAY;n++);

    cli();  
      
    if(DmxProtokoll == 1) // code nummer 1, fixfarbe
    {
      for(c_address = 1; c_address <= 7; c_address++) 
      { 
        uart2_s_pro1(c_address); 
        for(c_pro2_delay = 0; c_pro2_delay < 200; c_pro2_delay++);        
      }
    }
    
    
    else if(DmxProtokoll == 2) // code nummer 2, farbverlauf
    {
      for(c_address = 1; c_address <= 7; c_address++) 
      { 
        uart2_s_pro2(c_address); 
        for(c_pro2_delay = 0; c_pro2_delay < 200; c_pro2_delay++);        
      }
    }

    else if(DmxProtokoll > 2 && DmxProtokoll < 39) // Zeichen
    {      
      uart2_s_pro3((BYTE)(DmxProtokoll-3));      
    }

    else // Karomuster, 0 und alle nicht genutzten Werte
    {      
      DmxAddress = DmxAddress;               // für Breakpoint setzen
      uart2_s_pro3(0x00); // Symbol für Karomuster      
    }

    sei();
  }


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

char uart2_s_pro3(BYTE symbolnr)
{
  volatile BYTE adr_count = 1;
  volatile WORD u2_count = 0;

  PORTB |= (1 << R_W_2);          // Auf senden umstellen
    
  for(adr_count = 1; adr_count <= 7; adr_count++)
  {
    while (!(UCSR2A & (1<<UDRE2))) {} 
    UDR2     = adr_count;            
    u2_crc_c    = adr_count;          // Zieladresse
    while (!(UCSR2A & (1<<UDRE2))) {} 
    UDR2     = 0x03;            
    u2_crc_c   ^= 0x03;            // Protkollnummer
    while (!(UCSR2A & (1<<UDRE2))) {} 
    UDR2     = color_t.red;
    u2_crc_c   ^= color_t.red;
    while (!(UCSR2A & (1<<UDRE2))) {} 
    UDR2     = color_t.green;
    u2_crc_c   ^= color_t.green;
    while (!(UCSR2A & (1<<UDRE2))) {} 
    UDR2     = color_t.blue;
    u2_crc_c   ^= color_t.blue;
    while (!(UCSR2A & (1<<UDRE2))) {} 
    UDR2     = color_t.white;
    u2_crc_c   ^= color_t.white;
    while (!(UCSR2A & (1<<UDRE2))) {} 
    UDR2     = color_b.red;
    u2_crc_c   ^= color_b.red;
    while (!(UCSR2A & (1<<UDRE2))) {} 
    UDR2     = color_b.green;
    u2_crc_c   ^= color_b.green;
    while (!(UCSR2A & (1<<UDRE2))) {} 
    UDR2     = color_b.blue;
    u2_crc_c   ^= color_b.blue;
    while (!(UCSR2A & (1<<UDRE2))) {} 
    UDR2     = color_b.white; 
    u2_crc_c   ^= color_b.white;

    while (!(UCSR2A & (1<<UDRE2))) {} 
    UDR2     = (BYTE) (symbol[symbolnr][adr_count-1]);
    u2_crc_c   ^= (BYTE) (symbol[symbolnr][adr_count-1]);
    while (!(UCSR2A & (1<<UDRE2))) {} 
    UDR2     = (BYTE) (symbol[symbolnr][adr_count-1] >> 8);
    u2_crc_c   ^= (BYTE) (symbol[symbolnr][adr_count-1] >> 8);
    while (!(UCSR2A & (1<<UDRE2))) {} 
    UDR2     = (BYTE) (symbol[symbolnr][adr_count-1] >> 16);
    u2_crc_c   ^= (BYTE) (symbol[symbolnr][adr_count-1] >> 16);

    while (!(UCSR2A & (1<<UDRE2))) {} 
    UDR2     = u2_crc_c;

    for(u2_count = 0; u2_count<200; u2_count++); // wait 200u
  } 
  
  return(0x02);
}

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

{

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



Im Disassemblerwindow sieht der Return-Teil so aus (13x pop?!)
:         for(adr_count = 1; adr_count <= 7; adr_count++)
+000002DA:   8189        LDD       R24,Y+1        Load indirect with displacement
+000002DB:   5F8F        SUBI      R24,0xFF       Subtract immediate
+000002DC:   8389        STD       Y+1,R24        Store indirect with displacement
+000002DD:   8189        LDD       R24,Y+1        Load indirect with displacement
+000002DE:   3088        CPI       R24,0x08       Compare with immediate
+000002DF:   F408        BRCC      PC+0x02        Branch if carry cleared
+000002E0:   CEF4        RJMP      PC-0x010B      Relative jump
144:      }
+000002E1:   E082        LDI       R24,0x02       Load immediate
+000002E2:   900F        POP       R0             Pop register from stack
+000002E3:   900F        POP       R0             Pop register from stack
+000002E4:   900F        POP       R0             Pop register from stack
+000002E5:   91CF        POP       R28            Pop register from stack
+000002E6:   91DF        POP       R29            Pop register from stack
+000002E7:   911F        POP       R17            Pop register from stack
+000002E8:   910F        POP       R16            Pop register from stack
+000002E9:   90FF        POP       R15            Pop register from stack
+000002EA:   90EF        POP       R14            Pop register from stack
+000002EB:   90DF        POP       R13            Pop register from stack
+000002EC:   90CF        POP       R12            Pop register from stack
+000002ED:   90BF        POP       R11            Pop register from stack
+000002EE:   90AF        POP       R10            Pop register from stack
+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

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Start der Funktion uart2_s_pro3(BYTE)

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

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

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

Autor: spess53 (Gast)
Datum:

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

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
  volatile BYTE adr_count = 1;
  volatile WORD u2_count = 0;

Das volatile für lokale Funktionsvariabeln macht normalreweise keinen 
Sinn, es sei denn man tut so gruselige Sachen wie:
 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.
+000002E2:   900F        POP       R0             Pop register from stack
+000002E3:   900F        POP       R0             Pop register from stack
+000002E4:   900F        POP       R0             Pop register from stack

Wieso?

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

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

Autor: Thomas Bergmüller (nichtessbar)
Datum:

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

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

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

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.