Forum: Mikrocontroller und Digitale Elektronik ARM-GCC: ISR aus main() aufrufen


von Walter T. (nicolas)


Lesenswert?

Guten Abend zusammen,

ich habe eine ISR - SysTick_Handler(), die ich vor dem ersten Interrupt 
ein paar (hundert) mal aus main() aufrufen will, damit sich beim ersten 
Interrupt die internen Zustände soweit stabilisiert haben.

Auf den ersten Blick sieht die ISR im Listfile nicht anders als andere 
void-void-Funktionen aus. Würde die Funktion sich selbst per IRQ 
unterbrechen, wäre das extrem ungewollt - deswegen werden alle 
Interrupts erst später freigegeben.

Gibt es noch andere Nebenwirkungen, die ich berücksichtigen müßte?

von Gerhard (Gast)


Lesenswert?

Klingt für mich nach einer fragwürdigen Vorgehensweise - so nach dem 
Motto: Bevor ich mir jetzt überlege, wie die internen Zustände am Anfang 
aussehen, rufe ich lieber 'ne Funktion ein paar hundert mal auf...

Was spricht dagegen, die internen Zustände über eine separate Funktion 
ordentlich zu initialisieren?

von Oliver S. (oliverso)


Lesenswert?

... oder den systick ein paar hundert mal ticken zu lassen, bevor die 
einheitliche Funktion freigegeben wird?

Aber egal, das Ganze klingt tatsächlich sehr fragwürdig.

Oliver

von Walter T. (nicolas)


Lesenswert?

Gerhard schrieb:
> Was spricht dagegen, die internen Zustände über eine separate Funktion
> ordentlich zu initialisieren?

Daß die internen Zustände intern sind und nirgendwo sonst benötigt 
werden.

Gerhard schrieb:
> Klingt für mich nach einer fragwürdigen Vorgehensweise

Ich halte inkrementell-iterative Lösungsverfahren für eine valide 
Vorgehensweise. Tatsächlich ist mein Weg gerade der aus der 
Gegenrichtung: Ich hatte bis heute nachmittag eine 
Initialisierungfunktion mit grob zwei Bildschirmseiten Quelltext mit 
etlichen Fallunterscheidungen, die sich bei einem 
inkrementell-iterativen Lösungsverfahren in wenige Zeilen Wohlgefallen 
auflösten. Und netterweise ist die neue Initialisierung inhaltlich zu 
100% schon im SysTick-Handler enthalten.

Also gibt es momentan eine Funktion, die sowohl von main() als auch vom 
SysTick_Handler() aufgerufen wird. Geht auch. Aber es wirft trotzdem die 
Frage auf, ob man nicht einfach SysTick_Handler() direkt aufrufen kann, 
oder ob wichtige Gründe dagegen sprechen.

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

Walter T. schrieb:
> Also gibt es momentan eine Funktion, die sowohl von main() als auch vom
> SysTick_Handler() aufgerufen wird. Geht auch.

Kann aber auf dem AVR die ISR ziemlich ausbremsen.

> Aber es wirft trotzdem die Frage auf, ob man nicht einfach
> SysTick_Handler() direkt aufrufen kann, oder ob wichtige Gründe dagegen
> sprechen.

Eine ISR wird mit reti beendet, welches die Interrupts einschaltet.

von NichtWichtig (Gast)


Lesenswert?

Der Unterschied von normalen Routinen und ISR Routine ist Dir bekannt ?

von Walter T. (nicolas)


Lesenswert?

Rolf M. schrieb:
> Kann aber auf dem AVR die ISR ziemlich ausbremsen.

Genau, und auf dem STM32 ist es auch nicht kostenlos.

Rolf M. schrieb:
> Eine ISR wird mit reti beendet, welches die Interrupts einschaltet.

Genau diesen Unterschied scheint es hier nicht zu geben. Die ISRs 
benötigen keinerlei Attribute oder Makros. Wobei ich mich zu erinnern 
meine, dass es kein generelles Problem gab, Funktionen mit reti auch 
"normal" aufzurufen.

von Rolf M. (rmagnus)


Lesenswert?

Walter T. schrieb:
> Rolf M. schrieb:
>> Kann aber auf dem AVR die ISR ziemlich ausbremsen.
>
> Genau, und auf dem STM32 ist es auch nicht kostenlos.

Oh, ich hatte irgendwie AVR gelesen statt ARM. Hätte mir eigentlich 
spätestens bei SysTick_Handler() auffallen müssen, weil das 
STM32-typisch ist.

von Nop (Gast)


Lesenswert?

Walter T. schrieb:

> Gibt es noch andere Nebenwirkungen, die ich berücksichtigen müßte?

Nein, Du solltest Du den Systick nicht vorher aktivieren. Dazu mußt Du 
insbesondere schauen, daß der nicht schon im Startup vor main() 
eingerichtet wird. Aber ansonsten ist die ISR auf ARM eine völlig 
normale C-Funktion.

Daß das vom Konzept her grober Pfusch ist und man das deswegen ganz 
grundsätzlich nicht so macht, wurde ja bereits erwähnt.

von Walter T. (nicolas)


Lesenswert?

Generell fielen mir drei Wege ein, den Aufruf der ISR durch main() für 
den vorgesehenen Fall zu vermeiden. Zu denen habe ich aber keinerlei 
Fragen.

Mich interessiert hauptsächlich, welche Gründe dagegensprechen 
(könnten), eine ISR aus main() aufzurufen.



Rolf M. schrieb:
> Oh, ich hatte irgendwie AVR gelesen statt ARM.

Passiert ;-)

von John Doe (Gast)


Lesenswert?

Nop schrieb:
> Walter T. schrieb:
>
>> Gibt es noch andere Nebenwirkungen, die ich berücksichtigen müßte?
>
> Nein, Du solltest Du den Systick nicht vorher aktivieren. Dazu mußt Du
> insbesondere schauen, daß der nicht schon im Startup vor main()
> eingerichtet wird. Aber ansonsten ist die ISR auf ARM eine völlig
> normale C-Funktion.

Und wen interessiert, warum das funktioniert, kann das hier nachlesen:
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/Babefdjc.html

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


Lesenswert?

Walter T. schrieb:
> ich habe eine ISR - SysTick_Handler(), die ich vor dem ersten Interrupt
> ein paar (hundert) mal aus main() aufrufen will, damit sich beim ersten
> Interrupt die internen Zustände soweit stabilisiert haben.

Das klingt wie eine blöde Idee <tm>

Was soll sich da "stabilisieren"? Initialisiere deine static Variablen 
(das meinst du wohl mit "interne Zustände") einfach korrekt. Und fertig.


Walter T. schrieb:
> Ich halte inkrementell-iterative Lösungsverfahren für eine valide
> Vorgehensweise.

Ich nicht. Insbesondere bezweifle ich, daß das überhaupt eine Lösung 
darstellt. Woher nimmst du die Gewißheit, daß die "internen Zustände" 
nach 100 oder 1000 Aufrufen "stabilisiert" sind? Woher die Gewißheit, 
daß sie es vorher nicht sind?

Als Programmierer mußt Du doch wissen, welche Zustände "stabil" sind. 
Also initialisiere das System einfach in einem solchen Zustand.

von Bauform B. (bauformb)


Lesenswert?

Jetzt mal unabhängig davon, ob das ein sinnvolles Verfahren ist. Stellt 
euch einfach vor, es gibt eine ganz normale winzige ISR und zweitens ein 
ganz normales Unterprogramm mit diesem speziellen Verfahren. Natürlich 
kann das Unterprogramm von main() aufgerufen werden. Es kann aber auch 
von der ISR aufgerufen werden. Das funktioniert doch auf jeden Fall?

Wenn dann die ISR nur noch aus diesem Aufruf besteht, sollte der 
Compiler das bis auf Null Overhead optimieren. Evt. kann man ihm einen 
Tipp geben, mit inline oder so.

von Walter T. (nicolas)


Lesenswert?

Guten Morgen,

da waren jetzt einige hilfreiche Antworten, und einige Antworten, die es 
noch werden können.

Nop schrieb:
> Aber ansonsten ist die ISR auf ARM eine völlig
> normale C-Funktion.

John Doe schrieb:
>
> Und wen interessiert, warum das funktioniert, kann das hier nachlesen:
> 
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/Babefdjc.html

Danke.


Axel S. schrieb:
> Woher nimmst du die Gewißheit, daß die "internen Zustände"
> nach 100 oder 1000 Aufrufen "stabilisiert" sind?

Aus dem gleichen Grund, aus dem ich die Gewißheit nehme, daß sie es 
später im Betrieb auch sein werden. Stabilitäts- und Konvergenzkriterien 
sind doch keine Raketenwissenschaft. Vor allem bei FIR-Systemen.

Axel S. schrieb:
> Woher die Gewißheit, daß sie es vorher nicht sind?

Das weiß ich tatsächlich nicht. Schlimmstenfalls vergeude ich also 
etliche hundert Aufrufe, obwohl das System schon im zweiten Schritt 
konvergiert ist. Es gibt aber schlimmeres. Das System startet so immer 
noch tausende Male schneller, als wenn ich erst etliche Male den 
SysTick-Interrupt abwarten müßte.


Nop schrieb:
> Daß das vom Konzept her grober Pfusch ist und man das deswegen ganz
> grundsätzlich nicht so macht, wurde ja bereits erwähnt.

Erwähnt ja, aber nicht begründet. Warum ist es Pfusch?

von Wolfgang (Gast)


Lesenswert?

