Guten Abend,
ich habe ein seltsames Problem das den STM32F1 zum Stehen bringt. Und
zwar wird eine ISR Funktion 'angleEstimate' mit ca 16KHz Takt
aufgerufen, wo paar Messwerte verarbeitet werden.
Mit dieser Version tritt kein Problem auf.
Meine Glaskugel sagt:
Alles Ok. Es wird so funktionieren.
ooooooooder: du schickst zuwenig Informationen mit.
Der Code an sich ist OK. Es wird sich an den Randbedingungen etwas
geändert haben was dem uC sauer aufstößt.
füge mal folgende Informationen hinzu:
* wo bleibt er hängen?
* Wann (sofort? nach einer Stunde?)
* wie oft durchläuft er die Schleifebevor er einfriert?
* Listing der Adressen von wichtigen Variablen
* Wie groß ist der Stack? gibt es evtl einen Überlauf?
* Was passiert wenn du nur ine Variable in ein Array verschiebst?
* Hast du einen Debugger zur Hand?
Stm M. schrieb:> Der Controller bleibt hängen
Definiere "bleibt hängen". Springt in einen Fault Handler? Bleibt an
einer bestimmten Instruktion stehen? Welche? Oder wird die ISR lediglich
so langsam dass der Controller diese nur noch in Endlosschleife ausführt
und nichts anderes mehr tut?
Welchen Compiler nutzt du, wie ist deine Compiler-Kommandozeile, wie
sieht die Disassembly aus?
Kannst du "Gain" nicht "const" machen?
Stm M. schrieb:> Ich hab leider keinen Debugger.
Dann ändere das mal, so kann man nicht vernünftig arbeiten. Es versucht
auch keiner Autos zu bauen ohne einen Schraubenzieher zu besitzen. Die
Discovery Boards und Nucleo Boards haben einen ST-Link Debugger und
kosten unter 20€. Wenn du dir ein paar graue Haare sparen möchtest (und
auf jeden Fall wenn du noch viel mit ARM machen möchtest) nimm einen
J-Link EDU für 50€. Ohne Debugger ist das alles nur stochern im Nebel...
mh schrieb:> Der F1 besitzt keine FPU.
Richtig.
mh schrieb:> Du solltest das ganze auf Festkommaarithmetik ändern.
Nicht nötig, es wird eben in Software gerechnet, was auch im Compiler
Aufruf korrekt steht. Ist halt nur langsam. Das geht ja sogar auf dem
AVR.
Zeig mal die Disassembly von beiden Varianten!
Dr. Sommer schrieb:> Dann ändere das mal, so kann man nicht vernünftig arbeiten. Es versucht> auch keiner Autos zu bauen ohne einen Schraubenzieher zu besitzen. Die> Discovery Boards und Nucleo Boards haben einen ST-Link Debugger und> kosten unter 20€. Wenn du dir ein paar graue Haare sparen möchtest (und> auf jeden Fall wenn du noch viel mit ARM machen möchtest) nimm einen> J-Link EDU für 50€. Ohne Debugger ist das alles nur stochern im Nebel...
Also man kann auch ohne Debugger gut auskommen, wenn man ein bisschen
Erfahrung hat und systematisch vorgeht.
Ein Nucleo-Board kann man übrigens auch mit der J-Link-Software flashen,
dann schlägt man zwei Fliegen mit einer Klappe und braucht nicht viel
auszugeben, man ist dann ab ca. 10,- Euro für das Entwicklungssystem +
J-Link-Debugger dabei (abhängig vom Nucleo-Board).
Dr. No schrieb:> Also man kann auch ohne Debugger gut auskommen, wenn man ein bisschen> Erfahrung hat und systematisch vorgeht.
Ja. Aber es ist einfach viel mehr Arbeit. Mit dem Debugger geht vieles
einfacher und schneller. Und so manchen gemeinen Fehler kann man ohne
praktisch gar nicht finden - Speicher Fehler in einer fremd
eingebundenen Library oder eigenen komplexen Programmen... Da kann ein
simpler watchpoint in kürzester Zeit zum Ergebnis führen.
Dr. No schrieb:> Ein Nucleo-Board kann man übrigens auch mit der J-Link-Software flashen,
Richtig, aber das geht dann (offiziell) nur mit STM32.
Das arbeiten mit Debugger ist deutlich einfacher und angenehmer. Erst
recht wenn man weis wie man damit umgehen muss;-)
Zu deinem Fehler:
Hast du mal versucht ein paar ausgaben zu machen?
Weist du schon, wo der Code Stecken bleibt?
Weist du wie man ein Disassembly erstellt?
Weist du wo du das Listing her bekommst?
Hast du mal mit der Reservierten Größe für den Stack gespielt?
Dein Code hat keinen Fundamentalen Fehler. Wenn du willst, dass wird dir
helfen brauchen wir mehr informationen.
Dr. Sommer schrieb:> Dr. No schrieb:>> Also man kann auch ohne Debugger gut auskommen, wenn man ein bisschen>> Erfahrung hat und systematisch vorgeht.>> Ja. Aber es ist einfach viel mehr Arbeit. Mit dem Debugger geht vieles> einfacher und schneller. Und so manchen gemeinen Fehler kann man ohne> praktisch gar nicht finden - Speicher Fehler in einer fremd> eingebundenen Library oder eigenen komplexen Programmen... Da kann ein> simpler watchpoint in kürzester Zeit zum Ergebnis führen.
Das streitet keiner ab, aber stmfresser kann ja schnell mal eine LED
blinken lassen, wenn eine Variable einen Wert annimmt, der nicht
zulässig ist, oder im nächsten Schritt die Werte über den USART
ausgeben. Eventuell auch über ein Display, wenn noch Pins frei sind. Die
meisten Fehler findet man damit auch recht fix.
> Dr. No schrieb:>> Ein Nucleo-Board kann man übrigens auch mit der J-Link-Software flashen,> Richtig, aber das geht dann (offiziell) nur mit STM32.
Klar, aber den benutzt er doch.
Dr. No schrieb:> schnell mal eine LED blinken lassen,
Da der Code sofort abstürzt kann er gar nix ausgeben. Er müsste die
ganze Initialisieung voll mit Debug Ausgaben machen. Mit dem Debugger
sieht man nach 2 Clicks wo es stecken bleibt.
Dr. No schrieb:> Klar, aber den benutzt er doch.
Ja, jetzt - wenn er vorhat das ARM Thema zu vertiefen könnte es
vorkommen dass er noch andere Controller nutzen will... das muss er
jedenfalls selber wissen.
Ich tippe auf Fehler im Linker Script, dass sich da aufgrund der
zusätzlichen Variable was verschiebt. Stack zu klein ist eine mögliche
Variante davon.
Stm M. schrieb:> Bei der Initialisierung stoppt er sofort bevor die Main Schleife> erreicht wird.
Es könnte sein daß bei der Initialisierung von Gain[] eine Funktion aus
der softfloat-lib aufgerufen wird, bevor das softfloat vollständig
initialisiert ist. Also ein Problem der Initialisierungsreihenfolge.
Probier mal das zu umgehen:
Gerd E. schrieb:> Es könnte sein daß bei der Initialisierung von Gain[] eine Funktion aus> der softfloat-lib aufgerufen wird
Das macht keinen Sinn. Erstens muss bei der Library nichts initialisiert
werden, zweitens erfolgt die Initialisierung von globalen Variablen
normalerweise im Startupcode auf Basis von Rohdaten, komplett unabhängig
ob das floats oder Integer oder C++ Klassen sind, quasi per memcpy. Da
ist es völlig unerheblich ob irgendeine Library schon initialisiert ist,
da werden nur Bytes kopiert.
Solange der OP nichts von sich hören lässt bzgl. Disassembly kann man
hier nicht viel machen...
Dr. Sommer schrieb:> Dr. No schrieb:>> schnell mal eine LED blinken lassen,>> Da der Code sofort abstürzt kann er gar nix ausgeben. Er müsste die> ganze Initialisieung voll mit Debug Ausgaben machen. Mit dem Debugger> sieht man nach 2 Clicks wo es stecken bleibt.
Den Debugger hat er ja nicht.
Also in den Init-Teil geschickt ein LED-Blink einfügen. Kommt es, nach
hinten verschieben, kompilieren, neu flashen, Reset.
Kommt es nicht, nach vorne verschieben, ...
Das ist doch fix gemacht und er muss jetzt nicht noch ne Woche warten,
bis ein Debugger oder ein neues Board geliefert wird.
> Ich tippe auf Fehler im Linker Script, dass sich da aufgrund der> zusätzlichen Variable was verschiebt. Stack zu klein ist eine mögliche> Variante davon.
Kann auch genauso gut ein Fehler im Makefile sein, oder...
Am besten, stmfresser postet kurz Linker-Skript, Makefile und die
Ausgabe des Compilers, damit man die Speicherbelegung sieht.
STM Apprentice schrieb:> Stm M. schrieb:>> Ich hab leider keinen Debugger.>> Ich frage mich welche dämliche Erklärung es gibt so einen> vollwertigen, voll kompatiblen Debugger für unter 10 Euro> nicht zu benutzen.
Ich frag mich, wie dämlich man sein muss, um solch unverschämte und
unqualifizierte Postings abzusetzen.
Oder ist das asoziale Elternhaus dafür verantwortlich?
Fragen über Fragen...
Stm M. schrieb:> zwar wird eine ISR Funktion 'angleEstimate' mit ca 16KHz Takt> aufgerufen, wo paar Messwerte verarbeitet werden.
Float-Berechnungen macht man nicht in einer ISR, zumindest wenn man
keine FPU hat. Setz in der ISR nur die Werte auf und mach die Berechnung
in einer Art Main-Schleife, oder in einem separaten Task.
Zum Zweiten scheint Deine ISR so einige Variablen zu nutzen (angle,
angle_vel, angle_m, hallCounterL etwa), die nicht in der ISR deklariert
sind. Das müssen folglich globale Variablen sein, die Du wahrscheinlich
dann auch anderswo verwendest.
Wann immer Du dieselbe globale Variable in einer ISR und im
Hauptprogramm gebrauchst, MUSS die mit "volatile" deklariert sein. Sonst
kann der Compiler diverse häßliche Wegoptimierungen machen.
Geh erstmal das mti dem volatile an, weil das am einfachsten zu machen
ist.
Nop schrieb:> Float-Berechnungen macht man nicht in einer ISR, zumindest wenn man> keine FPU hat. Setz in der ISR nur die Werte auf und mach die Berechnung> in einer Art Main-Schleife, oder in einem separaten Task.
Wozu? Welchen Vorteil soll es bringen, die Rechenzeit in der main statt
der ISR zu verbrauchen? Auf dem Cortex-M kann man schließlich auch die
ISR durch wichtigere Interrupts unterbrechen lassen durch Einstellung
der Priorität.
Dr. Sommer schrieb:> Wozu?
Man hält ISRs so kurz wie möglich, damit bei hoher Auslastung ggf. eine
Berechnung übersprungen wird. Aber manche Leute nutzen ja auch printf in
ISRs...
Nop schrieb:> Man hält ISRs so kurz wie möglich, damit bei hoher Auslastung ggf. eine> Berechnung übersprungen wird.
Das wird sie auch, wenn die ISR lang ist. Da geht dann halt ein
Interrupt verloren. Soweit kein Unterschied... Wobei ein System, bei dem
Interrupts verloren gehen, mMn schon einen Designfehler hat.
Dr. Sommer schrieb:> Auf dem Cortex-M kann man schließlich auch die> ISR durch wichtigere Interrupts unterbrechen lassen durch Einstellung> der Priorität.
So so, ist der STM auch so intelligent dass er seine aktuelle
ISR selbst unterbrechen kann um sie erneut abzuarbeiten?
Wenn die Rechnerei in der ISR so lang dauert dass schon wieder
ein IRQ daherkommt .....
STM Apprentice schrieb:> So so, ist der STM auch so intelligent dass er seine aktuelle> ISR selbst unterbrechen kann um sie erneut abzuarbeiten?
Ach so war das gemeint. Nein, das geht nicht. Das geht bei der typischen
main-Schleifen-Verarbeitung so aber auch nicht, es sei denn man baut an
allen Ecken und Enden Abfragen ein, ob die Berechnung abgebrochen werden
soll. Die könnte man aber genauso in die ISR einbauen (Interrupt-Flag
abfragen und dann einfach zurückkehren). Ist aber beides mMn ziemlich
mies.
Dr. Sommer schrieb:> Wobei ein System, bei dem> Interrupts verloren gehen, mMn schon einen Designfehler hat.
ISRs als Worker zu mißbrauchen, IST ein Designfehler.
STM Apprentice schrieb:> Wenn die Rechnerei in der ISR so lang dauert dass schon wieder> ein IRQ daherkommt .....
Wir kennen ja die Interrupt Gegebenheiten des TO nicht, aber
das ist wie beim AVR: wenn er zu lang in der ISR verharrt
wird er vor lauter Interrupts nicht mehr herauskommen und
"hängt" dann scheinbar ....
Nop schrieb:> ISRs als Worker zu mißbrauchen, IST ein Designfehler.
Solange der selbe Interrupt nicht zu schnell wieder kommt, ist das
überhaupt kein Problem. Das mache ich schon in einigen Projekten so und
funktioniert wie gewollt - warum auch nicht?
In der ISR partout auf lange Verarbeitungen zu verzichten ist ein
typischer Fall vom "Angry-Monkey-Syndrom" aka "das haben wir schon immer
so gemacht". Bei uC's ohne Interrupt-Prioritäten wie dem AVR mag das
sinnvoll sein, beim Cortex-M ist das aber hinfällig. Wenn man in der ISR
nichts anderes macht als ein Flag zu setzen, kann man die ISR auch
gleich komplett weglassen und einfach in der main() das Interrupt-Flag
in der Peripherie abfragen - das ist gewiss nicht die Intention von
Interrupts.
Nop schrieb:> Dr. Sommer schrieb:>>> Wobei ein System, bei dem>> Interrupts verloren gehen, mMn schon einen Designfehler hat.>> ISRs als Worker zu mißbrauchen, IST ein Designfehler.
Das ist mir zu dogmatisch.
Was man in einer ISR macht oder nicht, hängt vom Scheduling-Konzept
Deines Programms ab. Da gibt es verschiedene Varianten und welche da
Sinn machen hängt von den Möglichkeiten Deines µCs (ISR-Prioritäten
möglich ja/nein, etc.) und vor allem aber den Anforderungen der
Applikation ab.
Aber das schweift jetzt langsam vom Thema ab.
Dr. Sommer schrieb:> Wenn man in der ISR> nichts anderes macht als ein Flag zu setzen, kann man die ISR auch> gleich komplett weglassen und einfach in der main() das Interrupt-Flag> in der Peripherie abfragen - das ist gewiss nicht die Intention von> Interrupts.
Offensichtlich (Stichwort 16 kHz) geht es dabei um Timing, und man
verwendet deswegen ISRs, um die Meßwerte mit festem Raster zu erfassen.
Kann man auch in der main machen, das wird dann aber deutlich
frickeliger, mit Delays und all sowas.
Daß man die Meßwerte mit festem Raster erfaßt, bedeutet nicht, daß man
auch gleich die ganze Signalverarbeitung drauf loslassen muß.
Und sich über Interruptprioritäten ein Multitasking-RTOS in Sparversion
zu bauen, ist auch nicht gerade ein Design-Highlight. ^^