Forum: Mikrocontroller und Digitale Elektronik SysTick enable führt zu sofortigem Fault


von Walter T. (nicolas)


Lesenswert?

Hallo zusammen,

ich bin gerade mit meinem Latein am Ende, obwohl das Beispiel, das den 
Fehler erzeugt, wirklich minimal ist:

Und zwar landet ein STM32F103RE beim folgenden Beispiel direkt im 
HardFault-Handler, ein STM32F446 fühlt sich dagegen pudelwohl:
1
#define SYSTICK_TIMER_INTERVAL_MS 1
2
3
#ifdef STM32F4XX
4
    #define SYSTEMCORECLOCK 168000000ULL
5
#elif defined( STM32F10x )
6
    #define SYSTEMCORECLOCK 72000000ULL
7
#endif
8
9
10
int main(void)
11
{
12
    // Timer und Interrupt-Prioritaeten einstellen
13
14
15
16
    #if defined( STM32F4XX ) || defined( STM32F10x )
17
        #if defined( STM32F4XX )
18
            #define HIGHSPEED_TIMER_IRQn TIM6_DAC_IRQn
19
        #elif defined( STM32F10x )
20
            #define HIGHSPEED_TIMER_IRQn TIM4_IRQn
21
        #endif
22
23
24
        SystemInit();
25
        SysTick_Config(SystemCoreClock/1000*(SYSTICK_TIMER_INTERVAL_MS));
26
        assert( SystemCoreClock == SYSTEMCORECLOCK );
27
28
        uint32_t savectrl = SysTick->CTRL;
29
        SysTick->CTRL  = 0; // SysTick-IRQ deaktivieren
30
        //NVIC_DisableIRQ(SysTick_IRQn); funktioniert nicht
31
32
33
        // NVIC/ISRs konfigurieren
34
        NVIC_PriorityGroupConfig(0);
35
36
        NVIC_SetPriority(PendSV_IRQn, 2);
37
        NVIC_SetPriority(SysTick_IRQn, 1);
38
        NVIC_SetPriority(HIGHSPEED_TIMER_IRQn, 0);
39
40
        //FIXME: Enablen der IRQs landet am STM32F103RE sofort im Hard Fault Handler - und 
41
        // ich habe keine Ahnung warum
42
        NVIC_EnableIRQ(HIGHSPEED_TIMER_IRQn); 
43
        NVIC_EnableIRQ(PendSV_IRQn);
44
45
        // SysTick wieder einschalten
46
47
        SysTick->CTRL  = savectrl; // <=========  DAAAAAAAAAAA
48
49
50
51
        while(1);
52
    #endif
53
    return 1;
54
}
Die ISRs für PENDSV-Handler, SysTick-Handler und Timer-ISR sind 
definiert, werden aber noch nicht einmal angesprungen.

Was habe ich übersehen?
Viele Grüße
W.T.

: Bearbeitet durch User
von derjaeger (Gast)


Lesenswert?

Ein Schrittweises durchgehen der Zeilen könnte den Fehler eingrenzen ...

von derjaeger (Gast)


Lesenswert?

Sorry habs überlesen ... kannst du die Defines mitposten?

von Walter T. (nicolas)


Lesenswert?

Beides ergänzt. Viel gibt es nicht.

von derjaeger (Gast)


Lesenswert?

Hast du nur den SysTick mal versucht zum laufen zu kriegen ohne deine 
anderen Timer / Interrupts? Ich hatte den SysTick auf dem F103RE auch 
verwendet und das waren wirklich nur zwei Zeilen oder sowas.

Ich glaub es fehlt noch ein __enable_irq

von Walter T. (nicolas)


Lesenswert?

derjaeger schrieb:
> Hast du nur den SysTick mal versucht zum laufen zu kriegen ohne deine
> anderen Timer / Interrupts?

Ja. Wenn ich die beiden Zeilen mit "NVIC_EnableIRQ();" auskommentiere, 
geht alles.

Ich kann dann auch später mit
TIM_ITConfig(), NVIC_Init() und TIM_Cmd(TIM4, ENABLE) den Timer 
einschalten.

Mich interessiert nur, was hier schief geht, daß ich die beiden IRQs 
nicht vor dem SysTick-Timer einschalten kann, und was in dieser Hinsicht 
den STM32F103 vom STM32F446 unterscheidet.

von RAc (Gast)


Lesenswert?

ich vermute entweder ein alignment Problem oder (wahrscheinlicher) ein 
Stack Problem (Stack nicht gross genug auf dem kleinen Controller o.ä.). 
Du kannst den Fault Status im SCB genauer analysieren. Erster Punkt zum 
Gucken ist der R13 im Fault Fall. Wo zeigt der hin? Was ist im R14?

