Forum: Mikrocontroller und Digitale Elektronik Problem mit Arrayübergabe an Funktion


von André W. (sefiroth)


Lesenswert?

Hallo,

ich habe hier ein Problem mit einer Arrayübergabe an eine Funktion. Ich 
habe im Hauptprogramm ein globales Array. Die Funktion soll via SPI aus 
einem Flashspeicher byteweise Daten auslesen und in besagtem Array 
ablegen.

Das (für mich) mysteriöse: Bis zu 20 Byte werden problemlos ausgelesen 
und gespeichert. Ab 200 Byte stürzt der Controller ab :-) Er startet 
dann einfach neu...
1
// Defines
2
#define FM_SPI_CHIP_SELECT()      { FM_CS_PORT &= ~_BV(FM_CS_PIN); }
3
#define FM_SPI_CHIP_RELEASE()      { FM_CS_PORT |= _BV(FM_CS_PIN); }
4
#define FM_SPI_WAIT_FOR_READY()      { while(!(SPSR & (1<<SPIF))) { NOP(); } } // Warten bis Übertragung abgeschlossen
5
#define FM_SPI_SEND_BYTE(byte)      { SPDR = byte; FM_SPI_WAIT_FOR_READY(); } // Überträgt ein Byte und wartet bis die Übertragung abgeschlossen ist
6
7
8
// Globale Variablen
9
volatile uint8_t u8_TempData[260];
10
11
12
// Funktion
13
uint8_t flashmem_read_block(uint32_t u32_Adress, volatile uint8_t *u8_Datablock, uint16_t u16_Length)
14
{
15
  
16
  flashmem_wait_for_ready();
17
18
  // CMD: Byte/Page Program
19
  FM_SPI_CHIP_SELECT();
20
21
  FM_SPI_SEND_BYTE(FM_OPCODE_READ_ARRAY);        // OPCODE
22
  FM_SPI_SEND_BYTE( (u32_Adress >> 16) & 0xFF );    // Adresse A16-A23
23
  FM_SPI_SEND_BYTE( (u32_Adress >> 8) & 0xFF );    // Adresse A8-A15
24
  FM_SPI_SEND_BYTE( u32_Adress & 0xFF );        // Adresse A0-A7
25
26
  for (uint16_t u16_Position = 0; u16_Position < u16_Length ; u16_Position++ )
27
  {
28
    FM_SPI_SEND_BYTE(0x00);        // Dummy-Byte
29
    
30
31
    *u8_Datablock = SPDR;        // Response
32
33
    u8_Datablock++;              // Zeiger auf nächstes Byte im Array
34
  }
35
36
  FM_SPI_CHIP_RELEASE();
37
38
  return 0;
39
}
40
41
42
// Hauptprogramm
43
int main (void)
44
{
45
   // Inits rausgekürzt...   
46
47
   while (1)
48
   {
49
     flashmem_read_block(0x000000, u8_TempData, 256);
50
   }        
51
}
52
53
// C-Code ist für die Lesbarkeit gekürzt!
54
// Controler: AT90CAN128 @ 16 MHz

Der Flash-Speicher gibt mir als Antwort auf ein Dummy-Byte immer das 
gelesene Datenbyte zurück und erhöht intern automatisch die Leseadresse 
um 1 Byte. Die empfangenen Bytes möchte ich im übergebenen Array 
speichern, um damit später im Hauptprogramm zu arbeiten.

Es gibt noch eine Funktion, die in den Speicher schreiben soll, die 
eigentlich genau wie die die Lese-Funktion aufgebaut ist - nur dass sie 
nichts ins Array schreibt. Diese macht überhaupt keine Probleme - egal 
wieviele Byte sie verarbeiten soll...

Es würde mich sehr freuen, wenn Ihr mir erklären könnt, was hier 
passiert.

Vielen Dank schonmal!

Gruß,
André

PS: Pointer sind nur solange schön, wie sie funktionieren... ;-)

von Uwe (de0508)


Lesenswert?

Nur als Tipp, wo übergibst du einen Zeiger auf das Feld |u8_TempData| ?

von Thomas (Gast)


Lesenswert?

Einzige Vermutung: Ist Dein Data-Block im Linkerfile groß genug 
definiert?

