Forum: Mikrocontroller und Digitale Elektronik ISR wie normale Funktion aufrufen


von Funktionus Interuptus (Gast)


Lesenswert?

Guten Tag,

ist es möglich, auf einem STM32 eine ISR einfach wie eine normale 
void-voi-Funktion aufrufen, also:
1
extern int32_t g;
2
3
void foo(void)
4
{
5
    do
6
    {
7
        TIM6_DAC_IRQHandler();
8
    } while( g == 0 ); 
9
}
oder muß ich dafür den IRQ triggern?

von Rolf M. (rmagnus)


Lesenswert?

Funktionus Interuptus schrieb:
> ist es möglich, auf einem STM32 eine ISR einfach wie eine normale
> void-voi-Funktion aufrufen, also:
> extern int32_t g;
>
> void foo(void)
> {
>     do
>     {
>         TIM6_DAC_IRQHandler();
>     } while( g == 0 );
> }
> oder muß ich dafür den IRQ triggern?

Warum machst du es nicht umgekehrt? Also eine normale Funktion schreiben 
und die von der ISR aus aufrufen?

von m.n. (Gast)


Lesenswert?

Rolf M. schrieb:
> Warum machst du es nicht umgekehrt? Also eine normale Funktion schreiben
> und die von der ISR aus aufrufen?

Weil es nicht notwendig ist.

von Markus F. (mfro)


Lesenswert?

Funktionus Interuptus schrieb:
> ist es möglich, auf einem STM32 eine ISR einfach wie eine normale
> void-voi-Funktion aufrufen

Ja. Interrupt-Handler sind "ganz normale" C-Funktionen.

"Aufrufen" geht also. Ob die Funktion allerdings auch das tut, was Du 
von ihr erwartest, ist eine andere Frage. Möglicherweise geht sie von 
Voraussetzungen aus, die nur in einem Exception-Kontext gegeben sind. 
Das weiss aber nur der (Du?), der sie geschrieben hat.

von Metatroll (Gast)


Lesenswert?

Eine ISR hat als letzte Instruktion ein Reti/iret : Return from 
interrupt, welche kein normales Funktions Return ist.

von Markus F. (mfro)


Lesenswert?

Metatroll schrieb:
> Eine ISR hat als letzte Instruktion ein Reti/iret : Return from
> interrupt, welche kein normales Funktions Return ist.

Ein AVR hat so was, richtig. Der ist hier aber nicht gefragt.

Beitrag #5212833 wurde vom Autor gelöscht.
von Cyblord -. (cyblord)


Lesenswert?

m.n. schrieb:
> Rolf M. schrieb:
>> Warum machst du es nicht umgekehrt? Also eine normale Funktion schreiben
>> und die von der ISR aus aufrufen?
>
> Weil es nicht notwendig ist.

Ist aber sauberer und portabler.

von Funktionus Interuptus (Gast)


Lesenswert?

Rolf M. schrieb:
> Warum machst du es nicht umgekehrt? Also eine normale Funktion schreiben
> und die von der ISR aus aufrufen?


Also
 - den Inhalt der ISR in eine separate Funktion packen,

 - abändern, dass sie re-entrant wird (globale Variablen statt static),

 - static inline machen, um in der ISR keinen Overhead für den
Funktionsaufruf zu haben,

 - an beiden Stellen aufrufen?

Geht auch. War nur nicht meine Frage.


Markus F. schrieb:
> Möglicherweise geht sie von
> Voraussetzungen aus, die nur in einem Exception-Kontext gegeben sind.

Das sollte bei einer Timer-ISR nicht der Fall sein.

von Peter D. (peda)


Lesenswert?

Markus F. schrieb:
> Ein AVR hat so was, richtig.

Beim AVR ist die Sache einfach, das RETI kann problemlos auch als RET 
fungieren.

