Forum: Compiler & IDEs statische Memberfunktion als Interrupt-Handler?


von Reinhard M. (reinhardm)


Lesenswert?

Hallo,

hier fand ich den Hinweis, dass man mit inline-Assembler den gemerkelten 
Namen ändern kann, sodass eine statische Member-Funktion als 
Interrupt-Handler akzeptiert wird.
Das fand ich richtig schick und habe es weitläufig bei den AVRs 
eingesetzt.

Bei der Portierung der Klassen auf stm32 musste ich feststellen, dass 
der Compiler mit dem Hack nichts anfangen konnte. Anstatt die 
Assembleranweisung auszuführen, führte es dazu, dass die 
Interrupt-Handler jetzt mit der Nop-Funktion (die auch inline assembler 
hat) zu einer Kollision führen (Funktion ist bereits implementiert ...).

Gibt es einen ähnlichen Hack, der auf stm32 funktioniert, sodass ich 
dort auch statische Member zu Interupt-Handler machen kann?

von Reginald L. (Firma: HEGRO GmbH) (reggie)


Lesenswert?

Ich hab das so gelöst, ist sehr geschickt wenns auf ein paar takte mehr 
nicht ankommt:
http://www.embedded.com/design/prototyping-and-development/4023817/Interrupts-in-C-

Das geile ist, dass es sich so schön obiektorientiert schaffen lässt.

von Reinhard M. (reinhardm)


Lesenswert?

> Das geile ist, dass es sich so schön obiektorientiert schaffen lässt.

Sorry, aber wenn man 10 Seiten schreiben muss, um einen Einzeiler zu 
ersetzen, dann finde ich das überhaupt nicht geil :(

von Wilhelm M. (wimalopaan)


Lesenswert?

Reinhard M. schrieb:

> hier fand ich den Hinweis, dass man mit inline-Assembler den gemerkelten

von Angela "ge-merkelt"? -> ge-mangled

von Wilhelm M. (wimalopaan)


Lesenswert?

Reinhard M. schrieb:
> Hallo,
>
> hier fand ich den Hinweis, dass man mit inline-Assembler den gemerkelten
> Namen ändern kann, sodass eine statische Member-Funktion als
> Interrupt-Handler akzeptiert wird.
> Das fand ich richtig schick und habe es weitläufig bei den AVRs
> eingesetzt.

Ja, ich dachte auch erst mal, dass das schick ist.

Aber: es geht mit Klassentemplates nicht (warum, weiß ich noch nicht). 
Und da ich bei baremetal-cpp stark auf parametrische Polymorphie setze, 
scheidet das für mich aus - wie man sieht, aus gutem Grund ...
Zudem wird ein singulärer Aufruf einer Elementfunktion aus den C-ISRs 
einfach zu zero-overhead optimiert. Es besteht als kaum ein Grund für 
den Hack ...

: Bearbeitet durch User
von Reinhard M. (reinhardm)


Lesenswert?

> es geht mit Klassentemplates nicht (warum, weiß ich noch nicht).
> Und da ich bei baremetal-cpp stark auf parametrische Polymorphie setze,
> scheidet das für mich aus

Hm, Du schreibst viel über Templates und Polymorphie - mach doch mal ein 
Beispiel, wie das aussehen könnte.

von Vincent H. (vinci)


Lesenswert?

Der "Hack" ist vermutlich jener hier?
1
struct A
2
{
3
  static void f() asm("TIM8_UP_IRQHandler"); // IRQ-Name, definiert in STs Header Files
4
};
5
6
void A::f()
7
{
8
  trace_printf("Update Interrupt Timer8\n");
9
}

Nona funktioniert das bei Templates nicht! asm-specifications sind nur 
bei Definitionen erlaubt. Sobald man aus einem Template aber eine Klasse 
stanzt, is jegliche Definition natürlich wertlos...
1
template<size_t N>
2
struct A
3
{
4
  static int x;
5
6
  static void foo() asm("TIM8_UP_IRQHandler"); // IRQ-Name, definiert in STs Header Files
7
};
8
9
template<size_t N>
10
void A<N>::foo()
11
{
12
  trace_printf("x is %d:\n", x);
13
}
14
15
template<>
16
int A<10>::x = 10;
17
18
template<>
19
int A<6>::x = 6;

Woher soll der Compiler denn wissen, ob er nun A<10>::foo() oder 
A<6>::foo() umbenennen soll?

Abgesehn davon find ich die Lösung auch eher "unschön", da man sich die 
Namen der Interrupts merken muss. Grad ST verwendet teils abstruse Namen 
wie etwa TIM1_TRG_COM_TIM17_IRQHandler... Na juhu ;)
Da legt man doch lieber irgendwo in den Tiefen seiner Ordner-Strukturen 
ein Makro ab:
1
#define EXTERN_C_IRQ_TO_CALLBACK(IRQ_NAME, CALLBACK)        extern "C" void     \
2
                                                            IRQ_NAME() {        \
3
                                                            CALLBACK();         \
4
                                                            }