von André W. (sefiroth)


Lesenswert?

Uwe S. schrieb:
> Nur als Tipp, wo übergibst du einen Zeiger auf das Feld |u8_TempData| ?

u8_TempData ist doch ein Array. Lasse ich die Klammern weg, müsste es 
doch automatisch als Zeiger auf das erste Byte verwendet werden. 
Schreibe ich &u8_TempData[0] tritt das Problem genauso auf.


Thomas schrieb:
> Einzige Vermutung: Ist Dein Data-Block im Linkerfile groß genug
> definiert?

Hmm, gute Frage. Bin mir nicht sicher wo ich das bei AVR Studio 5 
einstellen kann (war bisher noch nie notwendig). Nach dem 
Compilieren/Linken bekomme ich die Meldung:
1
AVR Memory Usage
2
----------------
3
Device: at90can128
4
Program:   21318 bytes (16.3% Full)
5
(.text + .data + .bootloader)
6
Data:       3033 bytes (74.0% Full)
7
(.data + .bss + .noinit)

von bhallinger (Gast)


Lesenswert?

Das mit Übergeben des Zeigers auf Arry und einfach weglassen der Klammer 
ist eigentlich korrekt macht aber ab und an Probleme...
Ich löse es so: &(arrary[0])

von Dosmo (Gast)


Lesenswert?

Doofe Frage: Watchdog bedient?

von André W. (sefiroth)


Lesenswert?

Dosmo schrieb:
> Doofe Frage: Watchdog bedient?

Der Watchdog wird nicht verwendet und ist deaktiviert.

