MSP430F2xx Stack Phänomen

Ich habe hier gerade zwei MSPs am Wickel. Einen MSP430F248 und einen MSP430F2617. Der letztere hat mehr RAM für ein paar Experimente. Beide sitzen aber auf einer sonst 100% identischen Entwicklungsumgebung.

Ich habe ein Programm (strictes C mit einigen Routinen ASM), welches ich für beide Plattformen sauber kompilieren kann. Auf dem F248 (auf 24MHz übertaktet) läuft das Programm problemlos. Tagelang... Beim F2617 im serientrimm haut die main-Loop mit jedem Durchlauf ein Element auf den Stack, bis er überläuft. Ich habe jetzt schon alle IRQs aus, bringt aber keine Besserung...

Hat jemand noch eine Idee, wo ich da weitersuchen kann?

Roland

Reply to
Roland Ertelt
Loading thread data ...

Wenn du schon festgestellt hast, daß es eine so starke positive Korrelation zwischen Stackwachstum und der Zahl der Durchläufe der Hauptschleife gibt, dann ist es ziemlicher Quatsch, den Fehler im Interruptsystem zu suchen. Er wird sehr wahrscheinlich nicht dort, sondern eben in der Hauptschleife stecken.

In der Hauptschleife natürlich. Im Prinzip bilden alle von dort aufgerufenen Funktionen einen Baum. Man geht also in die erste Ebene (also die Hauptschleife selber) speichert zu Beginn den Stackpointer als Referenzwert und prüft dann nach jedem Funktionsaufruf, ob sich der Stackpointer geändert hat. Hat er das, muß der Fehler in zuletzt aufgerufenen Funktion oder den wiederum von dieser Funktion aufgerufenen Funktionen liegen. Also baut man den Debugcode aus der Hauptschleife aus und in die gefundene Funktion eine Ebene tiefer wieder ein. Das wiederholt man immer wieder und steigt so in den Baum der Funktionen ab, bis man eine gefunden hat, die ihrerseits keine Funktionen mehr aufruft. Voíla: Die Funktion, die das Stackwachstum verursacht, ist gefunden.

Das heißt dann allerdings noch nicht notwendigerweise, daß der eigentliche Fehler wirklich in dieser Funktion steckt. Aber er steckt mit Sicherheit in dieser Funktion oder in einer der Funktionen, die die Parameter dafür liefern.

Daß man sowas einem Programmierer erklären muß, stimmt einigermaßen traurig...

Reply to
Heiko Nocon

Der faule Programmierer schmeisst einfach am Ende der Hauptschleife dieses Element wieder vom Stack runter. Spart ungemein Zeit beim Debuggen.

(SCNR)

Gerrit

Reply to
Gerrit Heitsch

Ergänzung: ... oder in der der keine Stackänderung mehr festzustellen ist.

Reply to
Heiko Nocon

Und so sprach Heiko Nocon:

Um den Fehler auf die main()-loop einzugrenzen, muss man nun mal die IRQs unterbinden. Und um einen deterministischen Ablauf der Main-Loop zu erhalten auch. Dass man *das* einem Programmierer sagen muss stimmt irnkwie traurig, gelle..?

Wie ich den Stackpointer beobachte weiss ich, dazu musst du kein Bild malen. Daher weiss ich ja auch, warum der Kern reproduzierbar in den Reset geht.

Ok. Und wenn jetzt jede der aufgerufenen Funktionen (es sind 3 Stück) allein kein Stackwachstum verursacht?

Wie jeder saubere Programmierer baue ich keinen selbstmodifizierenden Code, Spaghetti-Code und mache auch keine Pointer-Arithmetik. Achja, "globale"-Variablen gibt es auch keine...

Traurig ist, dass die Welt nicht so einfach ist, wie du es hier beschreibst.

Wenn das Problem *so* einfach lösbar gewesen wäre, hätte ich hier nicht gefragt.

Mal abgesehen davon, dass mich immer noch die Erklärung interessieren würde, warum der gleiche Quellcode auf einer anderen Ziel-Plattform keinen Stacküberlauf verursacht. Die Kerne sind abgesehen von einem DMA-COntroller und einem DAC (beide Module nicht verwendet) baugleich.

Roland

Reply to
Roland Ertelt

Und so sprach Gerrit Heitsch:

Darauf scheints gerade herauszulaufen ;)

Nein, im Ernst. Es scheint ein Linker-Problem zu sein. Wenn ich aus main() meine funktion() aufrufe (function() ist 100% assembler) packt er

4 Elemente auf den Stack. Das 'ret' holt aber nur zwei wieder ab. Ich muss jetzt erst mal wühlen gehen, warum das auf dem Kern so ist.

Roland

Reply to
Roland Ertelt

Dann steckt der Fehler logischerweise in der Hauptschleife selber. Das ist dadurch klar, daß sie keine Parameter übergeben bekommt, den Fehler also nur "unconditional" selber generieren kann.

Solange Computer deterministisch arbeiten, IST sie so einfach. Daß das so ist, macht z.B. viele Optimierungen von Compilern überhaupt erst möglich.

Wenn es tatsächlich so ist, wie du es beschreibst (ich glaube dir das jetzt einfach mal), dann liegt ein Fehler im Compiler vor. Das ist dann die einzige verbleibende Möglichkeit. Da hilft dann nur ein Blick in den vom Compiler generierten Assemblercode.

Wenn du den kannst, bist du wirklich bei den Programmierern angekommen...

Reply to
Heiko Nocon