Walter T. schrieb:
> Auf den ersten Blick sieht die ISR im Listfile nicht anders als andere
> void-void-Funktionen aus.
> ...
> Gibt es noch andere Nebenwirkungen, die ich berücksichtigen müßte?

Bei einem Interrupt wird zusätzlich zur Rücksprungadresse automatisch 
das Statusregister gesichert und mit der Rückkehr aus der Interrupt 
Routine wieder zurück gelesen.
Das sollte auch aus dem Listfile hervor gehen - k.a. wie der bei dir 
aussieht.

von Dr. Sommer (Gast)


Lesenswert?

Wolfgang schrieb:
> sollte auch aus dem Listfile hervor gehen

Nein, denn das macht der Prozessor automatisch, und dafür gibt es in der 
Software keine Instruktionen.

Kannst du nicht die Werte, welche die internen Zustände  nach dem 
"einschwingen" annehmen sollen, einfach direkt in die Initialisierung 
der jeweiligen Variablen schreiben? Dann wird das vom Startup-Code super 
effizient direkt aus dem Flash kopiert.

von Stefan F. (Gast)


Lesenswert?

Walter T. schrieb:
> Mich interessiert hauptsächlich, welche Gründe dagegensprechen
> (könnten), eine ISR aus main() aufzurufen.

Du doktorst damit an Symptomen herum, anstatt die Problemursache zu 
beheben. Mikrocontroller sind doch keine Motoren, die warm laufen 
müssen, bevor man sie belasten darf!

Wenn du vor der Programmausführung einen bestimmten Zustand brauchst, 
dann stelle ihn gezielt her. Das ganze RAM und alle I/O Register sind 
direkt beschreibbar.

von m.n. (Gast)


Lesenswert?

Walter T. schrieb:
> Es gibt aber schlimmeres. Das System startet so immer
> noch tausende Male schneller, als wenn ich erst etliche Male den
> SysTick-Interrupt abwarten müßte.

Eine ISR isr eine normale Funktion, die auch direkt aufgerufen werden 
kann. Allein auf Seiteneffekte sollte man aufpassen.
Man kann auch den Systick auf 10 µs einstellen, damit die Funktion 
häufiger aufgerufen wird.
Such Dir etwas aus.

von John Doe (Gast)


Lesenswert?

Wolfgang schrieb:
> Walter T. schrieb:
>> Auf den ersten Blick sieht die ISR im Listfile nicht anders als andere
>> void-void-Funktionen aus.
>> ...
>> Gibt es noch andere Nebenwirkungen, die ich berücksichtigen müßte?
>
> Bei einem Interrupt wird zusätzlich zur Rücksprungadresse automatisch
> das Statusregister gesichert und mit der Rückkehr aus der Interrupt
> Routine wieder zurück gelesen.
> Das sollte auch aus dem Listfile hervor gehen - k.a. wie der bei dir
> aussieht.

Warum liest Du nicht einfach bei ARM - den Link habe ich oben gepostet - 
nach, wie es funktioniert?
Dann würdest Du nicht so einen Unsinn schreiben.

von Walter T. (nicolas)


Lesenswert?

Ich habe ein FIR-Filter n-ter Ordnung, das auf einen Sensorwert 
angewendet werden soll. Nehmen wir der Einfachheit an, es wäre der ADC. 
Wann ist das Filter eingeschwungen? Wenn in allen z bis z^{-n} der 
korrekte Startwert steckt.

Dazu fallen mir spontan mehrere Lösungen ein:

a) Mir das Filter genau anschauen, die n Werte global machen, eine 
Initialisierungsfunktion schreiben, die die n Startwerte korrekt für den 
ADC-Wert zum Initialisierungszeitpunkt ausrechnet und einträgt, und dann 
SysTick aktivieren. Bei FIR ist das kein Problem, nur Schreibarbeit. Bei 
IIR etwas mehr Schreibarbeit, aber auch kein generelles Problem. 
Allerdings ist hier schon allgemeinen Fall das Lösen eines 
Gleichungssystems nötig.

b) SysTick_Handler() einfach n mal mit dem ADC-Wert der Initialisierung 
durchlaufen lassen und wissen, daß das Filter eingeschwungen sein wird. 
Bei IIR abweisend m mal, bis die Fehlerschranke unterschritten ist (m 
läßt sich vorberechnen).

c...f) Andere Wege finden, daß die Funktion in SysTick_Handler() für n 
Schritte schneller ausgeführt wird als üblich. Zähler verkürzen, IRQs 
manuell setzen, Funktion indirekt aufrufen, indem sie einmal inline und 
einmal direkt aufrufbar etc.


Welchen konkreten Vorteil haben jetzt a), c...f) gegenüber b), das 
letztes als "Pfusch" oder "herumdoktorn an den Symptomen" bezeichnet 
werden muß, während die anderen Lösung als "Behebung des Problems" 
gelten?

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Danke. Jetzt haben wir eine plausible Erklärung, warum du die ISR 
wiederholt aufrufen willst. Das es technisch geht, war eh schon klar 
(hoffe ich).

von Dr. Sommer (Gast)


Lesenswert?

Ist es nicht beim FIR-Filter so, dass der sich lediglich die n letzten 
Eingangswerte merkt? In deinem initialen Lauf des Systick wirst du wohl 
davon ausgehen, dass die anfangs alle 0 oder auf einem fixen Wert sind. 
Kannst du nicht ganz schlicht das Array vorbelegen:
1
int X [N] = {42, 42, 42, 42, ... };
Wenn "X" eine "static"-Variable es geht das genau so. Wenn es C++ und 
ein Klassen-Member ist entweder auch so, oder eine Meta-funktion 
schreiben die das in Abhängigkeit von "n" automatisch macht. Eine 
Initialisierungsfunktion ist hier eh unnötig.

Beim Hochfahren die ISR wiederholt aufrufen ist hauptsächlich langsam 
und unelegant. Wenn du später in der ISR noch mehr Dinge tun möchtest 
gibt's ein Chaos...

von Walter T. (nicolas)


Lesenswert?

Dr. Sommer schrieb:
> Kannst du nicht ganz schlicht das Array vorbelegen:

Klar. Das entspricht Variante a) aus meinem obigen Post. Dafür muß ich 
nur das Array global machen, damit es neben der ISR von einer 
Initialisierungs-Funktion beschrieben werden kann.


Dr. Sommer schrieb:
> Wenn du später in der ISR noch mehr Dinge tun möchtest
> gibt's ein Chaos...

Nur dann, wenn ich Dinge darin tun will, die vom exakten Zeitstempel 
abhängen. Aber stimmt: Ab diesem Punkt würde es unelegant.


Meine Frage ist: Was ist an a) jetzt so viel besser als b), das diesen 
Mehraufwand rechtfertigt?

von Stefan F. (Gast)


Lesenswert?

Walter T. schrieb:
> Was ist an a) jetzt so viel besser als b), das diesen
> Mehraufwand rechtfertigt?

Es sieht ordentlicher aus, hat weniger den Character eines billigen 
Workarounds.

Wenn dir die Lösung a besser gefällt, dann mach das halt. Nur darfst du 
dich dann auch nicht beklagen, wenn später jemand fragt "was hast du dir 
denn dabei gedacht?". Uns hast du es nachvollziehbar erklärt.

von Dr. Sommer (Gast)


Lesenswert?

Walter T. schrieb:
> Klar. Das entspricht Variante a) aus meinem obigen Post. Dafür muß ich
> nur das Array global machen

Ist es momentan "static" innerhalb der ISR? Auch dann kannst du es genau 
so in der ISR initialisieren. Der "Aufwand", es global zu machen, ist 
gar nicht nötig.

Walter T. schrieb:
> Meine Frage ist: Was ist an a) jetzt so viel besser als b), das diesen
> Mehraufwand rechtfertigt?

Es startet schneller, es ist eine korrekte Initialisierung im Sinne der 
Sprache, es entfällt für den Leser die Überraschung dass die ISR ohne 
Interrupt aufgerufen wird...


Falls es sich um C++ handelt, kannst du folgendermaßen ein Array mit dem 
gleichen Wert vorbelegen:
1
#include <utility>
2
#include <array>
3
#include <cstddef>
4
5
template <typename T, std::size_t N, std::size_t... I>
6
constexpr std::array<T, N> genArray (const T& init, std::index_sequence<I...>) {
7
  return {{ (I, init)... }};
8
}
9
10
template <typename T, std::size_t N>
11
constexpr std::array<T, N> genArray (const T& init) {
12
  return genArray<T, N> (init, std::make_index_sequence<N> {});
13
}
14
15
std::array<int,20> X = genArray<int, 20> (42);

So kannst du globale Variablen, Member-Variablen oder auch 
"static"-Variablen einer ISR initialisieren:
1
class MyFirFilter {
2
  public:
3
    constexpr MyFirFilter () : X (genArray<int,20> (42)) {}
4
    std::array<int,20> X;
5
};
6
7
MyFirFilter myFirFilter;
8
9
void ISR () {
10
  static std::array<int,20> X = genArray<int, 20> (42);
11
}

Es muss nichts global sein, es gibt keine Initialisierungs-Funktion, der 
Compiler berechnet das Speicherlayout und der Startup-Code muss es nur 
noch in den RAM kopieren.

Das "genArray" kann man auch etwas abwandeln um unterschiedliche Werte 
für die Einträge zu berechnen. Auch dann muss das Array nicht global 
sein. In C geht das dann nicht ganz so praktisch; aber auch hier kannst 
du die static-Variable direkt initialisieren:
1
void ISR () {
2
  static int X [5] = { 42, 42, 42, 42, 42 };
3
}
Hat letztendlich den gleichen Effekt, es ist keine 
Initialisierungsfunktion und keine globale Variable nötig.