Ich vermute, dass die Funktion die ausgelesenen Daten irgendwo 
speichert, wo sie nichts zu suchen haben und dadurch das Programm nach 
(oder während) der Speicherung keine Befehle oder korrekte 
Sprungadressen/Stackdaten mehr findet und ins Nirwana läuft. Dann wird 
sie wahrscheinlich irgendwann beim Reset-Vektor ankommen und so das 
Steuergerät "neu starten". Aber das ist mehr ins Blaue geraten :-(

Leider kann ich das Programm nicht zur Laufzeit debuggen...

von Karl H. (kbuchegg)


Lesenswert?

C mässig ist an dem Codefetzen nichts auszusetzen.

Also musst du am drumherum suchen
* richtiger Prozessor eingestellt
* Hast du Dinge, die zur Laufzeit exzessiv Stack verbrauchen
  (zb in main viele lokale Variablen)
  so dass die 74% SRAM-Verbrauch signifikant zur Laufzeit
  überschritten werden?

von André W. (sefiroth)


Lesenswert?

Karl Heinz Buchegger schrieb:
> C mässig ist an dem Codefetzen nichts auszusetzen.
>
> Also musst du am drumherum suchen
> * richtiger Prozessor eingestellt
> * Hast du Dinge, die zur Laufzeit exzessiv Stack verbrauchen
>   (zb in main viele lokale Variablen)
>   so dass die 74% SRAM-Verbrauch signifikant zur Laufzeit
>   überschritten werden?

Der Prozessor ist im AVR Studio richtig eingestellt. An lokalen 
Variablen habe ich nur ab und zu mal eine kleine Zählvariable in den 
üblichen for-Schleifen. Aber selbst wenn die alle gleichzeitig genutzt 
werden würden, käme ich da zusammen auf nicht mehr als 100 Byte (eher 
wesentlich weniger)... Und die verbleibenden 26% sind gut 1000 Byte.

Ich habe eben etwas merkwürdiges festgestellt: Wenn ich das Arry nicht 
global anlege, sondern lokal in der main (vor der while(1)-Schleife), 
stürzt der Controller beim Ausführen der Funktion nicht ab. Es wird 
immer seltsamer...

von Karl H. (kbuchegg)


Lesenswert?

André Wippich schrieb:

> Ich habe eben etwas merkwürdiges festgestellt: Wenn ich das Arry nicht
> global anlege, sondern lokal in der main (vor der while(1)-Schleife),
> stürzt der Controller beim Ausführen der Funktion nicht ab. Es wird
> immer seltsamer...


Es liegt dann an einer anderen Stelle im Speicher und du überschreibst 
halt irgendwas anderes im Speicher, was für das Programm nicht so vital 
ist, wie die Rückkehradresse der Funktion nach main().

-> Variablen im Speicher rumschieben bringt nichts. Die Dinge sind dann 
nur im Speicher anders angeordnet und unter Umständen verlagert sich 
dadurch der Fehler nur an eine andere Stelle. Aber auch wenn man den 
Fehler nicht mehr sieht, ist er immer noch vorhanden. Die Devise lautet: 
Die Ursache bekämpfen, nicht die Symptome.

Hilft nichts: Ganzes Programm muss her.
Wenn du nett bist, speckst du das Programm ab, so dass alles was zur 
Reproduzierbarkeit des Fehlers nicht notwendig ist rausfliegt, 
überprüfst nochmal ob sich der Fehler auch wirklich noch zeigt und 
postest das Minimalprogramm.

von André W. (sefiroth)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Hilft nichts: Ganzes Programm muss her.
> Wenn du nett bist, speckst du das Programm ab, so dass alles was zur
> Reproduzierbarkeit des Fehlers nicht notwendig ist rausfliegt,
> überprüfst nochmal ob sich der Fehler auch wirklich noch zeigt und
> postest das Minimalprogramm.

Das mache ich - schaffe es aber wahrscheinlich erst nächste Woche :-(

Dem Zeitdruck geschuldet habe ich das Programm jetzt so umgeschrieben, 
dass die Funktion direkt auf ein globales Array zugreift und jeden 
Pointer rausgeschmissen. So funktioniert es zumindest, auch wenn es 
nicht so richtig elegant ist...

So oder so möchte ich aber rausfinden was im Originalprogramm vor sich 
geht. Nächste Woche kann ich es vielleicht auch mal auf ein STK600 
flashen und mittels JTAG debuggen.

Ich möchte Euch aber schon jetzt für die vielen Antworten und die 
Hilfestellung danken!

Ein schönes WE wünsche ich!

von André W. (sefiroth)


Lesenswert?

Ich kann mit neuen Informationen aufwarten! Glücklicherweise konnte ich 
mich doch schon jetzt dransetzen und den Code debuggen, da mein Kollege 
einen Debugger in der Schublade hatte und sich die Zeit zum Testen ergab 
:-)

Witzigerweise funktionierte das Programm beim Debuggen problemlos - 
keinerlei Abstürze oder Fehlverhalten...

Ich habe dann folgendes probiert: AVR Studio 5 erzeugt ja verschiedene 
HEX-Dateien je nach Anwendungsfall. Eine HEX im Debug Ordner und eine 
HEX im Release Ordner, die jeweils mit einer eigenen Konfiguration 
erzeugt werden. Als ich die Release-HEX nochmal draufgespielt habe hing 
sich das Programm wie gewohnt auf. Mit dem Debug-HEX lief es problemlos. 
So weit so gut :-)

Ich habe dann die Compilier und Linker Optionen im AVR Studio 5 für 
beide Fälle angeschaut und tatsächlich gab es beim Linker eine 
Abweichung.

Linker-Debug-Configuration:
1
-Wl,-Map="$(OutputFileName).map" -Wl,-lm   -mmcu=($DEVICE) ($MEMORY_SETTINGS)

Linker-Release-Configuration:
1
-Wl,-Map="$(OutputFileName).map" -Wl,-lm  -Wl,--defsym=__stack=0x400  -mmcu=($DEVICE) ($MEMORY_SETTINGS)

Bei der Release-Config setzt AVR-Studio den Stack auf die Adresse 
0x0400. Und ratet mal wo mein u8_TempData-Array laut Debugger im 
Speicher liegt - im Adressbereich 0x0387 bis 0x048A. D.h. die Funktion 
schreibt programmgemäß Daten ins Array, nur leider überschneidet sich 
das ab der 121. Speicherstelle mit dem Stack. Dann ist es kein Wunder 
wenn das Programm durchdreht.