Auf dem ARM wird aber ein Interrupt im privilegierten Modus ausgeführt. 
Wenn also aus dem Usermodus ein Call erfolgt, kann das eine Exception 
auslösen.
Auch kann jederzeit der echte Interrupt den Call unterbrechen, d.h. es 
laufen 2 Instanzen gleichzeitig.

von m.n. (Gast)


Lesenswert?

Cyblord -. schrieb:
> Ist aber sauberer und portabler.

Das "sauberer" ist ja zweischneidig. Bei z.B. einem AVR8 bedingt ein 
Funktionsaufruf in einer ISR das komplette Sichern und Restaurieren 
aller Register: sauber und schön langsam!
Hier geht es um einen STM32, wo erst gezeigt werden müßte, daß der 
normale Aufruf einer ISR nicht sauber ist.

Portabel? Kann eine ISR überhaupt portabel sein?

von Falk B. (falk)


Lesenswert?

@ Funktionus Interuptus (Gast)

>ist es möglich, auf einem STM32 eine ISR einfach wie eine normale
>void-voi-Funktion aufrufen, also:

Selbst wenn es funktioniert klingt das eher nach einem schlechten 
Konzept.
So etwas sollte man tunlichst vermeiden und nur dann nutzen, wenn es 
WIRKLICH nicht anders geht. Und wenn man es dann tut, muss man die 
Nebenläufigkeit beachten. Das ist nicht nur das Thema reentrante 
Funktion!

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


Lesenswert?

Es funktioniert bestens, wenn du die Funktion gesondert schreibst und 
dann auch aus der ISR aufrufst. Habe ich schon öfter gemacht und auch 
z.B. so, das drei Interrupts alle dieselbe Funktion aufrufen.

von Funktionus Interuptus (Gast)


Lesenswert?

Danke, das hat mir sehr geholfen!

Peter D. schrieb:
> Auf dem ARM wird aber ein Interrupt im privilegierten Modus ausgeführt.
> Wenn also aus dem Usermodus ein Call erfolgt, kann das eine Exception
> auslösen.

Ich lese daraus: "Ohne OS und ohne Priviledge Levels ist das kein 
Problem. IRQ triggern wäre aber in diesem Sinne portabler."


Peter D. schrieb:
> Auch kann jederzeit der echte Interrupt den Call unterbrechen, d.h. es
> laufen 2 Instanzen gleichzeitig.

Das war klar - aber läßt sich auch problemlos sicherstellen.


Hintergrund der Aktion ist, daß ich einer Regelschleife ein paar Runden 
zur Stabilisierung geben will, bevor die Outputs aktiviert werden. In 
Pseudocode also so:
1
int32_t err = 1000;
2
#define eps 20
3
4
int ctrl_init(void)
5
{
6
    calcinitvars();
7
8
    // Regelschleife ein paar Runden Zeit zur Stabilisierung geben
9
    int n = 0;
10
    do
11
    {
12
        // IRQ manuell triggern, ISR manuell aufrufen oder so.
13
        TIM6_DAC_IRQHandler();
14
        if( n++ > 1000 ) return EXIT_FAILURE;
15
    } while( err > eps ); 
16
17
    enableOutputs();
18
    enableIRQs();
19
    return EXIT_SUCCESS;
20
}

von Cyblord -. (cyblord)


Lesenswert?

m.n. schrieb:
> Cyblord -. schrieb:
>> Ist aber sauberer und portabler.
>
> Das "sauberer" ist ja zweischneidig. Bei z.B. einem AVR8 bedingt ein
> Funktionsaufruf in einer ISR das komplette Sichern und Restaurieren
> aller Register: sauber und schön langsam!

Das spielt nur in Ausnahmefällen eine Rolle. Lesbarer Code ist und 
bleibt wichtiger als Optimierungen auf dieser Ebene.

> Hier geht es um einen STM32, wo erst gezeigt werden müßte, daß der
> normale Aufruf einer ISR nicht sauber ist.
>
> Portabel? Kann eine ISR überhaupt portabel sein?