Also hast du definitiv in deiner Antwort auf mein erstes Posting glatt gelogen, denn hier gibst du selber zu, daß der Aufruf einer der Funktionen doch den SP verändert!

BTW: Der Linker hat absolut nix damit zu schaffen, wieviele Bytes bei einem Funktionsaufruf auf den Stack gepackt oder oder beim Return dort herunter geholt werden. Dafür ist der Compiler zuständig.

Der Linker kann im besten Fall prüfen, ob Caller und Callee dieselben Erwartungen bezüglich der Aufrufkonventionen einer Funktion haben. Allerdings nicht in C.

Das erfordert nämlich "dekorierte" Funktionsnamen, denn der name mismatch der Symbole ist der einzige Anhaltspunkt, an dem der Linker das feststellen könnte. Solcherart Komfort gibt's in C aber nicht.

Reply to
Heiko Nocon

Und so sprach Heiko Nocon:

Der Unterschied ist, dass für den 249 ein Funktionsaufruf in 'call' übersetzt wird, und für den 2617 in 'calla'. Letzteres ist im offiziellen Befehlssatz von TI nicht aufgeführt.

Manchmal muss man sich einfach mal zurücklehnen, und ein Bier aufmachen. Sonst sieht man den Wald vor lauter Bäumen nicht mehr. Es ist wie so oft, wenn man eine Frage stellt, die andere verstehen sollen, kommt man dann auch selber drauf.

Wie ich den IAR dazu bringe, wieder ein normales 'call' zu machen, müssen mir die Nordlichter mal erklären. Ich hab die mal angeschrieben. Mal sehen was als Antwort kommt...

Roland

Reply to
Roland Ertelt

Roland Ertelt schrieb:

Was auch immer Du liest, in meiner "MSP430x2xx Family User's Guide" (SLAU144 vom Januar 2012) steht die CALLA-Instruktion natürlich drin. Die benötigt man auch, um Funktionsaufrufe im größeren Adressraum (20 Bit) des 2617 zu machen. Entsprechend muss man derart aufgerufene Funktionen natürlich mit RETA beenden. Steht auch so in der Guide.

Christian

--
Christian Zietz  -  CHZ-Soft  -  czietz (at) gmx.net 
WWW: http://www.chzsoft.de/ 
PGP/GnuPG-Key-ID: 0x6DA025CA
Reply to
Christian Zietz

Und so sprach Christian Zietz:

*Das* erklärt natürlich einiges. Vielen Dank dafür.

Die slau144i (Rev. Jan.2012) habe ich auch hier. Jetzt mit ner Volltextsuche nach dem Akronym habe ich es auch gefunden. Welcher Depp verteilt denn die Erklärung des Instruction Set innerhalb CPUX in zwei Unterkapitel, um zwei mal den Befehl "call" zu beschreiben. Die Dokus von TI sind irgendwie gewöhnungsbedürftig. Microchip kann das besser...

Aber ich habe auch schon gegrübelt, wie ich den kompletten Adressraum ausgenutzt kriege. Aber das wäre erst akut geworden, wenn ich tatsächlich mehr als 64k Code zusammenbekomme, und den in Assembler zusammenschrauben wollte.

Danke für den Augenöffner, auch wenn ich sie jetzt erst mal ein paar Stunden zu machen werde ;)

Roland

Reply to
Roland Ertelt

Roland Ertelt :

calla muss mit reta returniert werden. So einfach kann es manchmal sein. :-)

Im 24x programmierst Du im 16bit Adressraum im 26x im 32bit - zumindest auf dem Stack. Kannst das memorymodell des 26x im Compiler aber auch auf small stellen, dann verhält er sich wie der 24x. Den brachliegenden Flash kannste dann trotzdem zum Speichern von Daten nutzen (eigene Routinen dafür schreiben).

M.

Reply to
Matthias Weingart

Und so sprach Matthias Weingart:

Ganz so einfach ist es nicht, das Speichermodell für den Kompiler steht auf 'small'. Er macht da offenbar keine Unterscheidung im Befehlssatz.

Ich muss mich momentan halt darauf verlassen, dass der Kompiler immer die erweiterten Befehle nutzt...

Roland

Reply to
Roland Ertelt

Roland Ertelt :

Das ist dann wirklich ein Bug im IAR-Compiler. Der müsste im Small eigentlich die 16bit Befehle benutzen (und so Platz auf dem Stack sparen). Mein Crossworks Compiler unterscheidet das jedenfalls. Naja aber Du kannst ja per ifdef je nach CPU-Version den jeweils andren ret benutzen und hoffen, dass es nach einem Compilerupdate immer noch so ist.

M.

Reply to
Matthias Weingart

vielleicht rufst du deine asm-Routine mit calla und am ende steht ein einfaches ret?

Waldemar

--
My jsme Borgové. Sklopte ?títy a vzdejte se. Odpor je marný.
Reply to
Waldemar Krzok

Und so sprach Matthias Weingart:

Da die beiden Softwarestände sich in Zukunft eh auseinanderentwickeln werden, werde ich mir das erst mal sparen. Es reicht mir schon, dass ich jetzt erst mal durch alle meine Assembler-Routinen kriechen muss, um sämtliche Sprunganweisungen 20Bit-Fest zu machen. Es kann ja durchaus sein, dass eine davon mal auf der 64k-Grenze zu liegen kommt. Da muss ich jetzt erst mal abchecken, wie der Knilch darauf reagiert. Und beim pushen und poppen gehts dann weiter ;)

Roland

Reply to
Roland Ertelt

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.