von El Ef (Gast)


Lesenswert?

Walter T. schrieb:
> Ich habe ein FIR-Filter n-ter Ordnung, das auf einen Sensorwert
> angewendet werden soll. Nehmen wir der Einfachheit an, es wäre der ADC.
> Wann ist das Filter eingeschwungen? Wenn in allen z bis z^{-n} der
> korrekte Startwert steckt.

Was ist denn der korrekte Startwert? Was konkret macht denn die 
Initialisierung? Warum nicht nur zyklische Aufrufe? Ich verstehe dein 
konkretes Problem hier nicht, insbesondere

Walter T. schrieb:
> . Das System startet so immer noch tausende Male schneller, als wenn ich
> erst etliche Male den SysTick-Interrupt abwarten müßte.

bei äquidistanten Abtastwerten.

von W.S. (Gast)


Lesenswert?

Walter T. schrieb:
> Welchen konkreten Vorteil haben jetzt a), c...f) gegenüber b)

Also, du hast irgend eine Quelle für Daten (z.B. ADC), und diese Daten 
müssen gefiltert werden. Soweit ja in Ordnung.

Prinzipiell kannst du nicht wissen, welchen numerischen Wert diese Daten 
haben, denn sie können ja in ihrem Wertebereich beliebig herumschwanken, 
was nicht von deinem µC-System, sondern von der Umwelt bestimmt ist.

Wäre das nicht so, dann könntest du dir das Erfassen dieser Daten ja 
einsparen. Allerdings meine ich, daß es für diese Daten durchaus einen 
mittleren Erwartungswert geben dürfte - und den wirst du sicherlich 
kennen (wenigstens so einigermaßen).

Deshalb wäre es schlichtweg der korrekte Weg, zum Initialisieren das 
Feld z[n], also die gespeicherten Daten mit dem Erwartungswert zu füllen 
und dann schlichtweg deinen Timertick einzuschalten - ohne die ISR 
jemals aus dem Grundprogramm aufrufen zu wollen.

Walter T. schrieb:
> die n Werte global machen

Das mußt du sowieso, denn diese Variablen können nicht lokal zur ISR 
sein.

Walter T. schrieb:
> Wann ist das Filter eingeschwungen? Wenn in allen z bis z^{-n} der
> korrekte Startwert steckt.

Es gibt keinen korrekten Startwert, bestenfalls gibt es einen 
Erwartungswert. Siehe oben.

Und ein FIR-Filter ist niemals eingeschwungen, sondern die Daten sind 
"eingeschwungen". Das ist ein prinzipieller Unterschied zum IIR Filter 
und zu allen analogen Filtern, die in ihrer Wesensart immer IIR Filter 
sind und rein theoretisch eine unendlich lange Erinnerungszeit haben.

Also fülle dein z[n] einfach in der Init-Routine mit deinem 
Erwartungswert und fertig. Das Filter hat ja nur eine Erinnerungszeit 
von n und läuft schon beim allerersten echten Interrupt von da aus 
stracks in die richtige Richtung.

W.S.

von Walter T. (nicolas)


Lesenswert?

W.S. schrieb:
> Das mußt du sowieso, denn diese Variablen können nicht lokal zur ISR
> sein.

Warum nicht?

von Stefan F. (Gast)


Lesenswert?

Walter T. schrieb:
> W.S. schrieb:
>> Das mußt du sowieso, denn diese Variablen können nicht lokal zur ISR
>> sein.
>
> Warum nicht?

Vielleicht sind hier static Variablen innerhalb der Funktion gemeint.

von S. R. (svenska)


Lesenswert?

Walter T. schrieb:
> ich habe eine ISR - SysTick_Handler(), die ich vor dem ersten Interrupt
> ein paar (hundert) mal aus main() aufrufen will, damit sich beim ersten
> Interrupt die internen Zustände soweit stabilisiert haben

Mache es anders: Schreibe deinen Filter in eine eigene Funktion, die du 
sowohl vom SysTick_Handler() als auch von main() aus aufrufst. 
Unterschiede zwischen normalen Funktionen und ISRs fallen dann nicht ins 
Gewicht.

Der Kontext, in dem die Funktion aufgerufen wird (z.B. welcher Stack 
aktiv ist o.ä.) ist dann zwar unterschiedlich, aber das ist in der Regel 
kein Problem.

von Walter T. (nicolas)


Lesenswert?

Okay, wir sind wieder auf dem Stand "ISR aus main() aufrufen ist böse 
und muß unbedingt vermieden werden - egal wie aufwendig der Workaround 
ist!"

Woher kommt diese heftige Ablehnung? Normal entsteht sie ja nicht 
grundlos.

Was ist daran prinzipiell unschön, furchbar, abstoßend, gefährlich, 
eklig oder verwerflich? Warum ist es Pfusch?

Bitte nicht "Das ist Pfusch, weil <Synonym für Pfusch>", sondern die 
Gründe interessieren mich tatsächlich.

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Das hast du schon mehrmals gefragt und mehrere Antworten erhalten. lass 
gut sein, das Thema ist zu ende diskutiert. Aber jetzt kann es nur noch 
schlecht werden.

von Walter T. (nicolas)


Lesenswert?

Stefanus F. schrieb:
> [...] und mehrere Antworten erhalten

Ich habe neue Synonyme für "Pfusch" gelernt. Das ist nicht nichts, aber 
auch nicht das, was ich mir erhofft habe. Es gab drei echte Ansätze der 
Erklärung:

Rolf M. schrieb:
> Eine ISR wird mit reti beendet,

Das stimmt, trifft aber auf STM32 nicht zu.

Die anderen beiden (die zweite ist von mir umschrieben):

Dr. Sommer schrieb:
> [...] langsam und unelegant.

Dr. Sommer schrieb:
> [wenn die ISR komplizierter wird, wird das kompliziert]

Sind beides echte Begründungen, aber nicht unbedingt ausreichend, um 
eine allergische Reaktion dieses Ausmaßes zu verstehen.

Es muß also noch stärkere Gründe geben.

von Stefan F. (Gast)


Lesenswert?

Du hast meine Begründung übersehen:

> Es sieht ordentlicher aus, hat weniger den Character
> eines billigen Workarounds.

Ist auch kein starker Grund.

von Dr. Sommer (Gast)


Lesenswert?

Walter T. schrieb:
> Sind beides echte Begründungen, aber nicht unbedingt ausreichend, um
> eine allergische Reaktion dieses Ausmaßes zu verstehen.

Beim Programmieren gibt es nicht für alles 100% klare knallharte 
Argumente. Viele Dinge macht man "nach Gefühl", welches sich mit 
Erfahrung bildet. Wenn das Programm weiter entwickelt wird und wächst, 
freut man sich über eine klare logische Struktur. Eine ISR einfach auf 
Verdacht 1000 mal aufzurufen (warum 1000 und nicht 999?) macht das 
Programm undurchsichtiger und für Leser, welche gängige Vorgehensweisen 
erwarten, schlechter lesbar. Man erwartet, dass eine Initialisierung 
über C-Variablen-Initialisierung, ggf. eine separate Funktion, oder 
Konstruktor gemacht wird. Dort sieht man dann auch klar und eindeutig, 
was die Startwerte sind. Die ISR 1000x aufzurufen verschleiert das - es 
ist unklar, was überhaupt der Ausgangszustand ist nach den 1000 
Aufrufen. Es macht den Eindruck, dass du einfach 1000x drauf haust bis 
es "funktioniert". Ineffizient ist es sowieso.

Allergische Reaktionen kommen immer, wenn man eine gewöhnliche Aufgabe 
(Initialisierung) auf eine völlig unerwartete Art macht, ohne einen 
ersichtlichen großen Vorteil (Sparen von 5 Zeilen ist keiner). Solchen 
Code möchte niemand warten! Daher fühlen sich viele fast schon 
beleidigt, wenn jemand knallharte Argumente für die normale gängige und 
von der Sprache vorgesehene Vorgehensweise verlangt und implizit damit 
droht, einen irgendwann später mit derart unerwartet strukturiertem Code 
zu konfrontieren.

von Walter T. (nicolas)


Lesenswert?

Stefanus F. schrieb:
> Du hast meine Begründung übersehen:
>
>> Es sieht ordentlicher aus, hat weniger den Character
>> eines billigen Workarounds.

Diese Sätze lesen sich für mich wie: "Das ist kein <freundlicheres 
Synonym für Pfusch>, weil es nicht den Charakter eines <anderes 
freundlicheres Synonym für Pfusch> hat". Das ist wahrscheinlich nicht 
böse gemeint, aber hilft nicht unbedingt beim Verständnis.

Mein Fliesenleger begründet anders: "Wenn ich das uneben lege, ist das 
Pfusch, weil das Auge bei geraden Linien leider schon recht kleine 
Abweichungen erkennen kann." Oder: "Wenn ich das nicht in einer leichten 
Neigung zum Rand lege, ist das Pfusch, weil das Wasser nicht ablaufen 
kann, und sich Lachen auf dem Boden bilden. An den Stellen wächst dann 
sehr schnell Moos in den Fugen." Vielleicht sind Fliesenleger aber auch 
einfach von sich aus sehr geduldige Erklärer oder ich habe den besten 
Fliesenleger der Welt getroffen.

: Bearbeitet durch User
von Dr. Sommer (Gast)


Lesenswert?