Eben nicht. Darum ist es portabler die eigentliche Funktion als normale 
und damit portable Funktion auszuführen, und diese lediglich von der 
nicht-portablen ISR aufrufen zu lassen.

Vor allem wenn die Funktion auch noch anderweitig aufgerufen werden 
soll.

von Funktionus Interuptus (Gast)


Lesenswert?

P.S.: In Pseudocode sind natürlich alle Variablen volatile.

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


Lesenswert?

Matthias S. schrieb:
> Es funktioniert bestens, wenn du die Funktion gesondert schreibst und
> dann auch aus der ISR aufrufst.

Wollte noch editieren, das du auf jeden Fall dran denken musst, das 
auslösende Bit, wenns ein Hardware IRQ ist, zu löschen, bevor du die 
Funktion aufrufst. Das ist aber bei STM32 immer so.

von Peter II (Gast)


Lesenswert?

Funktionus Interuptus schrieb:
> - abändern, dass sie re-entrant wird (globale Variablen statt static),

das verstehen ich nicht. Globale variabelen und static haben das gleiche 
Verhalten, nur unterschiedliche Sichtbarkeit.

von Root (Gast)


Lesenswert?

Peter II schrieb:
> Funktionus Interuptus schrieb:
>> - abändern, dass sie re-entrant wird (globale Variablen statt static),
>
> das verstehen ich nicht. Globale variabelen und static haben das gleiche
> Verhalten, nur unterschiedliche Sichtbarkeit.

stimmt!

von Root (Gast)


Lesenswert?

Beim den Cortexen sind die Interrupt Handler ganz normale C-Funktionen 
und man kann sie definitiv auch direkt aufrufen.

Ob das Sinn macht ist was anderes.
Das ist wie in MSWord auch da kann man problemlos Rechtschreibfehler 
machen. Funktionieren tut Word dennoch. Wie jeder Vergleich hinkt auch 
dieser!

von Markus F. (mfro)


Lesenswert?

static gibt's in C zweimal: als Speicherklasse und als Linkage.
Und da ist durchaus ein Unterschied.

von Rolf M. (rmagnus)


Lesenswert?

Funktionus Interuptus schrieb:
> Also
>  - den Inhalt der ISR in eine separate Funktion packen,
>
>  - abändern, dass sie re-entrant wird (globale Variablen statt static),
>
>  - static inline machen, um in der ISR keinen Overhead für den
> Funktionsaufruf zu haben,
>
>  - an beiden Stellen aufrufen?
>
> Geht auch. War nur nicht meine Frage.

Löst aber dein Problem.

> Markus F. schrieb:
>> Möglicherweise geht sie von
>> Voraussetzungen aus, die nur in einem Exception-Kontext gegeben sind.
>
> Das sollte bei einer Timer-ISR nicht der Fall sein.

Die sollte normalerweise aber auch nicht außerhalb ihres Timer-Zyklus 
drankommen.

m.n. schrieb:
> Cyblord -. schrieb:
>> Ist aber sauberer und portabler.
>
> Das "sauberer" ist ja zweischneidig. Bei z.B. einem AVR8 bedingt ein
> Funktionsaufruf in einer ISR das komplette Sichern und Restaurieren
> aller Register: sauber und schön langsam!

Nur wenn Inlining nicht möglich ist. Und beim AVR würde ein manueller 
Aufruf einer ISR auch was anderes tun, als wenn es eine normale Funktion 
wäre.

> Hier geht es um einen STM32, wo erst gezeigt werden müßte, daß der
> normale Aufruf einer ISR nicht sauber ist.

Es fühlt sich für mich einfach falsch an, eine ISR aufzurufen, auch 
wenn's beim ARM vielleicht unfallfrei gehen sollte.

> Portabel? Kann eine ISR überhaupt portabel sein?

Nein, deshalb soll der Code ja nicht in die ISR.

