Forum: Mikrocontroller und Digitale Elektronik Delay in ISR


von Walter T. (nicolas)


Lesenswert?

Hallo zusammen,

gibt es eigentlich einen Grund, der gegen einen delay in einer ISR 
spricht?
1
void HardFault_Handler(void)
2
{
3
    // Sicheren Zustand herstellen
4
    GPIOA->MODER = 0;
5
    GPIOB->MODER = 0;
6
    GPIOC->MODER = 0;
7
    GPIOD->MODER = 0;
8
9
10
    setOutput(ERRORLED_GPIO, ERRORLED_Pin);
11
12
    while(1) {
13
        ERRORLED_GPIO->ODR ^= (uint32_t) ERRORLED_Pin;
14
        delay_ms(200);
15
    }
16
}

Eigentlich müßte doch beim HardFault-Handler der Drops gelutscht sein 
und mich delays nicht mehr interessieren.

Viele Grüße
W.T.

von Stefan F. (Gast)


Lesenswert?

In diese Fall spricht nichts dagegen, finde ich.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Nö, du musst nur zusehen, das der SysTick eine noch höhere Priorität als 
der Hardfault Handler hat, sonst hängts. Nicht, das du das nicht sowieso 
wolltest, aber blinken tuts dann auch nicht.

von dummschwaetzer (Gast)


Lesenswert?

Sicherer Zustand währe für mich Interrupts sperren, geht da deine 
delay() noch?

von Vincent H. (vinci)


Lesenswert?

Hat der HardFault nicht eine höhere (nicht änderbare) Priorität als der 
SysTick? Falls ja, dann geht das mit Sicherheit nicht.

von Ingo L. (corrtexx)


Lesenswert?

Bei sowas würde ich auch keine delay-Funktion nutzen, die auf andere 
ISRs angewiesen ist. Da würde ich tatsächlich mit roher CPU Gewalt 
Rechenleistung für ein delay alà:
1
void delay ( uint32_t Delaytime ) 
2
{
3
 while ( Delaytime ) Delaytime--;
4
}
verbraten. Timing is hier sowieso nur von geringerer Präzision 
notwendig.

: Bearbeitet durch User
von Peter II (Gast)


Lesenswert?

Ingo L. schrieb:
> für ein delay alà:

und hoffen das der Compiler es nicht komplett entsorgt. Da sollte dann 
noch ein volatile oder ähnliches rein.

von Walter T. (nicolas)


Lesenswert?

Die hier funktioniert recht zuverlässig:
1
    #define TUNE_FAC 1.0
2
            
3
4
   #define delay_us(delayval) delay_us_( \
5
          (uint64_t)( (SYSCLK) / 3000000ULL *delayval * TUNE_FAC) )
6
7
  #define delay_ms(delayval) delay_us_( \
8
          (uint64_t)( (SYSCLK) / 3000ULL *delayval * TUNE_FAC) )
9
10
  static inline void delay_us_(uint64_t delayval)
11
  {
12
        if(delayval)
13
            {
14
          asm volatile (\
15
                "L_LOOPUS_%=:     \n\t" \
16
                "subs %0, %0, #1  \n\t" \
17
                "bne  L_LOOPUS_%= \n\t" \
18
                :  "+r" (delayval) );
19
        }
20
        else
21
            {
22
          asm volatile("nop");
23
        }
24
    }

von Ingo L. (corrtexx)


Lesenswert?

Peter II schrieb:
> und hoffen das der Compiler es nicht komplett entsorgt. Da sollte dann
> noch ein volatile oder ähnliches rein.
Kann man ja machen, wenn es nicht auf Anhieb funktioniert...

von Walter T. (nicolas)


Lesenswert?

dummschwaetzer schrieb:
> Sicherer Zustand währe für mich Interrupts sperren,

Warum? Was sollten die ISRs noch anstellen, wenn alle Pins Eingänge 
sind?

von Jim M. (turboj)


Lesenswert?

Peter II schrieb:
> Ingo L. schrieb:
>> für ein delay alà:
>
> und hoffen das der Compiler es nicht komplett entsorgt. Da sollte dann
> noch ein volatile oder ähnliches rein.

Und genau das sorgt bei unterschiedlichen optimierungsstufen für eine 
seeeehr variable Durchlaufzeit. Viele Leute nutzen daher eine simple 
Funktion, die eine passend berechnete Anzahl an __NOP(); für so 1us oder 
10us enthält.

Für den OP noch der Hinweis, das man solche Schleifen im Hardfault gerne 
mal mit Taste unterbrechbar haben will (um z.B. einen Reset auszulösen). 
Dann muss man die 200ms unterteilen (z.B. 1ms Schritte), sonst muss der 
Anwender die Taste lange gedrückt halten.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Walter T. schrieb:
> "L_LOOPUS_%=:     \n\t" \
>                 "subs %0, %0, #1  \n\t" \
>                 "bne  L_LOOPUS_%= \n\t" \

