Forum: Mikrocontroller und Digitale Elektronik STM32F4: Anfängerfrage: nach NVIC_Init lande ich in hardfault handler


von Josef S. (josef2)


Lesenswert?

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 */
3
  NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn;
4
  /* Set priority */
5
  NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x00;
6
  /* Set sub priority */
7
  NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x00;
8
  /* Enable interrupt */
9
  NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
10
  /* Add to NVIC */
11
  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
2
//               Most of the code is copied from Tijen 
3
//               Majerle EXTI-Tutorial:
4
//               http://stm32f4-discovery.com/2014/08/stm32f4-external-interrupts-tutorial/
5
6
#include "stm32f4xx.h"
7
8
9
/* Configure pin to be output (orange LED on STM32F4-Discovery Board)*/
10
void Configure_PD13(void) {
11
    GPIO_InitTypeDef  GPIO_InitStructure;
12
13
    // ---------- GPIO  for LED (PD13) -------- //
14
    // GPIOD Periph clock enable
15
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
16
17
    // Configure PD13
18
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
19
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
20
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
21
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
22
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
23
    GPIO_Init(GPIOD, &GPIO_InitStructure);
24
    // Switch on orange LED on STM32F4 discovery board
25
    GPIO_SetBits(GPIOD, GPIO_Pin_13);
26
}
27
28
29
/* Configure pins to be interrupts */
30
void Configure_PD0(void) {
31
  /* Set variables used */
32
  GPIO_InitTypeDef GPIO_InitStruct;
33
  EXTI_InitTypeDef EXTI_InitStruct;
34
  NVIC_InitTypeDef NVIC_InitStruct;
35
36
  /* Enable clock for GPIOD */
37
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
38
  /* Enable clock for SYSCFG */
39
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
40
41
  /* Set pin as input */
42
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
43
  GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
44
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
45
  GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
46
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
47
  GPIO_Init(GPIOD, &GPIO_InitStruct);
48
49
  /* Tell system that you will use PD0 for EXTI_Line0 */
50
  SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOD, EXTI_PinSource0);
51
52
  /* PD0 is connected to EXTI_Line0 */
53
  EXTI_InitStruct.EXTI_Line = EXTI_Line0;
54
  /* Enable interrupt */
55
  EXTI_InitStruct.EXTI_LineCmd = ENABLE;
56
  /* Interrupt mode */
57
  EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
58
  /* Triggers on rising and falling edge */
59
  EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
60
  /* Add to EXTI */
61
  EXTI_Init(&EXTI_InitStruct);
62
63
  /* Add IRQ vector to NVIC */
64
  /* PD0 is connected to EXTI_Line0, which has EXTI0_IRQn vector */
65
  NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn;
66
  /* Set priority */
67
  NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x00;
68
  /* Set sub priority */
69
  NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x00;
70
  /* Enable interrupt */
71
  NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
72
  /* Add to NVIC */
73
  NVIC_Init(&NVIC_InitStruct);        // !!! CRASHES HERE !!! //
74
}
75
76
/* Set interrupt handlers */
77
/* Handle PD0 interrupt */
78
void EXTI0_IRQHandler(void) {
79
  /* Make sure that interrupt flag is set */
80
  if (EXTI_GetITStatus(EXTI_Line0) != RESET) {
81
    /* Do your stuff when PD0 is changed */
82
    GPIO_ResetBits(GPIOD, GPIO_Pin_13);
83
    /* Clear interrupt flag */
84
    EXTI_ClearITPendingBit(EXTI_Line0);
85
  }
86
}
87
88
89
int main(void) {
90
  /* System init */
91
  SystemInit();
92
  /* Configure PD13 as output (orange LED) */
93
  Configure_PD13();
94
  /* Configure PD0 as interrupt */
95
  Configure_PD0();
96
97
  while (1) {
98
  }
99
}

von Dr. Sommer (Gast)


Lesenswert?

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.

von Josef S. (josef2)


Lesenswert?

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

von Christian J. (Gast)


Lesenswert?

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

von Dr. Sommer (Gast)


Lesenswert?

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

von Josef S. (josef2)


Angehängte Dateien:

Lesenswert?

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:
1
"shell start "GDB Server" "D:\Programs\stlinkgdbserver\st-util.exe""
2
3
# ... 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

von Manuel W. (multisync)


Lesenswert?

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.

: Bearbeitet durch User
von hp-freund (Gast)


Lesenswert?

Wirf erst einmal einen Blick in deine
1
startup.S
das dürfte einiges bezüglich EXTI erklären...

von Bernd K. (prof7bit)


Lesenswert?

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.

von Josef S. (josef2)


Lesenswert?

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:
1
/************************************************************************************
2
 *
3
 *  The minimal vector table for Cortex-M4.
4
 *  Device specific external interrupts can be added below.
5
 ************************************************************************************/
6
    .section .isr_vector
7
    .align 2
8
    .globl __isr_vector
9
__isr_vector:
10
    .long    __stack_end__         /* Top of Stack */
11
    .long    Reset_Handler         /* Reset Handler */
12
    .long    NMI_Handler           /* NMI Handler */
13
    .long    HardFault_Handler     /* Hard Fault Handler */
14
    .long    MemManage_Handler     /* MPU Fault Handler */
15
    .long    BusFault_Handler      /* Bus Fault Handler */
16
    .long    UsageFault_Handler    /* Usage Fault Handler */
17
    .long    0                     /* Reserved */
18
    .long    0                     /* Reserved */
19
    .long    0                     /* Reserved */
20
    .long    0                     /* Reserved */
21
    .long    SVC_Handler           /* SVCall Handler */
22
    .long    DebugMon_Handler      /* Debug Monitor Handler */
23
    .long    0                     /* Reserved */
24
    .long    PendSV_Handler        /* PendSV Handler */
25
    .long    SysTick_Handler       /* SysTick Handler */
26
27
    /* External interrupts */
28
    .long    Default_Handler
29
    .long    Default_Handler       /* NEU */
30
    .long    Default_Handler       /* NEU */        
31
    .long    Default_Handler       /* NEU */
32
    .long    Default_Handler       /* NEU */
33
    .long    Default_Handler       /* NEU */
34
    .long    EXTI0_IRQHandler      /* NEU */
35
36
37
    .size    __isr_vector, . - __isr_vector


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

von Bernd K. (prof7bit)


Lesenswert?

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.

: Bearbeitet durch User
von Josef S. (josef2)


Lesenswert?

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

von hp-freund (Gast)


Lesenswert?

Moin,

Du hast so viele schöne Timer die nur auf eine solche Aufgabe warten.

Stichwort: Input Capture

von Josef S. (josef2)


Lesenswert?

@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

: Bearbeitet durch User
von hp-freund (Gast)


Lesenswert?

Hier hat schon jemand eine ähnliche Idee gehabt:
http://www.programering.com/a/MjMyQzMwATk.html

von Josef S. (josef2)


Lesenswert?

@hp-freund:

Seite war mir schon bekannt (trotzdem danke!) - leider ist das Englisch 
dort sehr verworren (und der Code auch ein bißchen ...)

von Dr. Sommer (Gast)


Lesenswert?

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.

von Josef S. (josef2)


Lesenswert?

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

von Josef S. (josef2)


Lesenswert?

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

von Bernd K. (prof7bit)


Lesenswert?

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.

von Josef S. (josef2)


Lesenswert?

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

von squierrel (Gast)


Lesenswert?

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.

von einfan (Gast)


Lesenswert?

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

von Christian J. (Gast)


Lesenswert?

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.

von Josef S. (josef2)


Lesenswert?

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

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.