PS: guter Code sollte so selbstdokumentierend sein, dass man kaum 
Kommentare braucht. Der Kommentar, der erläutert, dass genau 1000 
ISR-Aufrufe das gewünschte Ergebnis haben (welches?), dürfte länger 
sein, als der gesparte Code.

Wenn du ein Beispiel für die ja vorher vorhandene normale/explizite 
Initialisierung hast, könnte man dir ggf. helfen, das kompakter zu 
schreiben.

von Stefan F. (Gast)


Lesenswert?

Walter T. schrieb:
> Diese Sätze lesen sich für mich wie: "Das ist kein <freundlicheres
> Synonym für Pfusch>, weil es nicht den Charakter eines <anderes
> freundlicheres Synonym für Pfusch> hat". Das ist wahrscheinlich nicht
> böse gemeint, aber hilft nicht unbedingt beim Verständnis.

Ja stimmt. Der Dr. Sommer hat meine Gedanken dazu in 
Beitrag "Re: ARM-GCC: ISR aus main() aufrufen" besser 
auf den Punkt gebracht.

von Walter T. (nicolas)


Lesenswert?

Dr. Sommer schrieb:
> Eine ISR einfach auf
> Verdacht 1000 mal aufzurufen (warum 1000 und nicht 999?) macht das
> Programm undurchsichtiger und für Leser, welche gängige Vorgehensweisen
> erwarten, schlechter lesbar. Man erwartet, dass eine Initialisierung
> über C-Variablen-Initialisierung, ggf. eine separate Funktion, oder
> Konstruktor gemacht wird. Dort sieht man dann auch klar und eindeutig,
> was die Startwerte sind. Die ISR 1000x aufzurufen verschleiert das - es
> ist unklar, was überhaupt der Ausgangszustand ist nach den 1000
> Aufrufen. Es macht den Eindruck, dass du einfach 1000x drauf haust bis
> es "funktioniert". Ineffizient ist es sowieso.

Dieses Argument verstünde ich, träfe das auf den vorliegenden Fall zu. 
Wenn die Begründung lautet: "Ich benötige beim Start N Aufrufe der 
Funktion a(), bis Variable b die Fehlerschranke epsilon unterschritten 
hat", sollte das aber doch ausreichen?

Dr. Sommer schrieb:
> an erwartet, dass eine Initialisierung
> über C-Variablen-Initialisierung, ggf. eine separate Funktion, oder
> Konstruktor gemacht wird.

Bei einer klassischen Initialisierung von zur Compilezeit bekannten 
Variablen  verstehe ich das ja. Aber bei einer Ermittlung von 
Startwerten, die erst zur Laufzeit berechnet werden können, hätte ich 
erwartet, daß da das Kriterium Nr. 1 lautet: "So wenig fehlerträchtig 
wie möglich. Dafür opfere ich sogar gerne leichten Herzens einmalig ein 
paar hundert Takte." Und wenn die am wenigsten fehlerträchtige 
Möglichkeit darin besteht, einfach die selbe Funktion zur 
Initialisierung wie zur Laufzeit zu nutzen, sollte ich freudestrahlend 
in die Hände klatschen und rufen: "Wieder eine Fehlermöglichkeit 
weniger!".


Dr. Sommer schrieb:
> Beim Programmieren gibt es nicht für alles 100% klare knallharte
> Argumente. Viele Dinge macht man "nach Gefühl", welches sich mit
> Erfahrung bildet.

**seufz** Du kannst mit Gefühlen umgehen, weil Du die Erfahrung hast. 
Ich kann mich nur an Argumenten orientieren. Ich kann mir nur ein Blatt 
Papier nehmen und die für mich vorstellbaren Varianten skizzieren und 
ihre Vor- und Nachteile gegenüberstellen.

Und ich denke alle Mitdiskutaten sind sich einig: "Mindestens vier Leute 
im Internet finden diese Lösung merkwürdig" ist nicht unbedingt ein 
Argument, das für sich ein valider Punkt ist. Der Grund, warum diese 
vier Leute das merkwürdig finden, kann es aber durchaus sein.

von Gerhard (Gast)


Lesenswert?

Walter, ich versuche mal, diese gefühlsmäßige Abneigung rational zu 
begründen.

Ich entwickle beruflich sicherheitskritische Software (Luftfahrt). In 
den wenigen Fällen, wo wir noch in C "händisch" entwickeln, d.h. ein 
Mensch Source-Code schreibt, verfolgen wir gemäß den etablierten 
Standards einen ganz strengen Top-down-Ansatz.

Das bedeutet, wir erhalten exakte Anforderungen, WAS das System tun soll 
(funktionale Anforderungen) und wie gut (d.h. präzise, schnell, etc.) es 
das tun soll (qualitative Anforderungen).

Für diese Systemanforderungen (Requirements) überlegen wir uns dann 
vorläufig eine grobe Architektur (HW/SW). Mit diesen Annahmen teilen wir 
die Anforderungen dann auf in solche, die die Hardware betreffen und 
solche, die die Software betreffen. Das ist natürlich ein iteratives 
Vorgehen, welches auch den Kunden einbezieht und in seinem Verlauf genau 
dokumentiert wird.

Für die Software (und auch Hardware, ist aber hier kein Thema) werden 
die Anforderungen dann in immer tiefere Ebenen weiterentwickelt. Dabei 
wird die Softwarearchitektur ebenfalls immer detaillierter beschrieben 
und die ganze Zeit gegen die Anforderungen sowie Kompatibilität mit der 
Hardware kontrolliert.

Zum Schluß beschreibt die Softwarearchitektur neben einem generellen 
Ablaufdiagramm und globalen Erwägungen wie Speicherbedearf, Stacktiefe, 
I/O-Register, Bootloader, Initialisierung etc. jede einzelne Funktion.

Die tiefste Ebene der Anforderungen (low-level Requirements) ist dann so 
detailliert, dass man daraus direkt den Quelltext schreiben kann. In 
unserer Firma darf es z.B. keine einzige Zeile Quellcode geben, die sich 
nicht direkt zu einem Requirement verfolgen lässt. Tatsächlich schreiben 
wir die Verweise zu den Requirements als Kommentar in den Quellcode.

Für einfache Funktionen beschreiben die Requirements beispielsweise: 
Ein- und Ausgabewerte, Wertebereiche, Auflösung, maximale 
Ausführungszeit, Verhalten bei Grenz- und Sonderfällen, Rückgabe und 
Behandlung von Fehlern,  Initialisierung etc.

Die Low-Level-Requirements sind dabei so formuliert, dass ich dagegen 
ganz einfach Test-Cases schreiben kann, die sich meist auf eine bis drei 
Codezeilen beschränken.

Der Vorteil an dem Vorgehen ist nun, dass ich auf jeder Ebene 
Verifikation durchführen kann - d.h. Quelltext gegen 
low-level-requirements, low-level-Requirements gegen 
high-level-Requirements und so weiter, bis ich wieder oben bei der 
Systemebene angekommen bin (V-Modell).

Damit habe ich eine objektiv gerechtfertigte Zuversicht, dass der Code 
korrekt ist.

Wenn man sich nicht an dieses Vorgehen hält, dann ist es dagegen sehr 
wahrscheinlich, dass man zahlreiche Fehler einbaut, weil man das 
Verhalten des Codes ausschließlich auf der Systemebene prüft (Gerät 
macht aus Sicht des Benutzers, was es soll), sich bei diesen Tests aber 
naturgemäß auf einen ganz begrenzten Bereich beschränken muss.

Fehler wie das Aufhängen eines Gerätes beim Roll-Over der GPS-Woche 
werden durch dieses strukturierte Vorgehensweise vermieden, weil man 
sich zwangsläufig mit den Details der Datenstruktueren auseinandersetzen 
und alle Sonderfälle behandeln (und testen) muss.

Diese Vorgehensweise ist mir mitterweile so in Fleisch und Blut 
übergegangen, dass ich allerdisch reagiere, wenn ein unstrukturierter 
Ansatz vergfolgt wird.

Das Herumbasteln im Quellcode beispielsweise (ISR in einer Schleife ein 
paar hundert mal aufrufen), bis sich aus Benutzersicht das gewünschte 
Verhalten einstellt (Filter ist bei Gerätestart "eingeschwungen"), ist 
ein Beispiel dafür, wie wir es in der Luftfahrt nicht machen würden.

Das Gegenbeispiel wäre das Betrachten der Frage, wie das Filter sich 
beim Einschalten verhalten soll und warum (welche System-Requirements 
beschreiben das? Wenn es sie nicht gibt, Meldung an den Kunden mit der 
Bitte um Ergänzung).

Wenn man dieses Wissen hat, kann man sich beim Herunterbrechen der 
Requirements überlegen, an welcher Stelle man die Initialisierung 
durchführt. Das hängt dann unter anderem davon ab, ob die 
Initialisierung auch während der Laufzeit gebraucht wird 
(Watchdog-Reset).

Meine Kritik richtet sich also weniger gegen die konkrete 
Implementierung (Aufrufen der ISR in einer Schleife), sondern mehr gegen 
die Vorgehensweise, die zu dieser Implementierung führt.

von Dr. Sommer (Gast)


Lesenswert?

Walter T. schrieb:
> "Ich benötige beim Start N Aufrufe der Funktion a(), bis Variable b die
> Fehlerschranke epsilon unterschritten hat", sollte das aber doch
> ausreichen?

Ich würde da gerne eine Begründung sehen. Und natürlich, welche Werte da 
am Ende genau raus kommen. Also genau die, die man bei einer expliziten 
Initialisierung auch hinschreiben würde.

Walter T. schrieb:
> Aber bei einer Ermittlung von Startwerten, die erst zur Laufzeit
> berechnet werden können,

