Forum: Mikrocontroller und Digitale Elektronik xmega verhält sich mit Debugger anders


von Jörg S. (Gast)


Lesenswert?

Hallo,

ich stehe gerade total auf dem Schlauch und brauche frische Ideen. Ich 
hoffe ihr könnt mir helfen:

Ich setze einen ATxmega64A4U (getaktet auf 64MHz) ein und nutze dort das 
SPI an Port C als Master (Teiler 128).
Ich sende nur Daten über MOSI heraus.
Ich musste ein paar Pins sparen und haben folgendes gemacht:
Den Pin MISO (PC6) betreibe ich permanent als Eingang, ändere aber mit 
Hilfe der Pullup/Pulldown-Widerstände den Logikpegel.
Den Pin SS an PC4 nutze ich als Ausgang für andere Geschichten. Der Pin 
ist permanent auf Output.

Als SPI-Treiber nutze ich die Atmel-Bibliothek "spi_driver".

Nun zum Problem: Mein Programm bleibt in der while-Schleife hängen, die 
abfragt ob alle bits das Datenregister verlassen haben. Das habe ich mit 
Hilfe einer LED an einem Ausgang festgestellt.
1
uint8_t SPI_MasterTransceiveByte(SPI_Master_t *spi, uint8_t TXdata)
2
{
3
  /* Send pattern. */
4
  spi->module->DATA = TXdata;
5
  
6
  /* Wait for transmission complete. */
7
  while(!(spi->module->STATUS & SPI_IF_bm)) {    // hier
8
9
  }
10
  /* Read received data. */
11
  uint8_t result = spi->module->DATA;
12
13
  return(result);
14
}

Jetzt aber der Witz an der Sache: Mein Programm läuft korrekt durch, 
soweit ich es mit dem Debugger (Atmel-ICE) gestartet habe. Es ist egal 
ob ich aktiv debugge oder es einfach nur darüber anschubse.
Es fällt mir schwer die Ursache zu finden, denn mit Debugger dran rennt 
das Programm einfach durch, wie ich es auch im Normalbetrieb erwarten 
würde.

Da ich annehme, dass der Master-Mode verloren geht, habe ich diesen vor 
dem Senden explizit nocheinmal gesetzt.
Jetzt läuft zwar das Programm auch ohne Debugger durch, aber es werden 
"falsche" oder keine Daten gesendet. Ich betreibe einen Stromregler 
TLC5922 dran, daher kann ich recht schnell auf dem Messgerät sehen, dass 
es nicht passt.

---

- Liegt es daran, dass ich die ungenutzten SPI Pins anderweitig 
verwende?
- Kennt von euch jemand das Phänomen, dass das Programm mit Debugger 
anders funktioniert als ohne? (Es liegt nicht Debug/Release Version)
- Oszi-Aufnahme habe ich nocht nicht. Wäre da etwas sinnvoll zu messen?


Ich bin für jeden Denkanstoß dankbar!

Viele Grüße,
Euer Jörg

von Curby23523 N. (Gast)


Lesenswert?

Jörg S. schrieb:
> Ich setze einen ATxmega64A4U (getaktet auf 64MHz)

Wie kriegst du das hin? Afaik kann der Xmega nur 32MHz, evtl. etwas mehr 
bei Übertaktung. Bitte korrigieren, wenn ich mich da irre.

von Sibbel (Gast)


Lesenswert?

Jörg S. schrieb:
> Mein Programm läuft korrekt durch,
> soweit ich es mit dem Debugger (Atmel-ICE) gestartet habe

Wie ist es denn, wenn der Debugger lediglich angeschlossen, aber nicht 
über die IDE in Betrieb ist? Also nur anschließen, aber dennoch den 
Controller selbst laufen lassen.

von J Zimmermann (Gast)


Lesenswert?

läuft das Programm, wenn Du den Controller mit 32MHz betreibst?
mfg

von Holger K. (holgerkraehe)


Lesenswert?


von Jörg S. (Gast)


Lesenswert?