Das is zwar alles andere als "modern C++", aber wie Wilhelm schon 
erwähnte entsteht dadurch eh 0 Overhead. Der Callback kann dann auch 
durchaus in ein spezialisiertes Template führen... Das macht selbst bei 
gebastelten Libraries ja durchaus Sinn.

/edit
Typo fixed

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

Vincent H. schrieb:

> Nona funktioniert das bei Templates nicht! asm-specifications sind nur
> bei Definitionen erlaubt.

Ja. Meine Vermutungen / Hoffnungen waren:

1) in allen Template-Instanziierungen bekommen die Elementfunktionen 
denselben Namen, den man vorgibt. Das hätte dann den schönen 
Nebeneffekt, dass unterschiedliche Instanziierungen zu demselben Namen, 
damit zur Verletzung der ODR kommt. Was meistens dann sinnvoll wäre.

2) ich könnte bei der Instanziierung den Namen festlegen.

Leider habe ich dazu nicht wirklich Quellen gefunden.

von Wilhelm M. (wimalopaan)


Lesenswert?

Reinhard M. schrieb:
>> es geht mit Klassentemplates nicht (warum, weiß ich noch nicht).
>> Und da ich bei baremetal-cpp stark auf parametrische Polymorphie setze,
>> scheidet das für mich aus
>
> Hm, Du schreibst viel über Templates und Polymorphie - mach doch mal ein
> Beispiel, wie das aussehen könnte.

Jetzt weiß ich nicht, was Du wissen möchtest. Fangen wir mit "Hello 
World" an:
1
#include "mcu/ports.h"
2
3
using namespace AVR;
4
using PortB = Port<DefaultMcuType::PortRegister, AVR::B>;
5
using led = Pin<PortB, 0>;
6
7
int main()
8
{
9
    led::dir<Output>();        
10
    led::high();
11
    
12
    while(true) {
13
        led::toggle();        
14
    }    
15
}

von tictactoe (Gast)


Lesenswert?

Aah! Endlich einer, der kapiert hat, wie man einen MCU mit C++ 
programmiert. Gibt's das als Library, oder ist das selbst erfunden?

von Reinhard M. (reinhardm)


Lesenswert?

> Jetzt weiß ich nicht, was Du wissen möchtest. Fangen wir mit "Hello
> World" an:

Sorry, aber auf dem Level brauchen wir uns nicht unterhalten.
Wertlose Trivialitäten habe ich von dem Kormanyos schon so reichlich 
erhalten, dass es mir schon zu den Ohren raus kommt :(

Du hast von parametrischer Polymorphie geschrieben. Da hätte ich gerne 
ein Beispiel für gesehen, welches auch im Alltag Sinn macht.
Nehmen wir mal ein nicht-triviales Beispiel:
ein ATmega88 (und Co) hat 3 verschiedene Hardware-Timer. Wie würdest Du 
die mit Templates abbilden, sodass es keinen Code-Overhead gibt?
Interrupts der Timer sollen nach wie vor optional bleiben und natürlich 
sollen auch nach wie vor alle Möglichkeiten unterstützt werden.

... und bitte nicht so halblebige Codefetzen.

von Wilhelm M. (wimalopaan)


Lesenswert?

Ist selbst erfunden, weil die meisten Cpp Frameworks sind "zu alt", um 
die neuen features zu nutzen.

Ich bin eigentlich dabei, meine ganzen uC Projekte umzustellen. Damit 
habe ich konkrete Anwendungsfälle und sehe wie sich das Ganze 
entwickelt. Bin aber schon ziemlich weit. Bei der Abstraktionsschicht 
beschränkt es sich allerdings derzeit auf ein paar AVRs, denn das ist 
reine Fleißarbeit ...

Neben Mini-Projekten wie Wordclock, etc. habe ich auch einen 
RC-Sensor-Schaltmodul umgestellt: der kann dann (Graupner) Hott-Sensoren 
nachbilden, das SumD-Protokoll auswerten, PWM-Out, PPM-Out, 
Schaltfunktionen, Sensoren wie Strom, Temperatur, ... auswerten.

von Wilhelm M. (wimalopaan)


Lesenswert?

Reinhard M. schrieb:
>> Jetzt weiß ich nicht, was Du wissen möchtest. Fangen wir mit "Hello
>> World" an:
>
> Du hast von parametrischer Polymorphie geschrieben.

Ok. ein etwas größeres Beispiel.

Hier hat man jetzt schon eine EventQueue, man kann beliebig viele 
logische Timer erstellen (hier nur einer), man hat Ausgabe (hier per 
simavr-console, geht aber auch einfach über USART, SW/HW-SPI, SW-Usart 
..., indem man terminal umdefiniert). Man hat schon (sieht man nicht) 
constant-rate Adapter und variable-rate Adapter...

Die Größe dieses Programm sind 998 Bytes auf einem ATMega328p.
1
#include "mcu/ports.h"
2
#include "hal/softtimer.h"
3
#include "console.h"
4
#include "simavr/simavrdebugconsole.h"
5
6
#include <stdlib.h>
7
8
using systemClock = AVR::Timer8Bit<0>;
9
using systemTimer = Timer<systemClock>;
10
11
using sampler = PeriodicGroup<systemTimer>;
12
13
using terminal = SimAVRDebugConsole;
14
namespace std {
15
    std::basic_ostream<terminal> cout;
16
    std::lineTerminator<CRLF> endl;
17
}
18
19
class TimerHandler : public EventHandler<EventType::Timer> {
20
public:
21
    static void process(const uint8_t&) {
22
        std::cout << "Hello"_pgm << std::endl;
23
    }
24
};
25
26
int main()
27
{
28
    Scoped<EnableInterrupt> interruptEnabler;
29
    systemTimer::init();
30
    auto tid1 = systemTimer::create(1000_ms, TimerFlags::Periodic);
31
    using handler = EventHandlerGroup<TimerHandler>;
32
    EventManager::run<sampler, handler>([](){});
33
}
34
ISR(TIMER0_COMPA_vect) {
35
    sampler::tick();
36
}
37
38
void assertFunction(bool b, const char* function, const char* file, unsigned int line) {
39
    if (!b) {
40
        std::cout << "Assertion failed: " << function << "," << file << "," << line << std::endl;
41
        abort();
42
    }
43
}

Und die noch die Config:
1
#pragma once
2
3
#include <stdint.h>
4
#include "std/literals.h"
5
6
using namespace std::literals::chrono;
7
using namespace std::literals::physical;
8
9
struct Config final
10
{
11
    static constexpr std::megahertz fMcuMhz {F_CPU / 1000000};
12
    static constexpr std::hertz fMcu{F_CPU};
13
14
    static_assert(fMcuMhz.value <= 20, "F_CPU too high");
15
    static_assert(fMcuMhz.value >=  1, "F_CPU too low");
16
17
    struct Timer {
18
        static constexpr uint8_t NumberOfTimers = 8;
19
        static constexpr std::hertz frequency = 100_Hz;
20
        static constexpr std::milliseconds resolution = std::duration_cast<std::milliseconds>(1 / frequency);
21
    };
22
    struct EventManager {
23
        static constexpr uint8_t EventQueueLength = 32;
24
    };
25
    struct Usart {
26
        typedef uint8_t SizeType;
27
        static constexpr SizeType SendQueueLength = 64;
28
        static constexpr SizeType RecvQueueLength = 0;
29
    };
30
    struct SoftSpiMaster {
31
        static constexpr std::microseconds pulseDelay = 1_us;
32
    };
33
    struct Button {
34
        static constexpr uint8_t buttonTicksForPressed = 100_ms * Timer::frequency;
35
    };
36
37
    static constexpr bool ensureTerminalOutput = true;
38
    static constexpr bool disableCout = false;
39
};
40
41
constexpr std::hertz Config::fMcu;
42
constexpr std::megahertz Config::fMcuMhz;
43
constexpr uint8_t Config::Timer::NumberOfTimers;
44
constexpr std::hertz Config::Timer::frequency;
45
constexpr std::milliseconds Config::Timer::resolution;
46
constexpr uint8_t Config::EventManager::EventQueueLength;
47
constexpr Config::Usart::SizeType Config::Usart::SendQueueLength;
48
constexpr Config::Usart::SizeType Config::Usart::RecvQueueLength;
49
constexpr bool Config::ensureTerminalOutput;
50
constexpr bool Config::disableCout;
51
constexpr std::microseconds Config::SoftSpiMaster::pulseDelay;

: Bearbeitet durch User
von Reginald L. (Firma: HEGRO GmbH) (reggie)


Lesenswert?

Reinhard M. schrieb:
> Sorry, aber wenn man 10 Seiten schreiben muss, um einen Einzeiler zu
> ersetzen, dann finde ich das überhaupt nicht geil :(
Naja. Dafür kannst der Endanwender mit einem einzeiler zb. Einen timer 
getriggerten dma mem2mem Vorgang ausführen.
Die Lib wird natürlich länger, logischerweise. aber der nutzen ist am 
Ende enorm. Vorausgesetzt es kommt nicht auf den letzten krümmel Takt 
an.

von Reinhard M. (reinhardm)


Lesenswert?

Wilhelm M. schrieb:
>>> Jetzt weiß ich nicht, was Du wissen möchtest. Fangen wir mit "Hello
>>> World" an:
>>
>> Du hast von parametrischer Polymorphie geschrieben.
>
> Ok. ein etwas größeres Beispiel.

Bist Du vielleicht beim Kormanyos in die Schule gegangen?

Ich habe zweimal geschrieben, was mich interessiert und beides mal 
müllst Du mich mit Belanglosigkeiten zu, die überhaupt nix zeigen.
OK, habe verstanden, dass Du nix zeigen willst.

Ich verzichte auf weitere Beleerungen :(

Reginald Leonczuk schrieb:
>> Sorry, aber wenn man 10 Seiten schreiben muss, um einen Einzeiler zu
>> ersetzen, dann finde ich das überhaupt nicht geil :(
> Naja. Dafür kannst der Endanwender mit einem einzeiler zb. Einen timer
> getriggerten dma mem2mem Vorgang ausführen.

Hm, wenn dem so wäre ... ;)
Ich bin ja Anwender und Bibliotheksentwickler, jedoch mit Schwerpunkt 
Anwender. Deshalb wird ständig neu geschrieben und wieder verworfen ...
... bis ich eben mit der Anwendung zufrieden bin.
Sorry, aber ich habe in dem Beispiel nix entdecken können, was ich jetzt 
nachmachen wollte. Vielleicht habe ich es ja auch nicht verstanden?

von Wilhelm M. (wimalopaan)


Lesenswert?

Reinhard M. schrieb:

> Nehmen wir mal ein nicht-triviales Beispiel:
> ein ATmega88 (und Co) hat 3 verschiedene Hardware-Timer. Wie würdest Du
> die mit Templates abbilden, sodass es keinen Code-Overhead gibt?
> Interrupts der Timer sollen nach wie vor optional bleiben und natürlich
> sollen auch nach wie vor alle Möglichkeiten unterstützt werden.

Willst Du es sehen, oder nicht? Ich möchte Dich auf keinen Fall 
langweilen ...

von mcucpp_timer (Gast)


Angehängte Dateien:

Lesenswert?

Ein Beispiel ATmega644 - Timer-0,-1,-2:
**************************************

AvrTimer_.zip extrahieren und
das ganze Verzeichnis in
Mcucpp_Master/examples einfügen.

AvrTimer_.cppproj in AtmelStudio(6.2)(*) öffnen und kompilieren.

***************************************************************
BaseTimerD _local.h  und
BaseTimerH _local.h  und das Verzeichnis
 ATmega-164-324-644-1284 mit Timer _local.h

 gehören für Normalgebrauch (dann ohne _local) ins Verzeichnis 
\mcucpp\AVR

***************************************************************

Die lebendige Diskussion in diesem Thread ist erfreulich.
Ich persönlich hätte gerne etwas detailliertere Ausführungen
mit kompilierbaren Beispielen.
.
Ich verwende c++/mcucpp für AVR8 und versuche mich (noch mit Mühe)
an c++/mcucpp für STM32_F3.

STM32_spaghetticode & Eclipse sind die Baustellen.

***************************************************************

(*) aktuelle Toolchain:
 *********************
Beitrag "Re: (dauerhaft) aktuelle Toolchain"

von Wilhelm M. (wimalopaan)


Lesenswert?

Lustig, Deine Lösung ist 438 bytes groß,
und meine auch 438 Bytes ;-)

Natürlich finde ich meine (etwas) besser, weil z.B. die Konfiguration 
der Timer auf eine bestimmte Interruptfrequenz eleganter ist, und auch 
das ISR-Händling besser abstrahiert ist.

Fall jemand den Code sehen, dann PN.

: Bearbeitet durch User
von tictactoe (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Die Größe dieses Programm sind 998 Bytes auf einem ATMega328p.

Gehe ich recht in der Annahme, dass (Größenordnung) 950 Bytes davon sich 
damit beschäftigen, Text über die Pins hinauszuquetschen?

von Wilhelm M. (wimalopaan)


Lesenswert?

Ein Programm, welches 2 ISRs definiert, und damit eine globale Variable 
manipuliert ist in C 272 Bytes und in C++ 248 Bytes groß für den 
Mega328. Sollte eigentlich gleich sein, doch man sieht, dass dummerweise 
in der C Isr viel zuviel gepushed wird.

von Vincent H. (vinci)


Lesenswert?

Reinhard M. schrieb:
> Ich verzichte auf weitere Beleerungen :(

Ich hab mir deine AVR-libCPP aus dem anderen Thread runtergeladen. Wenn 
das obige Beispiel belanglos is, in welche Kategorie fällt dann deine 
"Library"?

von Reinhard M. (reinhardm)


Lesenswert?

@mcucpp_timer
Danke für die Beispiele. Allerdings sehe ich (noch?) keine Polymorphie.
Die Registermaps finde ich dagegen toll, habe die auch schon so 
eingesetzt.
Womit ich (bei meinem Projekt) noch nicht richtig glücklich bin, ist die 
Abstraktion der einzelnen AVR-controller. Ich mag einfach nicht für jede 
CPU alle Dateien kopieren, wenn sich nur ein/zwei Zeilen ändern.

Werde da wohl doch bei den gewohnten defines bleiben :O

> Ich hab mir deine AVR-libCPP aus dem anderen Thread runtergeladen. Wenn
> das obige Beispiel belanglos is, in welche Kategorie fällt dann deine
> "Library"?

Lach - guter Einwand :)

Nun - ich hatte nach templates und parametrierter Polymorphie gefragt.
Weder das eine noch das andere war in dem Codebeispiel.
Wofür also war das Codegeplemper gut?
Es verdeutlicht nix, außer vielleicht die Diskrepanz zwischen den 
vollmundigen Äußerungen eines Wilhelm M. und seiner tatsächlichen 
Codequalität :O

Meine Klassen sind vielleicht auch belanglos. Keine Ahnung.
Aber die Beispiele sind komplett, lassen sich übersetzen und 
funktionieren.
Wer sich also was anschauen will, findet alles in dem Upload (zumindest 
dem aus dem letzten Beitrag).

von Wilhelm M. (wimalopaan)


Lesenswert?

Reinhard M. schrieb:

> Nun - ich hatte nach templates und parametrierter Polymorphie gefragt.
> Weder das eine noch das andere war in dem Codebeispiel.

Jetzt lache ich auch mal ganz laut!

1) Der obige Code besteht NUR aus templates.

2) Als parametrische Polymorphie bezeichnet man in C++ den Einsatz von 
Funktions- und Klassen-Templates.

Deshalb würde ich Dir raten: beschäftige Dich etwas intensiver damit!

von Reginald L. (Firma: HEGRO GmbH) (reggie)


Lesenswert?

Reinhard M. schrieb:
> Hm, wenn dem so wäre ... ;)
Also in meiner stm-Lib ist das so.

