Hi Leute,
ich bin noch Anfänger im STM32-Umfeld und kämpfe nun schon seit Stunden
mit einem Problem, bei dem sich die STM32-Profis unter Euch vermutlich
auf die Schenkel klopfen werden.
Mein Testprogramm - ich möchte die EXTI-Funktionalität testen - stürzt
sang- und klanglos nach dem Aufruf der letzten Zeile in diesem Teil
meines Codes ab:
1
/* Add IRQ vector to NVIC */
2
/* PD0 is connected to EXTI_Line0, which has EXTI0_IRQn vector */
NVIC_Init(&NVIC_InitStruct);// !!! CRASHES HERE !!! //
Der Debugger findet sich anschließend im Hard Fault handler und ich
selber finde einfach meinen Fehler nicht.
Ich verwende emIDE als Entwicklungsumgebung (ein em::Blocks-Abkömmling)
und debugge via Texxane ST-Link auf meinem STM32F4-Discovery-Board.
Alle Hinweise, um den Bug zur Strecke zu bringen, sind hochwillkommen!
Viele Grüße
Josef
PS: hier der gesamte Code von main.c:
1
// Description: Simple testprogram to examine EXTI
Schau dir mal via Backtrace an, wo es genau abstürzt. Schau ins xPSR
welcher Interrupt genau aufgetreten ist. Schau im CFSR was der Grund für
den Absturz war. Prüfe mal ob der Interrupt korrekt an der richtigen
Stelle im ISR-Vektor landet, und nicht einfach nur der Default-Handler
aufgerufen wird.
Danke zunächst einmal für die schnelle Antwort!
Als STM32-Anfänger tue ich mich noch etwas schwer, Deine Antwort
zu verstehen und die Daten aus dem System zu kitzeln.
Ich muß daher gestehen: ich mußte alle Deine Tipps und Hinweise nach-
schlagen, um überhaupt einigermaßen zu erahnen, was Du meinst.
Dr. Sommer schrieb:> Schau dir mal via Backtrace an, wo es genau abstürzt.
Wie komme ich an den Backtrace ran und was genau ist das?
Ich konnte in meiner IDE zwar ein Fenster "J-Link Backtrace"
aktivieren, dort heißt es jedoch "Backtrace off No Trace Data".
> Schau ins xPSR welcher Interrupt genau aufgetreten ist.
Hmmmm:
xpsr = 0x81000003 Nzcvq, GE=0x0, EXC=3, T, ICIIT=0x00
Ich hoffe, das sagt Dir was?
> Schau im CFSR was der Grund für den Absturz war.
Wenn sich das CFSR-Register an Adresse 0x28 befindet
(mein stolzer Fund im PM0214 - Programming Manual), so
zeigt mein Debugger dort 0x00000000 an.
(seltsamerweise führt mein Debugger nur ein FCSR-Register
explizit auf...)
> Prüfe mal ob der Interrupt korrekt an der richtigen> Stelle im ISR-Vektor landet, und nicht einfach nur der Default-Handler> aufgerufen wird.
Oh - ich fürchte, hier brauche ich noch etwas Nachhilfe von Dir.
Sorry, für die dummen Fragen - ich bin einfach noch nicht so weit -
in ein paar Monaten würde ich Deine Anweisungen bestimmt schon
besser verstehen.
Kann man nicht bereits in meinem Programm den Fehler erkennen?
Viele Grüße
Josef2
Lass dich hier nicht kirre machen. ich hatte die gleiche Frage vor
Wochen auch und wurde zugetextet mir den Core von innen anzuschauen usw.
Du solltest Dir eine Debug Umgebung schaffen, das ist richtig und dazu
gibt es Beispiele im Netz. Entsprechende Handler, die Infos enthalten
was wo passiert ist.
Ich hänge dir gleich mal meinen Code an,. schau bitte selbst ob Du alles
hast, meiner läuft.
Prüfe auch die GCC Optimizer Einstellungen, Linker, LTO usw. Bei mir lag
es daran. Es stürzte nämlich nur bei -O2 ab und nicht, wenn ich die
Optimierung ausgeschaltet hatte.
Moment... ich suche .....
In dem Code sind für den F407 unten EXTI Einstellungen drin, für Pin A2
https://www.mikrocontroller.net/attachment/285411/nrf24l01.c
Josef S. schrieb:> Wie komme ich an den Backtrace ran und was genau ist das?
In GDB "bt" eingeben. In eclipse, das Fenster "Debug" öffnen. In deiner
IDE, keine Ahnung.
Josef S. schrieb:> Hmmmm:> xpsr = 0x81000003 Nzcvq, GE=0x0, EXC=3, T, ICIIT=0x00>> Ich hoffe, das sagt Dir was?
Ja, das heißt es wurde tatsächlich der Fault Handler (Interrupt Nr. 3)
aufgerufen, also du hast etwas ungültiges ausgeführt.
Siehe S. 573 im ARMv7M Architecture Reference Manual.
Josef S. schrieb:> Wenn sich das CFSR-Register an Adresse 0x28 befindet
Nö, das ist falsch. Laut S. 653 im ARMv7M Architecture Reference Manual
ist das an Adresse 0xE000ED28.
Josef S. schrieb:>> Prüfe mal ob der Interrupt korrekt an der richtigen>> Stelle im ISR-Vektor landet, und nicht einfach nur der Default-Handler>> aufgerufen wird.>> Oh - ich fürchte, hier brauche ich noch etwas Nachhilfe von Dir.
Laut S. 373 im STM32F4 Reference Manual sollte die Adresse der ISR vom
EXTI0 am Offset 0x00000058 stehen. Prüfe mal, ob in deinem
Programm-Binary an dieser Stelle die Adresse von deiner ISR ist.
Das ist aber vermutlich nicht der Fehler, da wir jetzt ja herausgefunden
haben dass es tatsächlich ein Fault Handler ist.
Josef S. schrieb:> Kann man nicht bereits in meinem Programm den Fehler erkennen?
Klar, wenn man den ultimativen Durchblick hat und unter den zig Zeilen
den vermutlich winzigen Fehler sehen kann... Und du zeigst ja nicht den
gesamten Code, also zB StartupCode + LinkerScript fehlen...
Vorab: Christian's Antwort und seinen Code muss ich erst noch
durcharbeiten - Danke für die Mühen aber schon jetzt.
Immerhin kann ich Dr. Sommer weiteren Input geben:
> Josef S. schrieb:>> Kann man nicht bereits in meinem Programm den Fehler erkennen?> Klar, wenn man den ultimativen Durchblick hat und unter den zig Zeilen> den vermutlich winzigen Fehler sehen kann... Und du zeigst ja nicht den> gesamten Code, also zB StartupCode + LinkerScript fehlen...
Daran soll's nicht scheitern: siehe ZIP-Datei im Anhang.
Aber es kann durchaus sein, dass Deine Vermutung stimmt und ich im
"Drum-Herum" (StartupCode + LinkerScript) einen Bock geschossen habe,
denn ich verstehe einfach noch nicht nicht alles, was ich da
zusammenklaue, mir selber zusammenkonfiguriere und zusammenlinke.
Den Debugger startet meine emIDE über:
# ... mit folgenden GDB-Commands after connection:
4
5
monitor reset
6
load
Leider weiß ich nicht, wie ich dann aus der IDE ein "bt" an den Debugger
absetzen kann .... oooder, halt, hoppla - hab's gerade gefunden:
1
[...]
2
Connected
3
At D:\EXTI-Test003\Setup\startup.S:86
4
At D:\EXTI-Test003\Src\main.c:93
5
Continuing...
6
Program received signal SIGTRAP, Trace/breakpoint trap.
7
At D:\EXTI-Test003\Setup\startup.S:163
8
> bt
9
#0 HardFault_Handler () at D:\EXTI-Test003\Setup\startup.S:163
10
#1 <signal handler called>
11
#2 0xbd107020 in ?? ()
12
#3 <signal handler called>
13
#4 NVIC_Init (NVIC_InitStruct=0x20001c5c) at D:\EXTI-Test003\STM32F4xx_StdPeriph_Driver\src\misc.c:169
14
#5 0x080001f6 in Configure_PD0 () at D:\EXTI-Test003\Src\main.c:75
15
#6 0x0800023c in main () at D:\EXTI-Test003\Src\main.c:97
Supi - leider verstehe ich auch davon nur die Hälfte:
main --ruft--> Configure_PD0 --ruft--> NVIC_Init --ruft-->
signal handler called --> und dann???
Und was das CSFR-Register angeht, so hat die Memory-Adresse
0xE000ED28 den folgenden Wert:
f8 ed 00 e0
Was evtl. noch sachdienlich sein könnte, sind meine Defines, die
ich via gcc setze:
1
DEBUG=1
2
STM32F40_41xxx
3
USE_STDPERIPH_DRIVER
4
HSI_VALUE="((uint32_t)16000000)"
Das Binary zu sichten und den Vector-Eintrag mit meiner ISR-Routine zu
vergleichen würde ich gerne erst dann machen, wenn Du mir sagst, dass
das wirklich wichtig ist, denn das kostet mich bestimmt 1h Arbeit
(herauszufinden, wie das geht ...).
Reichen Euch diese Infos, um die Nadel im Heuhaufen zu finden?
Gruß
Joesef2
Versuch mal die Struktur mit Standardwerten zu initialisieren bevor du
ihr Werte zuweist.
NVIC_StructInit(&NVIC_InitStruct);
Deine Struktur ist local, das heißt sie wird nicht initialisiert und hat
potentiell beliebigen Inhalt. Jene Member, die du nicht überschreibst,
haben daher auch noch beim Aufruf von NVIC_Init() zufällige Werte. Ich
denke, dass das die Ursache deiner Probleme sein könnte.
Nachtrag: Diese Funktion gibt es für jeden Peripherieblock, also auch
für GPIO, ADC und so weiter.
Manuel W. schrieb:> Versuch mal die Struktur mit Standardwerten zu initialisieren bevor du> ihr Werte zuweist.>> NVIC_StructInit(&NVIC_InitStruct);
Das wird die richtige Antwort sein.
Auch bezüglich der anderen beiden Structs. Das war auch mein erster
Anfängerfehler und gemeinerweise war das Fehlerbild nicht
deterministisch, trat erst später auf und hat sich mit der verwendeten
Optimierungsstufe unvorhersehbar geändert. Diese Structs werden temporär
irgendwo auf dem Stack angelegt auf dem sich bereits anderer Datenmüll
befinden kann und ihr Inhalt ist daher undefiniert solange man sie nicht
explizit komplett initialisiert hat.
IHR SEID DIE GROESSTEN !!
Also:
- Dr. Sommer hatte es bereits geahnt:
> Laut S. 373 im STM32F4 Reference Manual sollte die Adresse> der ISR vom EXTI0 am Offset 0x00000058 stehen. Prüfe mal,> ob in deinem Programm-Binary an dieser Stelle die Adresse> von deiner ISR ist.
- ... und hp-freund hat es gesehen:
> Wirf erst einmal einen Blick in deine>
1
startup.S
> das dürfte einiges bezüglich EXTI erklären...
In der Tat lat der Hund in der startup.S begraben.
Die mit /* NEU */ gekennzeichnenten Zeilen brachten den Druchbruch:
Aber warum läßt meine tolle emIDE-Entwicklungsumgebung diese wichtige
Handler-Tabelle unvollständig?
"startup.S" gehört nämlich zum Projekt-Grundgerüst, das automatisch von
der emIDE angelegt wird, wenn ich ein neues STM32F407VG-Projekt anlege.
Dafür gibt's bestimmt einen Grund - den ich aber nicht verstehe - hmmm.
Umso erstaunlicher, wie treffsicher Ihr das sofort gefunden habt - allen
voran hp-freund.
Ihr habt mir riesig geholfen!
Von Dr. Sommer habe ich zudem sehr viel über Debugging gelernt (Danke
Dir explizit dafür!!) und Manuel W. hat mit seinem Hinweis auf die
Nicht-Initialisierung lokaler Variablen ebenfalls 300% recht - darauf
muß ich zukünftig unbedingt achten - echter Greenhorn-Fehler von mir.
Danke Euch allen nochmals!
Josef2
Josef S. schrieb:> "startup.S" gehört nämlich zum Projekt-Grundgerüst, das automatisch von> der emIDE angelegt wird, wenn ich ein neues STM32F407VG-Projekt anlege.> Dafür gibt's bestimmt einen Grund - den ich aber nicht verstehe - hmmm.
Der Grund wird ein Versehen sein, auch Bug genannt. Vermutlich per copy
paste von nem kleineren Controller eingeschlichen bei Erstellung der
Vorlagen.
Deshalb verlassen viele sich im fortgeschrittenen Stadium auch nicht
mehr blind auf die Launen einer halbherzig gepflegten IDE sondern haben
eine eigene liebevoll gepflegte Sammlung von IDE-unabhängigen Vorlagen
samt Makefile für die jeweiligen Lieblingscontroller die für neue
Projekte herangezogen werden.
Hallo,
Danke Eurer Hilfe funktioniert inzwischen alles wie geschmiert.
Ich habe die neuen Erkenntnisse direkt zum Messen von Pulslängen
verwendet.
Jeweils in dem EXTI0-Handler mache ich folgendes:
Steigende Flanke => aktuellen SysTick-Wert merken (StartTick)
Fallende Flanke => aktuellen SysTick-Wert merken (StopTick)
Pulsdauer = StartTick - StopTick # SysTick dekrementiert ja
bekanntlich
Selbstverständlich muß man wegen "Unterlauf" und zweifachem Unterlauf
noch etwas aufpassen - aber das habe ich alles im Griff.
Allerdings kommen mir inzwischen Zweifel, ob es nicht noch elegantere
Wege gibt, um Pulslängen digitaler Signale zwischen ca. 1us ... 1ms auf
ca. 0.1us genau zu vermessen.
Wie würdet Ihr vorgehen?
Viele Grüße
Josef2
@hp-freund: Zunächst einmal Danke für den Tipp.
Input Capture hatte ich mir im Vorfeld auch schon angeschaut, aber
der "captured" ja immer nur den Timer-Wert, wenn er eine Flanke sieht.
Ich hatte da nicht so die rechte Idee, wie man den Timer bei steigender
Flanke startet und bei fallender Flanke anhält bzw. bei den jeweiligen
Flanken den Timer-Wert "captured".
So ginge es vielleicht:
- Bei jeder Flanke Counter grapschen (= capture'n)
- dann nachschauen, ob's eine steigende Flanke war
- dann capture-Wert abspeichern
- dann interrupt zurücksetzen und auf die nächste Flanke lauern
- dann fallende Flanke detektieren und capture-Wert abspeichern
- dann gucken, ob Timer-overflow passiert ist => ggf. Fehler spucken
- dann Differenz aus aktuellem capture-Wert und abgespeichertem Wert
bilden
- dann wieder interrupt zurücksetzen und auf nächste Flanke lauern
Aber elegant ist doch anders, oder?
(sorry - ich bin noch zu unerfahren, um das beurteilen zu können)
Kurzum:
Ich glaube, ich brauche da noch etwas mehr "Zaunpfahl" von Euch ...
Wie soll ich vorgehen, um das Problem etwas "eleganter" zu lösen?
Viele Grüße
Josef2
Josef S. schrieb:> .>> So ginge es vielleicht:
Schau mal im STM32F407VG Reference Manual, S. 593. ST hat sich nämlich
genau darüber schon Gedanken gemacht.
Man lässt den Timer automatisch bei steigenden Flanken resetten ("slave
mode"), und bei fallenden Flanken den aktuellen Wert capturen, den man
dann nur noch aus dem Register auslesen muss.
Dr. Sommer schrieb:> Schau mal im STM32F407VG Reference Manual, S. 593. ST hat sich nämlich> genau darüber schon Gedanken gemacht.
Bei mir beginnt im Reference Manual (DocID018909 Rev 11) auf S.593 das
Kapitel 18.3.3 "Clock Selection" - ich vermute daher, Du referenzierst
eine ältere Manual-Version.
> Man lässt den Timer automatisch bei steigenden Flanken resetten ("slave> mode"), und bei fallenden Flanken den aktuellen Wert capturen, den man> dann nur noch aus dem Register auslesen muss.
Deine Hinweise passen eher auf das Kapitel "18.3.14 Timers and external
trigger synchronization", welches ich mir auf Deinen Rat hin nun einmal
zur Brust genommen habe - und tatsächlich: "Slave mode: Gated mode"
scheint recht gut zu meinem Problem zu passen.
Das mit dem Resetten bei steigenden Flanken und Capture'n bei fallenden
Flanken habe ich beim Querlesen nicht gefunden - aber ich muss das
vermutlich alles nochmals genauer lesen (es sei denn, Du möchtest mir
die genaue Seite im neuesten Reference Manual nochmals nennen).
1000 Dank auf jeden Fall für diesen sehr guten Hinweis - Du hast mich
auf die richtige Spur gebracht!
Viele Grüße
Josef2
Stöhn!
Was sich so einfach anhörte ist eine echte Tortour:
Knappe 200 Seiten beschäftigen sich im Reference Manual mit Timern und
dann weiß man immer noch nicht, wie man die dort beschriebenen 1000
Flags und Register über die Peripheral-Lib Funktionen gesetzt bekommt.
Oder lese ich einfach nur die falsche Literatur?
Viele Grüße
Josef2
Josef S. schrieb:> und> dann weiß man immer noch nicht, wie man die dort beschriebenen 1000> Flags und Register über die Peripheral-Lib Funktionen gesetzt bekommt.
Genau das ist der Grund warum man massiv Zeit und Nerven spart wenn man
diese libs nicht verwendet. Das Reference Manual und die genaue Funktion
der Peripherie musst Du nämlich so oder so komplett gelesen und
verstanden haben, ganz egal ob Du die libs nutzen willst oder nicht,
daran führt eh kein weg vorbei, und spätestens an dem Punkt könntest Du
eigentlich schon loslegen, wirst aber dadurch gebremst daß Du Dich jetzt
jetzt rückwärts durch diese verschwurbelten libs arbeiten musst um quasi
das andere Ende des Fadens wiederzufinden den Du vorher schon in der
Hand hattest. Also vergiss die Libs und arbeite stattdessen allein nach
dem Reference Manual.
Danke an Bernd K. für seine Einschätzung und seinen Rat.
Da ich nun an einem Scheideweg stehe (ausführlich in Peripheral Library
einarbeiten oder nicht), wäre ich noch an ein paar mehr Meinungen
interessiert.
Was sagen die anderen dazu?
Ist wirklich auf Dauer einfacher, ohne die Funktionen der Peripheral
Library einen ARM-Prozessor zu programmieren?
Hintergrund: ich bin "nur" Hobby-Programmierer - kann mich also nicht
fulltime mit dem STM32F4 Reference Manual beschäftigen.
Viele Grüße
Josef2
An Bernd K. Einschätzung ist schon was dran.
Aber ich würde an deiner Stelle nur wenn du durch den Wunsch die HW ganz
geschickt zu nutzen auf die Std Lib verzichten.
Es klappt dann doch oft einfach zu viel so mal ganz schnell.
... wobei man immer einen Blick auf die benötigte Zeit durch Fehler in
der Lib und eigene in der Verwendung haben sollte. Oft ist der
Geschwindigkeitsvorteil dann doch eher gering durch die Lib!
Hängt natürlich auch immer davon ab wieviel mühe sich mit der Lib
gegeben wurde.
Messen auf 0,1 µs genau. Das sind halt dann schon Bereiche wo man so
langsam mal genauer schauen muss. Alles unter dem niedrigen einstelligen
ms-Bereich sehe ich da als Grenze zum komplexeren Verständnis wo man
dann sich die Sachen halt mal genauer anschauen muss.
Josef S. schrieb:> Hintergrund: ich bin "nur" Hobby-Programmierer - kann mich also nicht> fulltime mit dem STM32F4 Reference Manual beschäftigen.
warum abstrahierst du dann nicht noch eine Ebene höher
und nimmst fertige Librarys z.B. für Ext-Interrupts
von Tilen oder Uwe
Josef S. schrieb:> Danke an Bernd K. für seine Einschätzung und seinen Rat.>> Da ich nun an einem Scheideweg stehe (ausführlich in Peripheral Library> einarbeiten oder nicht), wäre ich noch an ein paar mehr Meinungen> interessiert.
Hallo,
lass Dich bitte nicht wieder kirre machen. Dun hast genug Durchblick.
Die Timer kann man auch verwenden, wenn man NICHT das ganze Manual
durchgelesen hat. Den meisten Kram braucht man so gut wie nie. Ich nutze
die Timer nur, um zyklische Ints zu erzeugen, die bei mir Service
machen, zb Werte vom Funkmodul umkopieren, AD Wandler auslesen usw. Und
das geht sehr gut mit den StdPeriphLibs oder CubeMx. Bei speziellen
Sachen wie Zeitmessung oder wie bei mir einen IR Sensor auslesen, wo man
die Pulslänge messen will und die Flanke umschaltet liest man sich etwas
ein.
Niemand, der pflegbaren Code erzeugen will schreibt die Register in
diesen. Das kann kein Mensch mehr lesen, ist unkompatibel zu anderen
Familien und der Compiler macht aus den ganzen Libs sowieso das
optimale, meist inline usw. Ich habe noch keinen Bug in den StdPerih
Libs gefunden außer einem falschen Takt, das war es auch schon.
Allerdings sind die HAL Libs das neueste und wie ich hörte auch besser.
Auchn mit dem CSIS Interface kann man einiges machen, viele nützliche
Dinge sind da drin.
Von den Libs von Tilen, die ich auch erst verwendet habe rate ich
teilweise ab! Ich habe mich mit dem Typen verzankt, da er extrem
arrogant ist und sich für Gott hält. Die Libs sind für den Keil und
lässt man sie durch den GCC laufen mit Optimierung erzeugen sie Hard
Fault etc. da er volatile und static so gut wie nicht benutzt hat. Ich
habe alle fremden Libs rausgeschmissen bei mir, alles selbst
geschrieben. Die von Uwe sind klasse, habe sie anfangs verwendet.
Danke an Christian J., einfan und squierrel für Eure Einschätzung - ich
werde daraufhin meinen Kurs bei der Einarbeitung etwas neu auszurichten:
Dann also doch etwas mehr Zeit in die PeriphLibs investieren und Tilens
Code nur mit Bedacht verwenden (sein Umgangston gefällt mir übrigens
auch nicht).
Viele Grüße
Josef2