von Nop (Gast)


Lesenswert?

Zudem wird der Systick nicht über den NVIC eingestellt, weil er kein 
Interrupt ist, sondern eine Exception. Kann aber sein, daß die 
API-Routine das im Falle des Systicks dann korrekt auf den System 
Control Block umbiegt, aber da mußt Du Dich mal durch den HAL-Wust 
kämpfen.

von Jim M. (turboj)


Lesenswert?

Walter T. schrieb:
> NVIC_EnableIRQ(PendSV_IRQn);

Das ist die eigentliche Ursache!

PendSV ist kein NVIC Interrupt. Wegen dem Schreibpuffer kommt der Fault 
ein oder 2 Takte zu spät und es sieht aus als wäre die nächste Zeile die 
Fehlerursache.

NVIC_EnableIRQ() funktioniert nur mit Interrupts >=0, PendSV_IRQn == -2, 
d.h. negativ.

von Jim M. (turboj)


Lesenswert?

Das Fiese ist hier auch das

> NVIC_SetPriority(PendSV_IRQn, 2);

ohne Probleme funktionert, auch für "Faults" wie SysTick oder PendSV. 
Hier werden im Macro negative _IRQn korrekt behandelt...

von Dr. Sommer (Gast)


Lesenswert?

Sicher dass die ISR auf beiden Kontrollen korrekt im ISR Vektor landet? 
Mal das CFSR ausgelesen? Sicher dass es überhaupt der HardFault Handler 
ist und nicht einfach nur dessen ISR der Default Ist? => IPSR auslesen

von Walter T. (nicolas)


Lesenswert?

Nop schrieb:
> Kann aber sein, daß die
> API-Routine das im Falle des Systicks dann korrekt auf den System
> Control Block umbiegt,

Hmm....

core_cm3.h (22. March 2012):
1
__STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
2
{
3
  if(IRQn < 0) {
4
    SCB->SHP[((uint32_t)(IRQn) & 0xF)-4] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff); } /* set Priority for Cortex-M  System Interrupts */
5
  else {
6
    NVIC->IP[(uint32_t)(IRQn)] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff);    }        /* set Priority for device specific Interrupts  */
7
}

core_cm4.h (18. March 2015)
1
__STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
2
{
3
  if((int32_t)IRQn < 0) {
4
    SCB->SHP[(((uint32_t)(int32_t)IRQn) & 0xFUL)-4UL] = (uint8_t)((priority << (8 - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL);
5
  }
6
  else {
7
    NVIC->IP[((uint32_t)(int32_t)IRQn)]               = (uint8_t)((priority << (8 - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL);
8
  }
9
}

Es sieht so aus, als seien in der neueren CMSIS für den M4 ein paar 
Angst-Casts hinzugekommen. In der neueren CMSIS für den M3 sind die dann 
auch drin.

Muß ich mal in Ruhe schauen, ob das einen Unterschied ergibt.

von Christopher J. (christopher_j23)


Lesenswert?

Das Problem ist, wie Jim schon richtig beschrieben hat, die 
NVIC_EnableIRQ. Hier mal Beispielhaft aus der core_cm3.h Version 4.30:
1
__STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn)
2
{
3
  NVIC->ISER[(((uint32_t)(int32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL));
4
}

Da wird der IRQn auf uint32_t gecastet, was dann für kleine negative 
Werte zu einer sehr großen positiven Zahl wird (PendSV_IRQn ist -2, 
(uint32_t)(-2) ist 4294967294) und damit landet 
NVIC->ISER[(uint32_t)(-2)] im Nirvana. In neueren Versionen der 
core_cm3.h ist eine if-Abfrage eingebaut um das Problem abzufangen: 
https://github.com/ARM-software/CMSIS_5/blob/master/CMSIS/Core/Include/core_cm3.h#L1503

Die Schuld an den Angst-Casts trägt MISRA:
https://github.com/ARM-software/CMSIS_5/issues/248

PS:
Die if-Abfragen wurden Ende April 2016 eingeführt. core_cmX.h, die älter 
sind, haben die dementsprechend nicht. Gut möglich, dass deine IDE für 
den F446 eine aktuellere core_cm4.h einbindet. Der entscheidende commit 
war wohl hier: 
https://github.com/ARM-software/CMSIS_5/commit/522d83bbd2b21ce062c5189a4d93383ed9fa3360#diff-cd53dfdd878fa5bcf254f5336653e39c

: Bearbeitet durch User
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.