Reinhard M. schrieb:
> Sorry, aber ich habe in dem Beispiel nix entdecken können, was ich jetzt
> nachmachen wollte. Vielleicht habe ich es ja auch nicht verstanden?
Na kann ja sein, dass das eben nix für dich ist :)
Ich finde es recht praktisch:
Du hast in der ISR die aktuelle Klasseninstanz und static fällt weg. du 
kannst so richtig feine callbacks  einsetzen.

von Reinhard M. (reinhardm)


Lesenswert?

@Reginald Leonczuk
heue morgen hatte ich etwas Zeit und Muße, mir den Link aus Deinem 
ersten Beitrag genauer zu Gemüte zu führen.
Ich würde mal so sagen: prinzipiell der richtige Weg. Aber mit den 
Modellierungsschritten bin ich nicht einverstanden.

Ausgangsthese in dem Artikel ist ja, dass ein device einen Interrupt 
hat.
Meiner Ansicht nach überspringt dieser Ansatz aber wichtige Schritte.

Für mich sieht es so aus, dass ein device aus Hardware-Modulen besteht 
und jedes dieser Hardware-Module kann beliebig viele Interrupts haben 
(es gibt ja - zumindest bei AVRs die Möglichkeit, softwaremäßig 
Interrupts auszulösen).
Die Anwendung würde aus div. Schichten bestehen. Die unterste Schicht 
wäre die Hardware-Abstraktion, wo ich die Hardware-Module über Klassen 
abbilden würde. Diese sollten möglichst frei von Anwendungscode und 
somit konstant zwischen unterschiedlichen Anwendungen sein.
Diese Anforderung kann aber von den Interrupts nicht erfüllt werden, 
weshalb sie auf einer höheren Abstraktionsebene liegen (für mich auf der 
höchsten, nämlich der Anwendungsebene, aber darüber kann man streiten).
Aus dieser Sicht ergibt sich die Notwendigkeit, dass die unterste Ebene 
Interruptfunktionen empfangen und einsortieren können muss - also die 
Anwendungschicht teilt dem Hardware-Modul mit: hier habe ich eine 
Funktion, die als Interrupt für Event XYZ ausgeführt werden soll.
Im Interrupt ist sowohl der Zugriff auf die Daten des Hardware-Moduls, 
wie auch der Zugriff auf die Daten des Anwendungsmoduls notwendig.
Die Möglichkeit, hier auf friend-Deklaration zurück zu greifen halte ich 
für falsch, weil ein Objekt einer höheren Schicht in einer niederen 
Schicht bekannt gemacht werden muss, was die Grundsätze der 
Datenkapselung verletzt.