Wieso erst zur Laufzeit? Basieren die auf einer Eingabe? Wie kommt eine 
Eingabe zustande, wenn doch bis dato die Interrupts aus sind?

Walter T. schrieb:
> "Wieder eine Fehlermöglichkeit weniger!".

Dafür eine Möglichkeit mehr: jemand schreibt noch mehr Code in die ISR. 
Bei einer Timer-ISR nicht besonders abwegig.

Walter T. schrieb:
> Mindestens vier Leute im Internet finden diese Lösung merkwürdig" ist
> nicht unbedingt ein Argument, das für sich ein valider Punkt ist

Doch, denn das bedeutet dass die Mehrheit deinen Code nicht so schnell 
durchblicken würde.

Ich darf auf Arbeit leider mit sehr viel sehr schlechtem Code arbeiten, 
der auch viele Dinge auf kuriose Art und Weise macht. Leider kann ich 
die Entwickler davon nicht erreichen. Hier verschwende ich viel Zeit 
damit, zu ergründen, was die da machen.

von Stefan F. (Gast)


Lesenswert?

Eine spannende Frage ist: Wie stellst du sicher, dass die N Aufrufe der 
Funktion in jedem möglichen Fall genügend sind?

von El Ef (Gast)


Lesenswert?

Walter T. schrieb:
> Mein Fliesenleger begründet anders: "Wenn ich das uneben lege, ist das
> Pfusch, weil das Auge bei geraden Linien leider schon recht kleine
> Abweichungen erkennen kann."

Wenn ich etwas ISR nenne und das dann nicht nur ISR ist, wirkt das 
erstmal verwirrend und merkwürdig alleine von der Begrifflichkeit.

Dr. Sommer schrieb:
> Ich würde da gerne eine Begründung sehen.

Ich auch. Unabhängig davon die ISR als Funktion aufrufen zu wollen

von Master (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Wieso erst zur Laufzeit? Basieren die auf einer Eingabe? Wie kommt eine
> Eingabe zustande, wenn doch bis dato die Interrupts aus sind?

Das frage ich mich auch die Ganze Zeit.

An den TE:

1.) Eine ISR ist eine Interrupt Service Routine. Diese wird durch einen 
Interrupt ausgelöst, nicht durch den User, das ist einfach ihr Sinn. So 
eine ISR einfach händisch aufzurufen ist Pfusch. Das ist nicht so schwer 
zu verstehen.

2.) Was genau soll sich denn da einschwingen? Du rufst eine Funktion 
1000 mal auf OHNE externe Eingabe. Es kann unter diesen Umständen kein 
sinnvolles Szenario geben, bei dem die Werte nicht deterministisch sind, 
die du durch einen iterativen Aufruf in das Array schreibst.

von S. R. (svenska)


Lesenswert?

Walter T. schrieb:
> Okay, wir sind wieder auf dem Stand "ISR aus main() aufrufen
> ist böse und muß unbedingt vermieden werden - egal wie
> aufwendig der Workaround ist!"

Eine ISR ist keine normale Subroutine und sollte daher nicht wie eine 
normale Subroutine behandelt werden. Wenn an einem Tankstutzen groß 
"DIESEL" dransteht, dann gehe ich in der Regel auch nicht davon aus, 
dass da Benzin (oder Gemisch) reingehört.

Tu deinen Filter in eine eigene, normale Funktion. Die kannst du - wenn 
reentrant gemacht oder passend gesichert - aus normalem Code und ISR 
aufrufen.

Das stinkt dann auch nicht so sehr nach "das hat ein Idiot 
programmiert".

Explizit initialisieren ist trotzdem schöner. Kann man auch im ersten 
Durchlauf machen.

von W.S. (Gast)


Lesenswert?

Walter T. schrieb:
> Es muß also noch stärkere Gründe geben.

Ja, natürlich!

Also: deine ISR wird ja wohl nicht im stillen Kämmerlein wie ein Autist 
herumwerkeln, sondern sie wird filtern und dann ein Ergebnis dabei 
herausbekommen, was dann in irgend einer Weise weiter in der Firmware 
propagiert wird.

So. Und nun läßt du diese ISR mutwillig auf die ersten n Samples los, 
die nach deiner Darstellung Mumpitz sind, weil nicht so, wie du dir das 
denkst. Also wird deine ISR aus den Mumpitz-Samples auch entsprechenden 
Mumpitz-Output erzeugen.

Willst du das?

Du könntest es einfacher haben: indem du einfach nur den Interrupt zu 
deiner ISR freigibst und ansonsten GARNICHTS tust. Nach n Samples wird 
sich dann alles von allein geregelt haben.

Wozu willst du dann den Zirkus mit den "ein paar hundert mal aus main 
aufrufen" überhaupt durchführen? Das ist komplett überflüssig.

Abgesehen davon ist es möglicherweise auch für die Hardware störend, 
weil diese normalerweise davon ausgeht, daß eine ISR nicht per Software, 
sondern nur vom zuständigen Interruptcontroller ausgelöst wird.

Mag sein, daß das bei deiner HW keine Rolle spielt, aber woanders spielt 
es eine deutliche Rolle, auch dann, wenn eine ISR lediglich als void 
deklariert worden ist. Lies z.B. mal bei Arm nach, was dort für ein 
Zirkus abgeht, wenn der Gleitkommaprozessor sowohl im Grundprogramm als 
auch in der ISR benutzt werden soll. Was da in welchem Falle auf den 
Stack gerettet werden muß oder auch nicht - und so weiter. Oder lies bei 
Chips mit Privilegien nach, was da an Systemzuständen gerettet und 
restauriert werden muß oder ob manche Befehle in der ISR nur dann 
funktionieren, wenn sie per Interrupt tatsächlich aus dem User-level in 
einen höheren Level gehoben ist.

Kurzum, bei einem AVR kannst du sowas ja gerne ausprobieren, wenngleich 
es dir auch sachlich nichts nützt, aber auf anderen Architekturen sollte 
man von so etwas Abstand nehmen. Man handelt sich gelegentlich mit sowas 
nur Bugs ein, die man ohne intime Kenntnis der HW garnicht finden 
kann.

W.S.

von m.n. (Gast)


Lesenswert?

S. R. schrieb:
> Tu deinen Filter in eine eigene, normale Funktion. Die kannst du - wenn
> reentrant gemacht oder passend gesichert - aus normalem Code und ISR
> aufrufen.

Was soll denn daran besser sein? Wenn die als ISR verwendete Routine die 
gleichen Vorgaben erfüllt, kann man diese auch direkt aufrufen. Ich 
finde diese Möglichkeit gut.
Die vielen Warnungen hier scheinen mir alle auf verkalkte Köpfe 
hinzuweisen:
"Haben wir noch nie gemacht" bzw. "Das machen wir immer so."

von W.S. (Gast)


Lesenswert?

Stefanus F. schrieb:
> Eine spannende Frage ist:

Nein, diese Frage ist zumindest bei einem FIR Filter überhaupt nicht 
spannend, sondern bereits vor der ersten Zeile Quellcode geklärt. Ein 
solches Filter mit n Taps hat ein Gedächtnis von exakt n Samples. Wenn 
er also 101 Taps hat, dann reichen exakt 101 Aufrufe.

Bei IIR Filtern sieht das anders aus, aber auch da reicht Obiges aus, 
denn wenn nicht, ist das Filter ohnehin instabil und liefert nur Murks. 
Kann bei IIR passieren, schließlich ist das ja quasi das Audion-Prinzip, 
also Versteilerung der Flanken durch Mitkopplung. Übertreibt man's, dann 
schwingt es. Und kurz drunter klingelt es. Ist also für Filterzwecke mit 
größter Vorsicht zu genießen. Aber da der Walter mit so einem Ansinnen 
kommt, schätze ich, daß er die Klasse der IIR-Filter ohnehin nicht 
wirklich handhaben kann. Mir wäre das auch zu heikel. FIR Filter sind da 
weitaus gutmütiger - und eben stabil und überschaubar im Verhalten.

W.S.

von S. R. (svenska)


Lesenswert?

m.n. schrieb:
> Was soll denn daran besser sein? Wenn die als ISR verwendete
> Routine die gleichen Vorgaben erfüllt, kann man diese auch
> direkt aufrufen.

Wenn man das kann, kann man das machen. Auf x86 und AVR kann man es 
definitiv nicht, weil dort eine ISR anders generiert werden muss.

Ist halt im Zweifelsfall brüchiger Code (spätestens, wenn sich Compiler 
oder Architektur ändern).

Einen normalen Funktionsaufruf - egal ob aus ISR oder nicht - kann der 
Compiler immer korrekt generieren. Einzig der Kontext ist 
unterschiedlich, aber dagegen kann man nichts tun.

m.n. schrieb:
> Ich finde diese Möglichkeit gut.

Manche stehen auch auf Peitschenhiebe. Auch wenn es funktioniert, ist es 
meistens trotzdem keine gute Idee.

von John Doe (Gast)


Lesenswert?

W.S. schrieb:
> Mag sein, daß das bei deiner HW keine Rolle spielt, aber woanders spielt
> es eine deutliche Rolle, auch dann, wenn eine ISR lediglich als void
> deklariert worden ist. Lies z.B. mal bei Arm nach, was dort für ein
> Zirkus abgeht, wenn der Gleitkommaprozessor sowohl im Grundprogramm als
> auch in der ISR benutzt werden soll. Was da in welchem Falle auf den
> Stack gerettet werden muß oder auch nicht - und so weiter.


