Hallo liebes Forum!
Ich habe ein Problem, wo ich mir die Haare ausreißen könnte und hoffe,
dass mir jemand einen Tip geben kann, warum dem so ist bzw. was ich
missachte (das Problem sitzt ja i.A. vor dem Rechner).
Hard Facts:
MPLAB X IDE v3.05
xc8 v1.33
PIC18F252
Zu meinem Problem:
Ich habe eine Funktion, in welcher beim ersten Aufruf ein Array geladen
werden soll (aus externem EEPROM). Da es aber bei späteren Aufrufen
genau so weiter benötigt wird habe ich mich dafür entschieden es a) als
lokal static zu definieren (1) und b) das Array um ein Feld länger
gemacht als benötigt, worin ich speichere, ob es schon geladen wurde.
Wenn ich jetzt beim ersten Aufruf der Funktion mir im Debugger die Werte
anschaue (siehe Screenshot) sind sie alles, aber nicht richtig
initialisiert (2). So schließe ich daraus, dass das Array schon
bestehenden RAM überschreibt und quasi Amok läuft. Warum wird es nicht
richtig initialisiert? Ich verstehe es nicht.
MPLAB XC8 C Compiler User's Guide (DS0002053E) Seite 175:
(1) "All static variables have permanent storage duration, even those
defindes inside a function which are "local static" variables."
(2) "Variables which are static and which are initialized only have
their initial value assigned once during the program's execution."
Anmerkungen:
- selber Effekt, wenn das Array global definiert wird (was ich aber
gerne
umschiffen würde)
- Länge des Arrays 242 x 1 Byte
Quellcode:
1
uint8_tpearson(uint8_tdataY[])
2
{
3
// TODO: check for better readable variables if sufficient RAM
Wenn ich das richtig lese, hat der PIC18F252 1,5KB RAM. Kann es sein,
dass Du zu diesem Zeitpunkt so viele aktive Auto-Variablen(-Arrays) auf
dem Stack hast, dass der Stack bereits in den Heap (in dem auch Dein
static-Array steckt) gelaufen ist?
Ich habe keine Ahnung, wie das RAM beim PIC aufgeteilt wird in Heap und
Stack.
P.S.
Die Initialisierung
static uint8_t refSpec[SPECPOINTS + 1] = {0};
kannst Du Dir sparen. statics sind per Definition mit 0 initialisiert.
So etwas in die Richtung vermute ich auch, kann es aber an nichts
speziellem fest machen da:
a) Mein Programm empfängt nur über USART einen Befehl und führt
anschließend oben genannten Code aus.
b) Der PIC hat (soweit ich das beurteilen kann) keinen Heap. Der Stack
liegt extra.
c) Das Array wird vom Linker an die Adresse 0x200 geschoben, was der
zweiten (von 5) Bank entspricht. Bank 4 und 5 sind laut Linker-Map leer,
woraus ich schließe, dass es kein Speicherproblem im Allgemeinen sondern
eine komische Art Speicherverwaltungsproblem ist. Was ich aber nicht
verstehe. Also garnicht. Kein bisschen. :(
PS: die Initialisierung ist zur besseren Lesbarkeit des Quellcodes da,
da ja auf == 0 überprüft wird (und wird vom Compiler herausoptimiert).
Aber das würde nur ein Doktern an den Symptomen sein. Ausserdem ist
refSpec[SPECPOINTS] ja schon laut Debugger != 0 und damit wird dieses if
überhaupt nicht zutreffend.
Kannst Du möglichst viel auskommentieren, bevor diese Funktion
aufgerufen wird? Besteht dann irgendwann dieses Array doch aus vielen
Nullen, könntest Du durch sukzessives Einkommentieren den Übeltäter,
welcher Dir das RAM vollschreibt, finden.
Oder der XC8 hat einen Bug, nämlich dass er statics nicht
initialisiert...
P.S.
Nimm versuchsweise trotzdem mal die Initialisierung raus. Vielleicht
schaltest Du mit dem expliziten Init die implizite Initialisierung ab.
Ich weiß nicht, ob der XC8 das wegoptimiert, der gcc konnte das früher
jedenfalls nicht - neuere Versionen schon.
Frank M. schrieb:> Die Initialisierung>> static uint8_t refSpec[SPECPOINTS + 1] = {0};>> kannst Du Dir sparen. statics sind per Definition mit 0 initialisiert.
Würde ich mich nicht drauf verlassen. Da die Controller klein sind kann
es sein das die aus Performancegründen nicht auf 0 gesetzt werden. Bei
MikroE C ist das z.B. definit so.
> "Variables which are static and which are initialized only have> their initial value assigned once during the program's execution."
deutet darauf hin das du ihr init value explizit angeben sollst.
> if (refSpec[SPECPOINTS] == FIRSTRUN)> {> loadSpectrum(&sumX, &NsumXX, &refSpec[0]);> }
kannst du doch einfach beim Initialisieren laden. Pack die Routinen in
die gleiche unit dann haben Sie "file scope".
meiner Meinung nach mehrfach gezwungen endlich mit Null initialisiert zu
werden, da es nun auch in einem Speicherbereich ist, wo laut linker weit
und breit nix passiert. Und es wird trotzdem nicht korrekt
initialisiert. Ist mein PIC vielleicht im Eimer? Aber dann würde ja der
Rest auch nicht funktionieren, vermute ich. Das mit Übeltäter finden
probiere ich gerade, gestaltet sich bloß etwas kompliziert mit nur
Variablen im Scope beobachten und sagenhaften einem Breakpoint....
>> if (refSpec[SPECPOINTS] == FIRSTRUN)>> {>> loadSpectrum(&sumX, &NsumXX, &refSpec[0]);>> }>> kannst du doch einfach beim Initialisieren laden. Pack die Routinen in> die gleiche unit dann haben Sie "file scope".
Eben das ist ja das Problem, dass die Werte nach dem initialisieren
Überschrieben werden... von wo auch immer. Herumvegetierende Zeiger habe
ich nicht zu bieten ...
Enrico K. schrieb:> Das mit Übeltäter finden> probiere ich gerade, gestaltet sich bloß etwas kompliziert mit nur> Variablen im Scope beobachten und sagenhaften einem Breakpoint....
Hat das Ding echt nur einen Breakpoint ?
Benutze ich schon sooo lange nicht mehr, dass ich mich gar nicht
erinnern kann.
Kannst du einen Datenbreakpoint setzen ?
<edit>sieht so aus als gäbe es keinen Datenhaltepunkt
"breakpoints (numhwbp=1 datacapture=false idbyte=p)"
sorry</edit>
Als Alternative gäbe es noch TRAP
-> http://www.microchip.com/forums/FindPost/434323
Enrico K. schrieb:> Ini drin oder draußen macht keinen Unterschied. Ich habe testweise> das Array mit static uint8_t refSpec[SPECPOINTS + 1] __at(0x400) = {0};> meiner Meinung nach mehrfach gezwungen endlich mit Null initialisiert zu> werden,
widerspricht sich mit
> Eben das ist ja das Problem, dass die Werte nach dem initialisieren> Überschrieben werden... von wo auch immer. Herumvegetierende Zeiger habe> ich nicht zu bieten ...
oder ist es keine Initialisierung und danach wird das auch noch
überschrieben?
static uint8_t refSpec[SPECPOINTS + 1] __at(0x400) = {0};
grenzt das Problem ja nicht ein. Ist internes flash ist und ich weiß
nicht wie du dem compiler sagst das es für deine Daten reserviert sein
soll.
Lade deine Daten hart (ohne condition) aus deinen EEPROM und dann schau
nach ob die auch da sind.
> Da es aber bei späteren Aufrufen> genau so weiter benötigt wird habe ich mich dafür entschieden es a) als> lokal static zu definieren (1) und b) das Array um ein Feld länger> gemacht als benötigt, worin ich speichere, ob es schon geladen wurde
static vars sind ja reserviert. Warum willst du da jedes mal beim Aufruf
der routine prüfen ob die schon geladen sind statt Sie gleich zu laden?
Versuch mal
volatile static uint8_t refSpec[SPECPOINTS + 1] = {0};
Eventuell macht der Optimierer was er will.
Im generierten Assembler listing sollte man alles finden, da stehen
auch die C Code Zeilen als Kommentar drin. Mit einem ordentlichen Editor
nach refSpec suchen.
Volker S. schrieb:> Kannst du einen Datenbreakpoint setzen ?>> <edit>sieht so aus als gäbe es keinen Datenhaltepunkt> "breakpoints (numhwbp=1 datacapture=false idbyte=p)"> sorry</edit>
Mist, muss mich gleich nochmal entschuldigen.
"Datacapture" ist anscheinend was anderes.
Du solltest also einen Datenbreakpoint auf die Adresse des Arrays setzen
können. Rechtsklick zu Öffnen des Kontextmenüs in einem Sourcefile oder
[Strg][Umschalt][F11] und beim Schreiben ...
Volker S. schrieb:> Als Alternative gäbe es noch TRAP> -> http://www.microchip.com/forums/FindPost/434323
Scheint beim XC8 __debug_break() zu heißen (noch nie getestet ;-)
-> http://www.microchip.com/forums/FindPost/779388
X4U schrieb:> Frank M. schrieb:>> Die Initialisierung>>>> static uint8_t refSpec[SPECPOINTS + 1] = {0};>>>> kannst Du Dir sparen. statics sind per Definition mit 0 initialisiert.>> Würde ich mich nicht drauf verlassen. Da die Controller klein sind kann> es sein das die aus Performancegründen nicht auf 0 gesetzt werden. Bei> MikroE C ist das z.B. definit so.
Dann darf der sich nicht "C Compiler" nennen. Die Initialisierung von
statics und anderen globalen Variablen mit 0 - wenn nicht anders
angegeben - ist schon seit 1970 Standard, also so lange, wie es C gibt.
Frank M. schrieb:> Dann darf der sich nicht "C Compiler" nennen. Die Initialisierung von> statics und anderen globalen Variablen mit 0 - wenn nicht anders> angegeben - ist schon seit 1970 Standard, also so lange, wie es C gibt.
Falscher Thread.
Rätsel gelöst. In einer anderen Prozedur ca. 2853 Codezeilen entfernt
habe ich ein Array selber größe (lokal), welches zu Berechnungszwecken
populiert wird. Dieses war nicht als static definiert, da nach Ende der
Prozedur die Werte keine Relevanz mehr hatten. Nur hat der liebe Linker
diese Werte (für mich nicht nachvollziehbar, warum) an den Platz meines
static-Arrays geschrieben. Für mich klingt das nach einem Linker-Fehler,
da ja (siehe oben) eine static-Variable eine feste Adresse hat, welche
für andere Daten tabu ist... falls jemand dazu noch ein paar
Sachdienliche Hinweise hat wäre ich sehr erfreut diese zu hören (um
solche Fehler in Zukunft zu vermeiden).
Sonst danke ich allen Teilnehmern für die sachdienlichen Hinweise,
wieder was gelernt ;)
Enrico K. schrieb:> Nur hat der liebe Linker> diese Werte (für mich nicht nachvollziehbar, warum)
Manchmal dauert es ein bisschen ...
Enrico K. schrieb:> an den Platz meines> static-Arrays geschrieben. Für mich klingt das nach einem Linker-Fehler,> da ja (siehe oben) eine static-Variable eine feste Adresse hat, welche> für andere Daten tabu ist... falls jemand dazu noch ein paar> Sachdienliche Hinweise hat
Wenn du ein gepacktes Minimal-Projekt posten würdest, welches das
Verhalten zeigt, könnte man ja mal schauen ;-)