Dafür hat der Gott der Unix-Assembler local labels erfunden:
1
   "1:  subs %0, %0, #1 \n\t" \
2
   "    bne 1b\n\t" \

von Adam P. (adamap)


Lesenswert?

Die Funktion delay_ms() basiert doch nicht auf Interrupts und auch nicht 
auf dem System-Tick (solange es keine Eigenentwicklung ist) - oder habe 
ich da etwas überlesen?

Die Prio vom HardFault und SysTick ist einstellbar.

Ich beziehe mich jetzt auf einen Cortex-M4, denn der verwendete 
Controller wurde nicht genannt.

von Carl D. (jcw2)


Lesenswert?

Walter T. schrieb:
> Hallo zusammen,
>
> gibt es eigentlich einen Grund, der gegen einen delay in einer ISR
> spricht?
>
>
1
> void HardFault_Handler(void)
2
> {
3
>     // Sicheren Zustand herstellen
4
>     GPIOA->MODER = 0;
5
>     GPIOB->MODER = 0;
6
>     GPIOC->MODER = 0;
7
>     GPIOD->MODER = 0;
8
> 
9
.
10
>     setOutput(ERRORLED_GPIO, ERRORLED_Pin);
11
> 
12
>     while(1) {
13
>         ERRORLED_GPIO->ODR ^= (uint32_t) ERRORLED_Pin;
14
>         delay_ms(200);
15
>     }
16
> }
17
>
>
> Eigentlich müßte doch beim HardFault-Handler der Drops gelutscht sein
> und mich delays nicht mehr interessieren.
>
> Viele Grüße
> W.T.

Das ist keine ISR, sondern ein Fault-Handler. Falls der nur eine 
Error-LED blinken lassen soll, warum nicht. Wenn er eine Situation 
behandelt, für die es tatsächlich eine softwaretechinsche Lösung gibt, 
dann würde man sicher kein delay() wollen. Die würde man dann aber eher 
in UsageFault/MemoryManagementFault behandeln, im HardFault ist die 
Fehlerursache gar nicht mehr ablesbar.

Hardfault ist so eine Art letztes Zucken, denn der kommt, wenn andere 
Fehlersituationen nicht oder nicht ohne neu auftretende Fehler behandelt 
werden. Da ist alles erlaubt. Zumal ein Hardfault eine kaum noch zu 
unterbietende Prio hat.

von Walter T. (nicolas)


Lesenswert?

Jörg W. schrieb:
> Dafür hat der Gott der Unix-Assembler local labels erfunden:

Danke für den Hinweis! ARM-Assembler ist für mich eine Fremdsprache, die 
ich nie ohne Wörterbuch in der Hand anfasse.

von Adam P. (adamap)


Lesenswert?

Adam P. schrieb:
> Die Prio vom HardFault und SysTick ist einstellbar.

Muss mich korrigieren:
HardFault hat Prio. (-1)

von Carl D. (jcw2)


Lesenswert?

Walter T. schrieb:
> Jörg W. schrieb:
>> Dafür hat der Gott der Unix-Assembler local labels erfunden:
>
> Danke für den Hinweis! ARM-Assembler ist für mich eine Fremdsprache, die
> ich nie ohne Wörterbuch in der Hand anfasse.

Die Sprache zu verstehen wäre aber Grundvoraussetzung, um die Auswirkung 
verschiedener C-Konstrukte abschätzen zu können.
Plus so Feinheiten, daß ein Register in dem Befehl nachdem es geladen 
wurde vielleicht noch nicht verfügbar ist und man deshalb besser 2 
"C-Statement" verschränkt ausführt.

von Walter T. (nicolas)


Lesenswert?

Jim M. schrieb:
> Für den OP noch der Hinweis, das man solche Schleifen im Hardfault gerne
> mal mit Taste unterbrechbar haben will (um z.B. einen Reset auszulösen).
> Dann muss man die 200ms unterteilen (z.B. 1ms Schritte), sonst muss der
> Anwender die Taste lange gedrückt halten.

Meine Reset-Taste benötigt immer gleich lang, egal was im Fault-Handler 
läuft.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Walter T. schrieb:
> ARM-Assembler ist für mich eine Fremdsprache

Wobei die Geschichte der local labels nicht so viel mit der
Architektur zu tun hat, sondern mit der Umgebung.  Der hier verwendete
GNU Assembler hat seine historischen Wurzeln in den Unix-Assemblern,
die haben solche Labels halt seit jeher gekannt.

Die kann man im GNU Assembler dann unabhängig von der Architektur
nutzen, also sowohl auf ARM, AVR oder x86.

Andere ARM-Assembler haben dieses Feature möglicherweise nicht.

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.