Ich habe das Problem leider noch nicht gelöst, kann also nur schreiben, 
was mich an dem Ansatz in dem Artikel stört. Prinzipiell denke ich zwar 
in die gleiche Richtung, will es aber anders umsetzen.

Deshalb: herzlichen Dank für Deine Denkanstöße!

Mir gefällt die Technik von ST der leeren Defaultimplementierung, die 
als "weak" deklariert ist. Somit könnte die Funktion auf Anwendungsebene 
ersetzt werden, ohne auf schmutzige Hacks angewiesen zu sein. Ob das 
allerdings auch in C++ funktioniert, habe ich noch nicht ausprobiert.

von Vincent H. (vinci)


Lesenswert?

Mir persönlich gefällt die Idee des universellen Interrupt-Handlings 
auch nicht, auch wenn ich den Ansatz und den Code sehr sauber find. Ich 
verwende schlichtweg Callbacks, die von den statischen Member-Funktionen 
innerhalb meiner Templates aufgerufen werden. Da Interrupts sowieso 
ausschließlich void(void) sein können, müssen die Callbacks nichtmal 
sonderlich generisch sein.

Der entscheidende Nachteil dieser Variante ist, dass für jeden Interrupt 
der genutzt werden will ein C-Wrapper innerhalb der Bibliothek angelegt 
werden muss. Geht man aber davon aus, dass man bei einem neuen Chip 
ohnehin einmal sämtliche Register und sonstiges Schmafu implementieren 
muss, kann man die Wrapper auch gleich anlegen... Die Schreibarbeit ist 
bei so gut wie allen Methoden die gleiche. Wer die Vektortabelle nicht 
neu schreibt, der muss irgendwo die Namen der Interrupts reinklopfen.