Beim Cortex M4F werden S0-S31 sowie FPSCR automatisch vom Prozessor auf 
den Stack gerettet. Was soll daran Zirkus sein?

von Heiko L. (zer0)


Lesenswert?

Also ich muss Walter Recht geben. Wer würde denn ein riesiges Array 
voller "magic numbers" als wartungsfreundlicher ansehen? Das müsste 
irgendwie schon gerechtfertigt sein. Aber die Herren haben sich schon 
derartig vergallopiert, dass es ihnen offensichtlich ist, z.B. einen 
Tippfehler in der X. Stelle in so einem Array leichter finden zu können, 
als einen Initialisierungs-Loop zu verstehen. Und sie haben Recht! Denn 
den Tippfehler findet man rein Mechanisch... Mann!

von Dr. Sommer (Gast)


Lesenswert?

Heiko L. schrieb:
> Also ich muss Walter Recht geben. Wer würde denn ein riesiges Array
> voller "magic numbers" als wartungsfreundlicher ansehen?

Im Idealfall generiert man das mit einem C++ Constexpr Algorithmus...

m.n. schrieb:
> Die vielen Warnungen hier scheinen mir alle auf verkalkte Köpfe
> hinzuweisen:
> "Haben wir noch nie gemacht" bzw. "Das machen wir immer so."

Manchmal haben verkalkte Köpfe auch mehr Erfahrung. Findest du die 
längere Hochfahr Zeit auch gut? Hier wird doch ständig über langsame 
Programme gelästert...

von Heiko L. (zer0)


Lesenswert?

Dr. Sommer schrieb:
> Im Idealfall generiert man das mit einem C++ Constexpr Algorithmus...

Mhm. Und das ist dann? Mal überlegen, man hat einen loop mit konstanten 
bounds und ... ähm ... nein...

Dr. Sommer schrieb:
> Findest du die
> längere Hochfahr Zeit auch gut?

constexpr ist übrigens keine Garantie, dass eine Berechnung zur 
Compile-Time stattfindet.

von Dr. Sommer (Gast)


Lesenswert?

Heiko L. schrieb:
> ähm ... nein...

Danke für die detaillierte Argumentation.

Heiko L. schrieb:
> constexpr ist übrigens keine Garantie, dass eine Berechnung zur
> Compile-Time stattfindet.

Doch, wenn das constexpr an der zu berechnenden Variable steht.

von Stefan F. (Gast)


Lesenswert?

W.S. schrieb:
> Ein
> solches Filter mit n Taps hat ein Gedächtnis von exakt n Samples. Wenn
> er also 101 Taps hat, dann reichen exakt 101 Aufrufe.

Mit welchem Input? Zufallsdaten? Müll? Nullen?

von Peter D. (peda)


Lesenswert?

Ich habe ein ähnlichen Problem so gelöst, daß ich im Timerinterrupt eine 
Variable runterzähle und erst, wenn sie 0 ist, wertet das Main die 
Ergebnisse aus.

von Stefan F. (Gast)


Lesenswert?

Wenn schon, dann würde ich den Algorithmus 100x mit definiertem 
Input aufrufen, und nicht einfach Interrupts simulieren, die dann 
zufällige Werte aus dem ADC verwursten.

Man möchte schließlich ein vorhersagbares Ergebnis.

von Walter T. (nicolas)


Lesenswert?

Guten Morgen,

über Nacht sind ein paar interessante Beiträge geschrieben worden. Da 
brauche ich ein besseres Eingabegerät und ein wenig Zeit, um die 
sinnvoll zu würdigen.

Aber einen Fehlschluß will ich kurz zwischen Tür und Angel korrigieren:

Stefanus F. schrieb:
> Mit welchem Input? Zufallsdaten? Müll? Nullen?

Der erste ADC-Wert (adc_0) ist alles andere als Müll. Es ist zu diesem 
Zeitpunkt das beste, was vorhanden ist. Und auch eigentlich gar nicht 
wirklich schlecht. Immerhin ist das in Hardware realisierte 
Anti-Aliasing Filter ja schon ein Weilchen vor dem Start der MCU aktiv. 
Damit ist in einem FIR-Filter für alle Eingangsverzögerungen u(z^(-i)) = 
adc_0 mit i in 0...n ein valider Startwert. Daß der Ausgang des Filters 
sich in den nächsten n Schritten immer weiter verbessern wird, ist 
natürlich auch klar. Aber ich wüßte keine bessere Schätzung für den 
Anfang.

: Bearbeitet durch User
von Heiko L. (zer0)


Lesenswert?

Dr. Sommer schrieb:
> Heiko L. schrieb:
>> ähm ... nein...
>
> Danke für die detaillierte Argumentation.
>
> Heiko L. schrieb:
>> constexpr ist übrigens keine Garantie, dass eine Berechnung zur
>> Compile-Time stattfindet.
>
> Doch, wenn das constexpr an der zu berechnenden Variable steht.

Das liest man immer wieder, stimmt aber so nicht. Das gilt nur dann, 
wenn die constexpr in einem Kontext verwendet wird, in dem eine 
Compile-Zeit-Konstante vorliegen muss.

von Dr. Sommer (Gast)


Lesenswert?

Heiko L. schrieb:
> Das gilt nur dann,
> wenn die constexpr in einem Kontext verwendet wird, in dem eine
> Compile-Zeit-Konstante vorliegen muss.

Und das ist der Fall, wenn eine globale oder statische Variable mit 
constexpr markiert wird. Wenn das nicht zur Compile-Time berechnet 
werden kann, gibt's einen Compiler-Error.

von Lukas (Gast)


Lesenswert?

Walter T. schrieb:
> Der erste ADC-Wert (adc_0) ist alles andere als Müll. Es ist zu diesem
> Zeitpunkt das beste, was vorhanden ist. Und auch eigentlich gar nicht
> wirklich schlecht. Immerhin ist das in Hardware realisierte
> Anti-Aliasing Filter ja schon ein Weilchen vor dem Start der MCU aktiv.
> Damit ist in einem FIR-Filter für alle Eingangsverzögerungen u(z^(-i)) =
> adc_0 mit i in 0...n ein valider Startwert. Daß der Ausgang des Filters
> sich in den nächsten n Schritten immer weiter verbessern wird, ist
> natürlich auch klar. Aber ich wüßte keine bessere Schätzung für den
> Anfang.

Das ganze klingt irgendwie, als ob du versuchst, schneller auszuwerten 
als das Filter Daten am Ausgang liefert (Warum?). Ist denn 
sichergestellt, dass dein Nutzsignal schon beim anschalten anliegt? 
Vielleicht fehlt mir zum Verständnis auch ein konkreter Anwendungsfall. 
Aber wenn ich z.B. an Sprachsignale denke, macht das für mich keinen 
Sinn.

von Heiko L. (zer0)


Lesenswert?

Dr. Sommer schrieb:
> Und das ist der Fall, wenn eine globale oder statische Variable mit
> constexpr markiert wird. Wenn das nicht zur Compile-Time berechnet
> werden kann, gibt's einen Compiler-Error.

Das ist ja auch, was du mit constexpr garantierst. "Kann zur 
Compile-Zeit berechnet werden."