Markus F. schrieb:
> static gibt's in C zweimal: als Speicherklasse und als Linkage.
> Und da ist durchaus ein Unterschied.

Inwiefern sollte dieses static sich in der Hinsicht anders verhalten? 
Auch hier sehe ich nicht, was das mit der Reentranz der Funktion zu tun 
haben sollte. Wie soll denn die Funktion reentrant werden durch 
entfernen des static?

von Axel S. (a-za-z0-9)


Lesenswert?

Rolf M. schrieb:
> hier sehe ich nicht, was das mit der Reentranz der Funktion zu tun
> haben sollte. Wie soll denn die Funktion reentrant wer

Sagen wir mal so: sie wird das nicht automatisch. Aber andererseits sind 
Funktionen, die statische lokale Variablen benutzen, mit Sicherheit 
nicht reentrant.

Viel interessanter wäre allerdings die Frage, ob diese Funktion 
tatsächlich reentrant sein muß. Wenn der Funktionsrumpf in der ISR 
ist, muß er normalerweise nicht reentrant sein, weil eine ISR, die von 
ihrem eigenen Interrupt unterbrochen wird, in jedem Fall ein Fehler ist 
(und auf manchen Plattformen auch gar nicht möglich).

Ob nun der Kern einer ISR, wenn er in eine normale Funktion ausgelagert 
wurde um auch als normale Funktion aufrufbar zu sein, reentrant sein 
muß, ist eine Frage der Programmlogik, die man ohne intime Kenntnis der 
Aufgabenstellung nicht beantworten kann. Aber im Normalfall würde ich 
erwarten, daß die Unterbrechung eben jeder Funktion durch den Interrupt 
nicht erwünscht ist und man deswegen geeignete Maßnahmen ergreifen 
wollen würde (etwa: den betreffenden Interrupt während der Ausführung 
der Funktion sperren).

von m.n. (Gast)


Lesenswert?

Funktionus Interuptus schrieb:
> Hintergrund der Aktion ist, daß ich einer Regelschleife ein paar Runden
> zur Stabilisierung geben will, bevor die Outputs aktiviert werden. In
> Pseudocode also so:
> ...

Ich nehme an, Du hast Deinen Code so umgesetzt, siehst, daß es 
funktioniert, und muß Dir über die zuletzt diskutierten Fehlerszenarien 
keine weiteren Gedanken machen.

von Rolf M. (rmagnus)


Lesenswert?

Axel S. schrieb:
> Rolf M. schrieb:
>> hier sehe ich nicht, was das mit der Reentranz der Funktion zu tun
>> haben sollte. Wie soll denn die Funktion reentrant wer
>
> Sagen wir mal so: sie wird das nicht automatisch. Aber andererseits sind
> Funktionen, die statische lokale Variablen benutzen, mit Sicherheit
> nicht reentrant.

Das kommt drauf an, wozu sie sie benutzen, aber die meisten sind es dann 
nicht.

> Ob nun der Kern einer ISR, wenn er in eine normale Funktion ausgelagert
> wurde um auch als normale Funktion aufrufbar zu sein, reentrant sein
> muß, ist eine Frage der Programmlogik, die man ohne intime Kenntnis der
> Aufgabenstellung nicht beantworten kann.

Der TE hat ja selbst geschrieben, er müsse die Funktion reentrant 
machen. Wenn er es nicht weiß, wer dann?
Meine Frage war aber auch nicht, ob sie wirklich reentrant sein muss, 
sondern wie die Umwandlung der static-Variablen in globale Variablen 
dazu führen soll, dass sie reentrant wird.

> Aber im Normalfall würde ich erwarten, daß die Unterbrechung eben jeder
> Funktion durch den Interrupt nicht erwünscht ist und man deswegen
> geeignete Maßnahmen ergreifen wollen würde (etwa: den betreffenden
> Interrupt während der Ausführung der Funktion sperren).

Sehe ich auch so.

von ich (Gast)


Lesenswert?