Ich bin inzwischen doch mit dem Oszi ran gegangen und habe festgestellt, 
dass im Betrieb ohne Debugger einfach gar nichts gesendet wird. Kein 
SPI-Takt, nichts. Mir scheint es am Master-Mode zu liegen.



Curby23523 N. schrieb:
> Wie kriegst du das hin? Afaik kann der Xmega nur 32MHz

Ich habe extern einen 16MHz Quarz dran und den PLL auf 4.



Sibbel schrieb:
> Wie ist es denn, wenn der Debugger lediglich angeschlossen, aber nicht
> über die IDE in Betrieb ist? Also nur anschließen, aber dennoch den
> Controller selbst laufen lassen.

Dann läuft das Programm nicht. Es muss tatsächlich über den Debugger 
angestoßen werden, das reine "angeschlossen sein" ist es leider nicht.



J Zimmermann schrieb:
> läuft das Programm, wenn Du den Controller mit 32MHz betreibst?
> mfg

Nein, dann auch nicht.



Holger K. schrieb:
> Evtl hilft dies hier?
>
> Beitrag "atxmega RAM korrupt ohne debugger"
Ich schaue es mir an, danke.

von Volker B. (Firma: L-E-A) (vobs)


Lesenswert?

Jörg S. schrieb:

> uint8_t SPI_MasterTransceiveByte(SPI_Master_t *spi, uint8_t TXdata)

SPI_Master_t finde ich nicht in den avr-libc Headern. Wie ist das 
definiert?

> Ich habe extern einen 16MHz Quarz dran und den PLL auf 4.

Natürlich kann man das einstellen. Die Frage ist nur, was die MCU dann 
macht...?

Es gibt Peripherie-Module, die ein Vielfaches des MCU-Taktes benötigen. 
Deshalb lässt sich die PLL auf solche Frequenzen einstellen.

Grüßle
Volker

Nachtrag: OK, ich hab's überlesen:

> Als SPI-Treiber nutze ich die Atmel-Bibliothek "spi_driver".

Das wird dann wohl korrekt sein.

: Bearbeitet durch User
von Jörg S. (Gast)


Lesenswert?

Zwischendurch ein DANKE für euer Feedback!

Volker B. schrieb:
> Natürlich kann man das einstellen. Die Frage ist nur, was die MCU dann
> macht...?
>
> Es gibt Peripherie-Module, die ein Vielfaches des MCU-Taktes benötigen.
> Deshalb lässt sich die PLL auf solche Frequenzen einstellen.

Ja ok, mit meinen 64MHz bin ich natürlich nicht im sicheren 
Arbeitsbereich. Ich habe mal gelesen, dass es geht und ausprobiert. Bis 
jetzt kann ich sagen, dass es stabil läuft. Um aber auszuschließen, dass 
es daran liegt, betreibe ich den Spaß jetzt mit 32MHz (also 16MHz mit 
PLL auf 2). Ohne Erfolg, wie oben schon erwähnt.



Holger K. schrieb:
> Evtl hilft dies hier?
>
> Beitrag "atxmega RAM korrupt ohne debugger"

In dem Beitrag war das Problem, das zu wenig Stack vorhanden war. 
Tatsächlich traten die Probleme auf, nachdem ich mein Programm erweitert 
habe. Ich nahm aber an, dass der Zusammenhang anders ist. Ich versuche 
mich daran und berichte.

Falls aber jemand noch eine Idee, zögert nicht zu schreiben.

von Holger K. (holgerkraehe)


Lesenswert?

Ich hätte noch einen Vorschlag.

Selber erlebt bei meinem Programm.

Der Debugger initialisiert das SRAM mit "0".
Dadurch sind alle Variablen automatisch mit Null initialisiert, sollten 
diese nicht anderweitig initialisiert worden sein.

So hatte ich das Problem, das mit zunehmender Zeit in der die 
Stromzufuhr unterbrochen war auch mehr Probleme auftraten.

Abhilfe schaffte es, die Variablen korrekt zu initialisieren.
Ich nahm an, dass die Variablen automatisch auf null initialisiert 
werden.