von m.n. (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Findest du die
> längere Hochfahr Zeit auch gut? Hier wird doch ständig über langsame
> Programme gelästert...

Daß hier viel und auch grundlos gelästert wird, ist bekannt. Das ist 
kein Argument.

Gerade beim Hochfahren hat ein Programm viel Zeit, da die Peripherie 
nicht sofort einsatzbereit ist. Programmier doch mal ein Gerät, das nach 
1 ms Startup auf ein angeschlossenes (LC-/TFT-)Display schreibt. Viel 
Lesbares wird da nicht zu sehen sein.

Walter T. schrieb:
> ich habe eine ISR - SysTick_Handler(), die ich vor dem ersten Interrupt
> ein paar (hundert) mal aus main() aufrufen will, damit sich beim ersten
> Interrupt die internen Zustände soweit stabilisiert haben.
> ...
>  - deswegen werden alle
> Interrupts erst später freigegeben.

Mache es einfach. Das wird doch in < 1 ms erledigt sein.

von Bernd K. (prof7bit)


Lesenswert?

Ich mach sowas in der Regel ganz pragmatisch so daß ich die ganze Sache 
beim Einschalten normal loslaufen lasse, jedoch die Ergebnisse der 
Messung (oder was auch immer) erst nach einer gewissen Zeit verwende, 
das beinhaltet die Zeit bis alle Spannungen überall stabil anliegen und 
Meßwerte brauchbar sind. Langsame moving averages oder andere Filter 
initialisiere ich mit den ersten brauchbaren Werten direkt (musst den 
Filter halt so implementieren daß das geht) so daß ich ich nicht zu 
lange warten und auch nicht tausende sinnloser Runden drehen muß. Wie 
lange es nach dem Einschalten dauert bis die ersten brauchbaren 
Messwerte reinkommen liegt an der jeweiligen Schaltung und wird 
experimentell ermittelt.

von Dr. Sommer (Gast)


Lesenswert?

Walter T. schrieb:
> Der erste ADC-Wert (adc_0) ist alles andere als Müll.

Ah, schön dass wir endlich erfahren dass die Eingabe doch erst zur 
Laufzeit bekannt ist. In dem Fall funktioniert eine normale 
Initialisierung natürlich nicht. Dann ist der Vorschlag am Besten, das 
Filter in eine eigene Funktion zu packen und die sowohl von ISR als auch 
von main() heraus aufzurufen.

m.n. schrieb:
> Programmier doch mal ein Gerät, das nach
> 1 ms Startup auf ein angeschlossenes (LC-/TFT-)Display schreibt.

Solche Dinge haben die Tendenz sich aufzusummieren. Daher achte ich 
schon gerne darauf, das Hochfahren auch zu beschleunigen. Sonst ist das 
am Ende wie beim Thermomix - nach dem Einschalten erstmal 1 Minute 
hochfahren bevor man loslegen kann...

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


Lesenswert?

Peter D. schrieb:
> Ich habe ein ähnlichen Problem so gelöst, daß ich im Timerinterrupt eine
> Variable runterzähle und erst, wenn sie 0 ist, wertet das Main die
> Ergebnisse aus.

Das ist das einzig sinnvolle.

Ein FIR Filter mit N Stufen braucht halt N Eingabewerte, bevor der 
Ausgabewert nützlich ist (im Sinne von: er korreliert mit den 
Eingabedaten). Das Filter mit irgendwelchen Werten zu füllen, bringt 
wenig bis nichts. Vollkommen egal, ob man dazu einen C-Initializer 
verwendet oder im Code explizit initialisiert oder N Dummy-Datenpunkte 
reinfüttert.

Der einzige 100% korrekte Weg besteht darin, N echte Messungen 
durchzuführen (also auch mit dem echten Timing) und so lange den 
Ausgabewert des Filters zu verwerfen.

Es gibt noch eine Variante, die vielleicht "gut genug" ist und bei der 
man weniger lang warten muß: man füllt das leere Filter beim allerersten 
Aufruf einmal komplett mit dem ersten Meßwert. Das hat dann den gleichen 
Effekt, als hätte man N-mal den gleichen Wert gemessen.

Aber für keinen dieser Lösungswege ist es notwendig, die ISR manuell 
aufzurufen.

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


Lesenswert?

S. R. schrieb:
> Ist halt im Zweifelsfall brüchiger Code (spätestens, wenn sich Compiler
> oder Architektur ändern).

Das hielte ich übrigens am ehesten für ein Argument (von „haben wir ja 
noch nie so gemacht!“ abgesehen :). Compiler jetzt nicht so sehr (das 
ist weitgehend alles durch die ARM-Hardware so vorgegeben), aber 
Architektur natürlich schon. Wenngleich: einen SysTick_Handler gibt's 
halt ohnehin nur auf dieser Architektur (mit diesem Namen). Beim 
Übergang auf eine andere Architektur muss man da also sowieso 
reinfassen.

Sauberer sieht es dann auf jeden Fall aus, eine separate Funktion zu 
schreiben, die N mal direkt und danach aus dem SysTick_Handler 
aufgerufen wird. Mit link time optimizations müssten Compiler und Linker 
das eigentlich auf der ARM-Architektur sogar wieder auf das gleiche 
optimieren können, wie Nicolas es hier gerade manuell erzwingen möchte.

Rolf M. schrieb:
> Hätte mir eigentlich spätestens bei SysTick_Handler() auffallen müssen,
> weil das STM32-typisch ist.

Kleine Korrektur: es ist Cortex-M-typisch, denn der SysTick ist von ARM 
standardisiert. Es ist eigentlich noch nicht ganz an der Zeit, dass man 
„STM32“ bereits als Synonym für „Cortex-M“ benutzen könnte. :)

von W.S. (Gast)


Lesenswert?

Axel S. schrieb:
> Es gibt noch eine Variante, die vielleicht "gut genug" ist..

Ja, sehe ich genau so. Das hatte ich ja mit dem "Erwartungswert" so 
angedeutet. Ich befürchte nur, daß auch deine Worte unverstanden 
verhallen.

Aber wenn hier Leute mit Zeugs wie constexpr und Compile-Time 
herumdiskutieren und selbst ein Moderator sowas schreibt:

Jörg W. schrieb:
> Sauberer sieht es dann auf jeden Fall aus, eine separate Funktion zu
> schreiben, die N mal direkt und danach aus dem SysTick_Handler
> aufgerufen wird.

..dann graust es mich.

W.S.

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


Lesenswert?

W.S. schrieb:
> und selbst ein Moderator

Könntest du bitte mal diesen unsinnigen Verweis unterlassen?

Die Moderatorenfunktion heißt doch nicht, dass wir uns deshalb 
sämtlicher fachlicher Diskussionen enthalten müssten. Selbstverständlich 
vertreten wir dann aber, was den fachlichen Teil angeht, einfach nur 
eine persönliche Meinung wie jeder andere. Die kann diskussionswürdig 
sein, aber du ziehst es ja vor, statt fachlich über meine 
Meinungsäußerung zu diskutieren, einfach nur die Polemik-Keule zu 
ziehen.

Was soll das denn?

von W.S. (Gast)


Lesenswert?

Peter D. schrieb:
> Ich habe ein ähnlichen Problem so gelöst, daß ich im Timerinterrupt eine
> Variable runterzähle und erst, wenn sie 0 ist, wertet das Main die
> Ergebnisse aus.

Das ist schlecht, denn es kostet Rechenzeit - und das für immer. Die 
Herunterzählzeit mag ja schon längst vergangen sein, und dennoch muß 
jedesmal in der ISR abgetestet werden, ob die variable nun 0 ist oder 
nicht. Aber gerade bei digitaler Signalverarbeitung ist die 
Samplefrequenz mit Regelmäßigkeit verdammt hoch und man geizt deshalb 
mit jedem Systemtakt. Was meinst du, wieviel Takte man für die gesamte 
ISR hat, wenn man nen Stereo-Audio-Codec mit 192 kHz Samplerate bedienen 
und den Input filtern will?

Und der erst:
John Doe schrieb:
> Beim Cortex M4F werden S0-S31 sowie FPSCR automatisch vom Prozessor auf
> den Stack gerettet. Was soll daran Zirkus sein?

Jahaha.. und nun willst du die ISR manuell von main aus aufrufen, ohne 
zu beachten, daß du ja nicht in Software diese Rettfunktion nachbilden 
kannst, die die Hardware da macht.

W.S.

von Peter D. (peda)


Lesenswert?

W.S. schrieb:
> Das ist schlecht, denn es kostet Rechenzeit - und das für immer.

Na übertreib mal nicht so. Ich hab dafür einen 1ms Timerinterrupt 
genommen, da ist genug Zeit. Ist 0 erreicht, kann der Interrupt auch 
sich selber sperren, die ARM haben ja in der Regel reichlich Timer.
Je nach ARM könnte man auch einen One-Shot Timer aufsetzen, d.h. ganz 
ohne Interrupt auskommen.

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


Lesenswert?

W.S. schrieb:
> Jahaha.. und nun willst du die ISR manuell von main aus aufrufen, ohne
> zu beachten, daß du ja nicht in Software diese Rettfunktion nachbilden
> kannst, die die Hardware da macht.

Muss ja auch niemand. Wie Nicolas schon feststellte, unterscheidet sich 
sowas wie der SysTick_Handler in nichts von jeder anderen 
void/void-Funktion. Alles exception handling wird durch die Hardware 
erledigt. Joe hatte oben auf die ARM-Seite verwiesen, unter "Exception 
return" steht beschrieben, wie das genau erledigt wird.

von Stefan F. (Gast)


Lesenswert?

Jörg W. schrieb:
>> und selbst ein Moderator
> Könntest du bitte mal diesen unsinnigen Verweis unterlassen?

Freu' Dich doch, letztendlich zeigt es, dass er dich von unten aus 
bewundert.

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


Lesenswert?

Stefanus F. schrieb:
> dass er dich von unten aus bewundert.

Darauf kann ich gut und gern verzichten.

Die Moderation ist Arbeit, die wir irgendwie nebenbei auf uns nehmen, 
aber eigentlich wollen wir Moderatoren diesen Teil allesamt nicht zum 
wesentlichen Anteil der Tätigkeit im Forum ausufern lassen. Wir sind 
hier genauso wie alle anderen der fachlichen Diskussionen wegen. Auch 
oder gerade bei Leuten wie W.S., bei denen ich nur selten eine fachliche 
Übereinstimmung finde *), lohnt sich die Diskussion allemal solange sie 
denn sachlich bleibt, denn es kann einen ja fachlich weiter bringen.

Einen puren Verweis „sowas kommt von einem Moderator“ (wohlgemerkt 
bezogen auf eine fachliche Meinungsäußerung, nicht etwa auf Umgangston 
oder dergleichen, da wäre es natürlich völlig gerechtfertigt) empfinde 
ich jedoch als völlig unsachliche Diskussionskultur, die nur Frust 
erzeugt und keinen Weiterbildungseffekt hat.

*) Ich bin allerdings wenig voreingenommen. W.S.' Lötstationsprojekt um 
den JBC-Kolben herum fand ich zum Beispiel sehr interessant.

: Bearbeitet durch Moderator
von Walter T. (nicolas)


Lesenswert?

Gerhard schrieb:
> Ich entwickle beruflich sicherheitskritische Software (Luftfahrt).
> [Danach kommt ein langer und lesenswerter Text über Softwareentwicklung
>  einem Bereich, der extrem stark reglementiert ist]

Danke für Deine Beschreibung. Daß jemand, der es gewohnt ist, 
grundsätzlich mit einem Top-Down-Ansatz zu arbeiten, jeden 
Bottom-Up-Ansatz als "unstrukturiertes Vorgehen" zu bezeichnen, kann ich 
nachvollziehen. Insofern finde ich Deinen Beitrag sehr lesenswert.

Im Alltag wirft man mir eigentlich selten "unstrukturiertes Vorgehen" 
vor, aber Softwareentwicklung ist ja auch definitiv nicht der Bereich, 
in dem ich mich zuhause fühle.