Der Vorteil von einem 0815 Callback ist, dass man ihn zur Laufzeit stets 
ändern kann. Außerdem bleibt man bei der Implementierung extrem 
flexibel. Ein void(void) Callback kann in C++ ja schlichtweg alles sein.

Normale Funktion, Member Funktion, Statische Member Funktion, Lambda, 
Func(k?)tor (grrr dieses Deutsch), usw. usf.

von Wilhelm M. (wimalopaan)


Lesenswert?

Vincent H. schrieb:

> Normale Funktion, Member Funktion, Statische Member Funktion, Lambda,
> Func(k?)tor (grrr dieses Deutsch), usw. usf.

Genau!
Ich schreibe in jede C-ISR den Aufruf eines Interrupt-Dispatchers 
hinein: und da der Typ des Interrupts ja statisch ist, geschieht das 
Dispatching auch durch template-Mechanik statisch. Und die eigentlichen 
ISR-Callbacks registriere ich auch statisch bei dem Dispatcher.

von Reginald L. (Firma: HEGRO GmbH) (reggie)


Lesenswert?

Reinhard M. schrieb:
> Deshalb: herzlichen Dank für Deine Denkanstöße!
Genau das War meine Intention :)

Ich komme aus dem maschinenbau weshalb ich hier also bei weitem nicht so 
tief in der Materie stecke wie du.
Ich wollte halt eine Möglichkeit die Interrupts mit der Peripherie zu 
verbinden (Hardware ebene), damit ich mit einem einzeiler eine ganze 
dma/isr/Peripherie einschalten kann.