von Jörg S. (Gast)


Lesenswert?

Danke für den Vorschlag. Ich habe überall versucht zu nullen, leider 
ohne Erfolg. Das heißt natürlich nicht, dass ich nicht irgendwo etwas 
vergessen habe.

Ich bin aber noch einen kleinen Schritt weiter: Per LED habe ich heraus 
bekommen, dass SCK nicht mehr Ausgang war. Als Workaround setze ich SCK 
in einer Routine vor dem Senden als Ausgang. Dass funktioniert dann auch 
ohne Debugger.

Es fragt sich natürlich trotzdem warum der SCK mit Debugger so bleibt 
wie initialisiert und ohne nicht?

Zufrieden bin ich also nicht, irgendwo ist noch der Wurm drin.

Gibt es eine Möglichkeit einen Stack-Overflow mit zu bekommen?

Viele Grüße,
Jörg

von Jörg S. (Gast)


Lesenswert?

Nach einigen Tagen debugging möchte ich mich nochmal für die 
konstruktive Hilfe bei allen bedanken: DANKE!

Für denn Fall, dass noch jemand ein ähnlich Problem hat, möchte ich 
kundtun wie ich aktuell Herr der Lage geworden bin. Anstoß war Holger's 
Post:


Holger K. schrieb:
> ...
> Der Debugger initialisiert das SRAM mit "0".
> Dadurch sind alle Variablen automatisch mit Null initialisiert, sollten
> diese nicht anderweitig initialisiert worden sein.
>
> So hatte ich das Problem, das mit zunehmender Zeit in der die
> Stromzufuhr unterbrochen war auch mehr Probleme auftraten.
>
> Abhilfe schaffte es, die Variablen korrekt zu initialisieren.
> Ich nahm an, dass die Variablen automatisch auf null initialisiert
> werden.


Ich denke zwar alle meine Variablen initialisiert zu haben, bin aber 
noch einen Schritt weiter gegangen. Mit Hilfe einer kleinen Funktion, 
basiert auf MichaelMcTernan's Stackmonitor setzte ich zu Beginn des 
Programms den kompletten SRAM auf 0x00. Michael war so freundlich seine 
Routinen frei zur Verfügung zu stellen, daher möchte ich hier meine 
Anpassungen posten:
1
#define STACK_DEFAULT 0x00
2
3
void ClearStackOnStartup(void) __attribute__ ((naked)) __attribute__ ((section (".init1")));
4
5
/** Fill the stack space with a known pattern.
6
 * This fills all stack bytes with the 'STACK_DEFAULT'
7
 * This runs in the .init1 section, before normal
8
 * stack initialisation and unfortunately before __zero_reg__ has been
9
 * setup.  The C code is therefore replaced with inline assembly to ensure
10
 * the zero reg is not used by compiled code.
11
 */
12
void ClearStackOnStartup(void)
13
{
14
#if 0
15
    uint8_t *p = INTERNAL_SRAM_START;
16
17
    while(p <= INTERNAL_SRAM_END)
18
    {
19
        *p = STACK_DEFAULT;
20
        p++;
21
    }
22
#else
23
    __asm volatile ("    ldi r30,lo8(_end)\n"
24
                    "    ldi r31,hi8(_end)\n"
25
                    "    ldi r24,lo8(0x00)\n" /* STACK_DEFAULT = 0x00 */
26
                    "    ldi r25,hi8(__stack)\n"
27
                    "    rjmp .cmp\n"
28
                    ".loop:\n"
29
                    "    st Z+,r24\n"
30
                    ".cmp:\n"
31
                    "    cpi r30,lo8(__stack)\n"
32
                    "    cpc r31,r25\n"
33
                    "    brlo .loop\n"
34
                    "    breq .loop"::);
35
#endif
36
}

Die Funktion muss nicht aufgerufen werden, sie wird durch die Attribute 
vom Compiler in das assembler-file integriert.

Viele Grüße,
Euer Jörg

von Jörg S. (Gast)


Lesenswert?

Hoppla, Korrektur:

nicht der gesamte SRAM, sondern der Teil zwischen ersten ungenutzten 
RAM-Adresse bis zum Stack-Ende

Es fehlt noch dieser Teil:
1
/** Gain access to linker symbol for end of variable section.
2
 * This symbol is defined to be the address of the first unused byte of SRAM.
3
 * The stack is by convention at the top of the SRAM, growing down towards
4
 * the address at which this variable resides.
5
 */
6
extern uint8_t _end;
7
8
/** Gain access to linker symbol for base of the stack.
9
 * This symbol is defined to be the address at the bootom of the stack.
10
 */
11
extern uint8_t __stack;

So sieht es dann aus:
1
#include <stdint.h>
2
3
#define STACK_DEFAULT 0x00
4
5
/**************************************************************************
6
 * Variables
7
 **************************************************************************/
8
9
/** Gain access to linker symbol for end of variable section.
10
 * This symbol is defined to be the address of the first unused byte of SRAM.
11
 * The stack is by convention at the top of the SRAM, growing down towards
12
 * the address at which this variable resides.
13
 */
14
extern uint8_t _end;
15
16
/** Gain access to linker symbol for base of the stack.
17
 * This symbol is defined to be the address at the bootom of the stack.
18
 */
19
extern uint8_t __stack;
20
21
/**************************************************************************
22
 * Local Functions
23
 **************************************************************************/
24
25
void ClearStackOnStartup(void) __attribute__ ((naked)) __attribute__ ((section (".init1")));
26
27
/** Fill the stack space with a known pattern.
28
 * This fills all stack bytes with the 'STACK_DEFAULT'
29
 * This runs in the .init1 section, before normal
30
 * stack initialisation and unfortunately before __zero_reg__ has been
31
 * setup.  The C code is therefore replaced with inline assembly to ensure
32
 * the zero reg is not used by compiled code.
33
 *
34
 * \note This relies on the linker defining \a _end and \a __stack to define
35
 *        the bottom of the stack (\a __stack) and the top most address
36
 *        (\a _end).
37
 */
38
void ClearStackOnStartup(void)
39
{
40
#if 0
41
    uint8_t *p = INTERNAL_SRAM_START;
42
43
    while(p <= INTERNAL_SRAM_END)
44
    {
45
        *p = STACK_DEFAULT;
46
        p++;
47
    }
48
#else
49
    __asm volatile ("    ldi r30,lo8(_end)\n"
50
                    "    ldi r31,hi8(_end)\n"
51
                    "    ldi r24,lo8(0x00)\n" /* STACK_DEFAULT = 0x00 */
52
                    "    ldi r25,hi8(__stack)\n"
53
                    "    rjmp .cmp\n"
54
                    ".loop:\n"
55
                    "    st Z+,r24\n"
56
                    ".cmp:\n"
57
                    "    cpi r30,lo8(__stack)\n"
58
                    "    cpc r31,r25\n"
59
                    "    brlo .loop\n"
60
                    "    breq .loop"::);
61
#endif
62
}

von Oliver S. (oliverso)


Lesenswert?

Jörg S. schrieb:
> Ich denke zwar alle meine Variablen initialisiert zu haben, bin aber
> noch einen Schritt weiter gegangen. Mit Hilfe einer kleinen Funktion,
> basiert auf MichaelMcTernan's Stackmonitor setzte ich zu Beginn des
> Programms den kompletten SRAM auf 0x00

Wenn dein Programm ohne das Nullen nicht funktioniert, enthält es also 
nach wie vor Programmfehler, die du mit der Aktion kaschierst. Kann man 
so machen, ist aber nur der halbe Weg.

Oliver

von Jörg S. (Gast)


Lesenswert?

Oliver S. schrieb:
> Wenn dein Programm ohne das Nullen nicht funktioniert, enthält es also
> nach wie vor Programmfehler, die du mit der Aktion kaschierst. Kann man
> so machen, ist aber nur der halbe Weg.
>
> Oliver

Ja da hast du leider recht. Ich suche auch weiter :-)

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.