Forum: Mikrocontroller und Digitale Elektronik STM32F1 bleibt hängen wegen einer seltsame Ursache


von Stm M. (stmfresser)


Lesenswert?

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.
1
void angleEstimate(void) {
2
  float angle_p = angle + angle_vel * 0.000064f;
3
4
  if (ABS(hallCounterL) > 0) {
5
    angle_m = (float) ((hallCounterL << 6) - (hallCounterL << 2));
6
    float error = angle_m - angle_p;
7
8
    angle = angle_p + 0.03340962f * error;
9
    angle_vel = angle_vel + 0.05676238f * error;
10
  }
11
}

Der Controller bleibt hängen wenn ich die Funktion wie folgt umschreibe
1
// R: 300, Q: 10000 
2
float Gain[2] = {0.03340962f, 0.05676238f};
3
4
void angleEstimate(void) {
5
  float angle_p = angle + angle_vel * 0.000064f;
6
7
  if (ABS(hallCounterL) > 0) {
8
    angle_m = (float) ((hallCounterL << 6) - (hallCounterL << 2));
9
    float error = angle_m - angle_p;
10
11
    angle = angle_p + Gain[0] * error;
12
    angle_vel = angle_vel + Gain[1] * error;
13
  }
14
}

Was mache ich falsch?

Vielen Dank.

von Dennis R. (dennis_r93)


Lesenswert?

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?

von Dr. Sommer (Gast)


Lesenswert?

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?

von Stm M. (stmfresser)


Lesenswert?

Danke für die Antworten!

Bei der Initialisierung stoppt er sofort bevor die Main Schleife 
erreicht wird. Ich hab leider keinen Debugger.
1
> arm-none-eabi-gcc --version
2
arm-none-eabi-gcc (GNU Tools for ARM Embedded Processors) 5.4.1 20160919 (release) [ARM/embedded-5-branch revision 240496]
1
arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -mfloat-abi=soft -O0 -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -ffreestanding -fno-move-loop-invariants -Wall -Wextra  -g3 -DDEBUG -DUSE_FULL_ASSERT -DTRACE -DOS_USE_TRACE_SEMIHOSTING_DEBUG -DSTM32F10X_HD -DUSE_STDPERIPH_DRIVER -DHSE_VALUE=8000000 -I"../include" -I"../system/include" -I"../system/include/cmsis" -I"../system/include/stm32f1-stdperiph" -std=gnu99 -MMD -MP -MF"src/main.d" -MT"src/main.o" -c -o "src/main.o" "../src/main.c"

Den Gain mit const, noch volatile versucht, keine Änderung.

von mh (Gast)


Lesenswert?

Der F1 besitzt keine FPU. Du solltest das ganze auf Festkommaarithmetik 
ändern.
Ansonsten sind aus den Code-Schnipsel keine Fehler erkennbar.

von Dr. Sommer (Gast)


Lesenswert?

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!

von Dr. No (Gast)


Lesenswert?

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).

von Dr. Sommer (Gast)


Lesenswert?

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.

von Dennis R. (dennis_r93)


Lesenswert?

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.

von Dr. No (Gast)


Lesenswert?

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.

von Dr. Sommer (Gast)


Lesenswert?

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.

von Gerd E. (robberknight)


Lesenswert?

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:
1
float Gain[2];
2
3
...
4
5
main()
6
{
7
    ...
8
    Gain[0] = 0.03340962f;
9
    Gain[1] = 0.05676238f;
10
    ...
11
    // ISR init

von Dr. Sommer (Gast)


Lesenswert?

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...

von Dr. No (Gast)


Lesenswert?

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.

von STM Apprentice (Gast)


Lesenswert?

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.

wie z.B.:
http://www.ebay.de/itm/ST-Link-V2-USB-Programmer-Stick-Dongle-kompakt-STM32-Debugger-rosa-/172692663082?hash=item283548eb2a:g:b4MAAOSwB-1YpT-c

von Dr. No (Gast)


Lesenswert?

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...

von Nop (Gast)


Lesenswert?

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.

von Horst (Gast)


Lesenswert?

Definitiv Startup-Code oder Linkerscript, wenn es mit lokalen Variablen 
geht aber mit globalen nicht.

von Dr. Sommer (Gast)


Lesenswert?

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.

von Nop (Gast)


Lesenswert?

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...

von Dr. Sommer (Gast)


Lesenswert?

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.

von STM Apprentice (Gast)


Lesenswert?

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 .....

von Dr. Sommer (Gast)


Lesenswert?

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.

von Nop (Gast)


Lesenswert?

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.

von STM Apprentice (Gast)


Lesenswert?

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 ....

von Dr. Sommer (Gast)


Lesenswert?

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.

von Gerd E. (robberknight)


Lesenswert?

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.

von Nop (Gast)


Lesenswert?

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. ^^

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.