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?
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.
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.
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.
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.
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.
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.
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?
@ 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!
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.
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_terr=1000;
2
#define eps 20
3
4
intctrl_init(void)
5
{
6
calcinitvars();
7
8
// Regelschleife ein paar Runden Zeit zur Stabilisierung geben
9
intn=0;
10
do
11
{
12
// IRQ manuell triggern, ISR manuell aufrufen oder so.
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.
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.
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.
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!
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!
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?
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).
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.
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.
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.
... 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,
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.
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.