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?
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.
> 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 :(
Reinhard M. schrieb: > hier fand ich den Hinweis, dass man mit inline-Assembler den gemerkelten von Angela "ge-merkelt"? -> ge-mangled
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
> 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.
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
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.
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 | }
|
Aah! Endlich einer, der kapiert hat, wie man einen MCU mit C++ programmiert. Gibt's das als Library, oder ist das selbst erfunden?
> 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.
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.
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
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.
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?
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 ...
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"
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
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?
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.
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"?
@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).
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!
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.
@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.
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.
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.
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.