S. R. schrieb:
> [...] Das stinkt dann auch nicht so sehr nach "das hat ein Idiot
> programmiert".

Ich übersetze mal ins Hochdeutsche:
Das ist <unfreundliches Synonym für "Pfusch">, weil <anderes 
unfreundliches Synonym für "Pfusch">.

Dr. Sommer schrieb:
> Manchmal haben verkalkte Köpfe auch mehr Erfahrung. Findest du die
> längere Hochfahr Zeit auch gut?

Wieso wird die Hochfahr-Zeit länger? Sie wird tatsächlich kürzer. Bei 
einer ISR, die im 10 Millisekunden-Raster aufgerufen wird und einem 
FIR-Filter mit n = 100 benötige ich im Normalfall 990 Millisekunden, bis 
der erste gültige Wert hinten herauspurzelt. Wenn ich das Filter 100 mal 
mit dem ersten Eingangswert füttere, ist vor der ersten Millisekunde der 
erste Ausgangswert vorhanden.

Lukas schrieb:
> Vielleicht fehlt mir zum Verständnis auch ein konkreter Anwendungsfall.
> Aber wenn ich z.B. an Sprachsignale denke, macht das für mich keinen
> Sinn.

Bei Sprachsignalen wäre das auch komplett sinnlos. Sprachsignale werden 
Blockweise mit einer hohen Abtastraste ausgewertet. Bei einen hohen 
Abtastrate bringt es aber auch kaum Geschwindigkeitsgewinn, schon 
loszulegen, bevor die ersten n Samples anliegen. Sinn ergibt es erst, 
bei sehr langsam veränderlichen Signalen mit einer sehr niedrigen 
Abtastrate.

Bernd K. schrieb:
> Langsame moving averages oder andere Filter
> initialisiere ich mit den ersten brauchbaren Werten direkt (musst den
> Filter halt so implementieren daß das geht) so daß ich ich nicht zu
> lange warten und auch nicht tausende sinnloser Runden drehen muß.

Axel S. schrieb:
> Es gibt noch eine Variante, die vielleicht "gut genug" ist und bei der
> man weniger lang warten muß: man füllt das leere Filter beim allerersten
> Aufruf einmal komplett mit dem ersten Meßwert. Das hat dann den gleichen
> Effekt, als hätte man N-mal den gleichen Wert gemessen.

W.S. schrieb:
> Ja, sehe ich genau so. Das hatte ich ja mit dem "Erwartungswert" so
> angedeutet. Ich befürchte nur, daß auch deine Worte unverstanden
> verhallen.

Walter T. schrieb:
> Der erste ADC-Wert (adc_0) ist alles andere als Müll. Es ist zu diesem
> Zeitpunkt das beste, was vorhanden ist. Und auch eigentlich gar nicht
> wirklich schlecht. Immerhin ist das in Hardware realisierte
> Anti-Aliasing Filter ja schon ein Weilchen vor dem Start der MCU aktiv.
> Damit ist in einem FIR-Filter für alle Eingangsverzögerungen u(z^(-i)) =
> adc_0 mit i in 0...n ein valider Startwert. Daß der Ausgang des Filters
> sich in den nächsten n Schritten immer weiter verbessern wird, ist
> natürlich auch klar. Aber ich wüßte keine bessere Schätzung für den
> Anfang.

Ihr vier hattet alle die gleiche gute Idee. Ich mache das auch so.

: Bearbeitet durch User
von Dr. Sommer (Gast)


Lesenswert?

Walter T. schrieb:
> Wieso wird die Hochfahr-Zeit länger? Sie wird tatsächlich kürzer.

Sie wird länger gegenüber einer direkten Initialisierung mit fixen 
Werten. Wie wir aber jetzt erst erfahren haben, geht das gar nicht weil 
die Initialisierung mit zur Laufzeit bekannten Werten geschieht.

Bei einem FIR-Filter könnte man den 1. ADC-Wert einfach in die Schlange 
der Eingabewerte kopieren a la memset(). Die 1000 Aufrufe der ISR 
bewirken wahrscheinlich auch 1000 Berechnungen des Ausgabewerts, welcher 
dann gar nicht gebraucht wird.

von Walter T. (nicolas)


Lesenswert?

Gerhard schrieb:
> Meine Kritik richtet sich also weniger gegen die konkrete
> Implementierung (Aufrufen der ISR in einer Schleife), sondern mehr gegen
> die Vorgehensweise, die zu dieser Implementierung führt.

Naja, meine Vorgehensweise bei der Implementierung kennst Du ja 
eigentlich gar nicht. Woher weißt Du, wie detailliert mein 
Mini-Lastenheft ist?

Klar - ein Requirements Engineering wie in der Luftfahrt kann ich bei 
einem Hobbyprojekt nicht leisten. Sonst wäre meine Lebenszeit schon vor 
der ersten Quelltextzeile um.

Und daß ich als Hobbyentwicker nur einen Bottom-Up-Ansatz wählen kann, 
weil

  1. Ich für jede Komponente erst einmal einen Funktionsprototypen 
benötige, um zu wissen, was überhaupt funktioniert und
  2. Sinnvolle Literatur über "Architektur einer 
Mikrocontroller-Firmware" Mangelware zu sein scheint, so daß jeder 
Entwickler jeden Fehler erst einmal selbst gemacht haben muß -oder 
zumindest jede Entwicklergruppe-, *)

ist auch nicht unbedingt ein echtes Zeichen für eine "unstrukturierte" 
Vorgehensweise.

Tatsächlich halte ich meine Vorgehensweise (1. Problem identifizieren -> 
2. verschiedene Lösungsansätze skizzieren -> 3. Vor- und Nachteile 
ausarbeiten -> 4. bewerten -> 6. auswählen -> immer: dokumentieren) für 
sehr strukturiert. Aber diese Selbsteinschätzung hat wohl jeder 
Ingenieur, der etwas auf sich hält.

Punkt 3 ist übrigens der Teil, der die meisten Foren-Fragen generiert 
und damit besonders schwierig ist.


Gerhard schrieb:
> Das Gegenbeispiel wäre das Betrachten der Frage, wie das Filter sich
> beim Einschalten verhalten soll und warum (welche System-Requirements
> beschreiben das?

Die Frage habe ich in meinem Mini-Lastenheft tatsächlich bislang außen 
vor gelassen. Danke für die Ergänzung.


*) Sollte jetzt jemand die entsprechende Literatur ("Archtitektur für 
Mikrocontroller-Firmware - das weiß man doch!") aus dem Hut zaubern: 
Darüber würde ich mich total ärgern. Versprochen!

: Bearbeitet durch User
von S. R. (svenska)


Lesenswert?

Walter T. schrieb:
>> [...] Das stinkt dann auch nicht so sehr nach
>> "das hat ein Idiot programmiert".
>
> Ich übersetze mal ins Hochdeutsche:
> Das ist <unfreundliches Synonym für "Pfusch">, weil <anderes
> unfreundliches Synonym für "Pfusch">.

Nun, ich habe eine sinnvolle Lösung präsentiert. Mehrfach. Hattu 
ignoriat.

Diese (oder eine der anderen vorgestellten sinnvollen Lösungen) nicht zu 
verwenden, ist nunmal Pfusch. Kann man machen, kann funktionieren, 
bleibt trotzdem Pfusch.

Aber wer überall "Pfusch" hören will, der hört es auch überall.

von Carl D. (jcw2)


Lesenswert?

W.S. schrieb:
> Und der erst:
> John Doe schrieb:
>> Beim Cortex M4F werden S0-S31 sowie FPSCR automatisch vom Prozessor auf
>> den Stack gerettet. Was soll daran Zirkus sein?
>
> Jahaha.. und nun willst du die ISR manuell von main aus aufrufen, ohne
> zu beachten, daß du ja nicht in Software diese Rettfunktion nachbilden
> kannst, die die Hardware da macht.
>
> W.S.

Das ist bei den Cortext-M egal. Das Hardware-Stacking gibt es nur, wenn 
der "Call" auch durch die Hardware ausgeführt wurde. Wenn die Hardware 
Register gesichert hat, dann steht im Link-Register statt der 
Return-Adresse eine "Magic Number" drin (0xFFFFFFFirgendwas), was die 
Hardware-Aktion wieder rückgängig macht. Inklusive "Run-Mode"-Wechsel, 
etc. D.h. die Maschine weiß selbst, wann sie besser RETI machen sollte.

Update:
Gut versteckt in der ARM-Doku (Application Note 298) ist zu finden, daß 
auf Cortext-M mit FPU auch die C-Calling-Convention (S0..S16 müssen vom 
Caller gesichert werden) implementiert ist. Nur wird dafür zuerst nur 
Platz auf dem Stack reserviert und das eigentliche Sicher erst 
durchgeführt, wenn die ISR erstmals FP benutzt.

: Bearbeitet durch User
von Walter T. (nicolas)


Lesenswert?

Carl D. schrieb:
> Update:
> Gut versteckt in der ARM-Doku (Application Note 298) ist zu finden, daß
> auf Cortext-M mit FPU auch die C-Calling-Convention (S0..S16 müssen vom
> Caller gesichert werden) implementiert ist. Nur wird dafür zuerst nur
> Platz auf dem Stack reserviert und das eigentliche Sicher erst
> durchgeführt, wenn die ISR erstmals FP benutzt.

Danke für den Hinweis! Ich mache zwar momentan alles in Integer, aber 
gibt doch ein wohliges Gefühl, daß auch hier keine Falle lauert.

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.