Weiß jemand warum AVR Studio 5 diese Stack-Einstellung vornimmt und ob 
sie notwendig ist? Ich habe sie definitv nicht dort eingetragen! Leider 
kenne ich mich mit der Speicher-Konfiguration für den Linker nicht aus 
und weiß nicht wie ich das Problem am Besten umgehen kann. Ich habe 
einfach mal den "-Wl,--defsym=__stack=0x400" Teil gelöscht und schon 
läuft das Programm mit der Release-Config (scheinbar) problemlos. Es 
stürzt nicht mehr ab :-)

Ich befürchte nur, mir durch das Ändern der Stack-Geschichte andere 
Fehler einzufangen. Wie gesagt: Ich weiß an der Stelle nicht so recht 
was ich damit beim Linker anrichte...

Gruß,
André

von André W. (sefiroth)


Lesenswert?

Hmm, schade dass keiner mehr antwortet.

Ich habe leider nicht mal bei Google was zum AVR Studio 5 Linker bzw. 
dessen Optionen finden können, um mir dessen Verhalten zu erklären. 
Kennt evtl. jemand eine Website, die sich mit dem Thema beschäftigt?

Gruß,
André

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

André Wippich schrieb:
> Linker-Release-Configuration:
1
-Wl,-Map="$(OutputFileName).map" -Wl,-lm  -Wl,--defsym=__stack=0x400  -mmcu=($DEVICE) ($MEMORY_SETTINGS)
> Bei der Release-Config setzt AVR-Studio den Stack auf die Adresse
> 0x0400.

Und was geschieht, wenn Du genau die Stackdefinition dort weglässt, also 
auf "--defsym=__stack=0x400" verzichtest?

von André W. (sefiroth)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Und was geschieht, wenn Du genau die Stackdefinition dort weglässt, also
> auf "--defsym=__stack=0x400" verzichtest?

Dann funktioniert das Programm. Allerdings weiß ich nicht, ob ich mir 
damit nicht einen Fehler an anderer Stelle einhandle, der dann 
sporadisch auftreten könnte. Ich kenne mich mit den Optionen des Linkers 
nicht aus und weiß daher nicht, ob er den Stack ohne die Definition 
automatisch an einer "sicheren" Stelle anlegt.

Die Entwickler vom AVR Studio 5 werden sich doch was dabei gedacht haben 
diese Stackdefinition extra einzutragen. Naja, vielleicht auch nicht... 
:-)

Gruß,
André

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Da im Debugfall diese Definition nicht angegeben wird, wird es wohl 
einen (sinnvollen?) Defaultwert für den Stack geben. Das sollte irgendwo 
dokumentiert sein.

von Stefan E. (sternst)


Lesenswert?

André Wippich schrieb:
> Die Entwickler vom AVR Studio 5 werden sich doch was dabei gedacht haben
> diese Stackdefinition extra einzutragen.

Ich habe das noch nie in irgendeinem Studio5-Build-Output gesehen. Ich 
bezweifle, dass das wirklich initial vom Studio5 stammt. Hast du das 
Projekt vielleicht irgendwo her übernommen? Oder hast du vielleicht 
irgendein anderes Projekt "recycelt"?

von André W. (sefiroth)


Lesenswert?

Stefan Ernst schrieb:
> Ich habe das noch nie in irgendeinem Studio5-Build-Output gesehen. Ich
> bezweifle, dass das wirklich initial vom Studio5 stammt. Hast du das
> Projekt vielleicht irgendwo her übernommen? Oder hast du vielleicht
> irgendein anderes Projekt "recycelt"?

Nein, habe kein altes Projekt recycelt. Und selbst wenn dem so wäre - 
ich habe mit absoluter Sicherheit noch nie den Stack verschoben ;-)

Verrücktes AVR Studio...

von André W. (sefiroth)


Lesenswert?

Guten Morgen!

Ich habe eben mal ein neues AVR Studio 5 Projekt für den AT90CAN128 
angelegt und tatsächlich ist dort diese "Stack ab 0x400" 
Linker-Einstellung nicht eingetragen. Woher die dann in meinem Projekt 
kommt ist ein Fall für die X Akten...

Also als Fazit können wir festhalten, dass die Stackadresse nicht 
manuell eingetragen werden muss und der Linker anscheinend weiß was er 
tut. Und man sollte auch die Linkereinstellungen nach Anlegen eines 
Projektes prüfen.

Vielen Dank für eure Hilfe!

Gruß,
André

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.