Reinhard M. schrieb:
> Die Anwendung würde aus div. Schichten bestehen. Die unterste Schicht
> wäre die Hardware-Abstraktion, wo ich die Hardware-Module über Klassen
> abbilden würde. Diese sollten möglichst frei von Anwendungscode und
> somit konstant zwischen unterschiedlichen Anwendungen sein.
Teilweise habe ich das bei mir schon implementiert. Allerdings ist es 
schwierig hier eine Linie zu ziehen, da der Anwender, je nach Anwendung, 
zb. nur einen puren Timer mit isr braucht.
Im großen und ganzen bin ich aber mit meiner Lib um Längen besser 
bedient als mit der spl oder hal von St.

von Reinhard M. (reinhardm)


Lesenswert?

Reginald Leonczuk schrieb:
>> Die Anwendung würde aus div. Schichten bestehen. Die unterste Schicht
>> wäre die Hardware-Abstraktion, wo ich die Hardware-Module über Klassen
>> abbilden würde. Diese sollten möglichst frei von Anwendungscode und
>> somit konstant zwischen unterschiedlichen Anwendungen sein.
> Teilweise habe ich das bei mir schon implementiert. Allerdings ist es
> schwierig hier eine Linie zu ziehen, da der Anwender, je nach Anwendung,
> zb. nur einen puren Timer mit isr braucht.

Yepp! Den Aspekt decke ich bislang mit bedingter Übersetzung ab und 
einer Config-Datei, in der bestimmt wird, welche Module verwendet 
werden.

Bei den (nativen) Interrupt-Funktionen ist es ja so, dass die in der 
Firmware auftauchen, auch wenn die Interrupts garnicht verwendet werden. 
Auch deshalb mag ich die Methode mit dem "weak" ;)
Yo, also da muss ich einfach etwas nachforschen und ausprobieren - was 
ich jetzt angehe ;)

> Im großen und ganzen bin ich aber mit meiner Lib um Längen besser
> bedient als mit der spl oder hal von St.

Das glaube ich Dir unbesehen. hal von St ist nicht darauf angelegt, 
Freunde zu finden =:O

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.