Funktionus Interuptus schrieb:
> ist es möglich, auf einem STM32 eine ISR einfach wie eine normale
> void-voi-Funktion aufrufen, also:

Üblicherweise unterscheiden sich ein Funktionaufruf und ein 
Interruptaufruf in der Sicherung von Prozessorstatus, Rücksprungadresse 
und Registern beim Einsprung und entsprechendem Rückladen beim 
Rücksprung. Es wird also auf deinen (unbekannten) Compiler ankommen, 
ggf. nur mit schmutzigen Inline-Assembler Tricks.

von (prx) A. K. (prx)


Lesenswert?

... schrieb:
> Üblicherweise unterscheiden sich ein Funktionaufruf und ein
> Interruptaufruf in der Sicherung von Prozessorstatus, Rücksprungadresse
> und Registern beim Einsprung und entsprechendem Rückladen beim
> Rücksprung.

Nur gehören die Cortex M in dieser Frage zu den "unüblichen" 
Architekturen. Da ist das nicht der Fall. Handler unterscheiden sich 
nicht von normalen Funktionen. Die Hardware ruft sie entsprechend auf.

> Es wird also auf deinen (unbekannten) Compiler ankommen,
> ggf. nur mit schmutzigen Inline-Assembler Tricks.

Nein,

: Bearbeitet durch User
von W.S. (Gast)


Lesenswert?

Funktionus Interuptus schrieb:
> Hintergrund der Aktion ist, daß ich einer Regelschleife ein paar Runden
> zur Stabilisierung geben will, bevor die Outputs aktiviert werden. In
> Pseudocode also so:

Also, ich verstehe deine Gedankengänge nicht, denn eine Regelschleife 
kann sich nur dann stabilisieren, wenn sie auch regeln KANN. Wenn du 
den Regler zuerst 1000 Runden lang trockenschwimmen läßt, ohne daß er 
wirken kann, dann wird er garantiert erstmal grandios in die Prärie 
galoppieren. Das ist unvermeidlich.

Also laß deinen Versuch bleiben und sieh lieber zu, daß du kurz vor dem 
Regler-Start die Anfangskonditionen mißt und in die Variablen deines 
Regelalgorithmus einträgst und auch einen sinnvollen Startwert für 
deinen Stellausgang vorsiehst. Dann den Regler starten und er wird ohne 
grandiosen Schlenker losgehen.

Funktionus Interuptus schrieb:
>     enableIRQs();

Sowas kommt von der AVR-Fraktion her, wo man generös nach Laune die 
Interrupts mal eben aus- und wieder einschaltet. Bei den Chips der 
ARM-Liga sollte man sich derartiges schlichtweg abgewöhnen. Dort 
bleiben die Interrupts ganz generell IMMER an und beim Inbetriebnehmen 
einer Peripherie löscht man lediglich die betreffenden Inerruptsignale 
in dieser Peripherie, bevor man im NVIC den Interrupt durchschaltet. 
Also immer ohne Herumtrampeln auf anderen Interrupts arbeiten!

W.S.

von (prx) A. K. (prx)


Lesenswert?

W.S. schrieb:
> bleiben die Interrupts ganz generell IMMER an und beim Inbetriebnehmen
> einer Peripherie löscht man lediglich die betreffenden Inerruptsignale
> in dieser Peripherie, bevor man im NVIC den Interrupt durchschaltet.

Interrupts global ganz zu sperren kann schon mal nötig sein. Meist 
reicht es aber aus, mit der laufenden Priorität zu arbeiten. Also über 
die MSRs BASEPRI und BASEPRI_MAX. Oder einzelne Interruptquellen zu 
sperren.

BASEPRI_MAX besitzt den Charme, ohne viel Zirkus reentrant zu sein. Man 
kann also mühelos in Funktionen Interrupts sperren, die schon gesperrt 
sind, ohne sie anschliessend versehentlich wieder einzuschalten. Mit den 
Enables vom NVIC ist das umständlicher.

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