Forum: Mikrocontroller und Digitale Elektronik Beispiele für gute, modulare embedded Software Architektur


von jk (Gast)


Lesenswert?

Hallo,

ich bin auf der Suche nach Literatur/Beispielen wiederverwendbare, 
modulare Architekturen auf mittleren MCUs (Cortex M3-M4, maximal M7).

Momentan wächst die Komplexität meiner Programme sehr schnell und ich 
muss zwingend meine Firmwares stärker modularisieren und entkoppeln um 
die Wiederverwendbarkeit und die Pflege zu vereinfachen.
Ich programmiere momentan in C (99), bin aber auch von C++ grundsätzlich 
nicht abgeschreckt.

Dass man grundsätzlich Interfaces definiert um eine möglichst schwache 
Kopplung zu erreichen ist mir klar. Dass man callbacks und dependency 
injection verwenden kann auch in der Theorie.
Was ich suche sind aber konkrete Anwendungsbeispiele.

Hier sind ein paar Beispiele, worüber ich mir den Kopf zerbreche
- Modul für einen Sensor, das möglichst ohne Anpassungen auch auf einem 
andern uC (beschränken wir uns mal auf die Cortex-M) laufen kann. Der 
Sensor kann entweder per SPI oder I2C angesprochen werden. Ich könnte 
zwei Init Methoden schreiben, (SPI und I2C), die z.B. den Zeiger auf die 
Peripherie bekommen (inkl. GPIO Port, Geschwindigkeit etc - recht 
umständlich und nicht portabel), oder ich gebe Funktionspointer zum 
Initialisieren mit, müsste dann aber die Kapselung etwas aufbrechen.
- RS485 wrapper auf "normaler" USART (rs232) - sehr ähnliche Probleme 
wie oben, wann wo initialisiere ich die Peripherie?
- Kommunikationsmodul, das unabhängig von der Schnittstelle (CAN, RS485 
etc) den Protokollparser enthält und je nach Anforderung Daten schreibt 
oder zurück gibt. Dafür muss das Modul aber alle anderen Teilmodule 
kennen (bzw. deren Instanzzeiger), macht man das so?
- Flash/EEPROM: Bisher war es so, dass es eine große flash.h gab, in der 
Adressen/Register für alle Teilmodule definiert wurden. Adressen mussten 
manuell inkrementiert werden (waren alles nur defines in dem Header). 
Das ist sehr fehleranfällig und auch nicht schön, weil 
Implementationsdetails (welche zu speichernden Parameter hat das Modul 
z.B.) aus allen anderen Modulen nötig sind.

Wie macht man solche Sachen sinnvoll?

Vielen Dank für euren Input!

von Eric B. (beric)


Lesenswert?

jk schrieb:
> ich bin auf der Suche nach Literatur/Beispielen wiederverwendbare,
> modulare Architekturen auf mittleren MCUs (Cortex M3-M4, maximal M7).

AutoSAR.

von Mark B. (markbrandis)


Lesenswert?

jk schrieb:
> Wie macht man solche Sachen sinnvoll?

Indem man die Teile, die hardwarespezifisch sind, von der eigentlichen 
Funktionalität entkoppelt.

Die eigentliche Funktionalität ist zum Beispiel eine Berechnung. Oder 
vielleicht die Abarbeitung eines Protokolls. Diesen Teil kann man so 
schreiben, dass der exakt gleiche Code auf den verschiedensten 
Plattformen kompiliert werden kann. So kann man den Code z.B. auch auf 
dem PC laufen lassen, um ihn dort zu testen.

von jk (Gast)


Lesenswert?

Eric B. schrieb:
> jk schrieb:
>> ich bin auf der Suche nach Literatur/Beispielen wiederverwendbare,
>> modulare Architekturen auf mittleren MCUs (Cortex M3-M4, maximal M7).
>
> AutoSAR.

Gucke ich mir an.

Mark B. schrieb:
> Indem man die Teile, die hardwarespezifisch sind, von der eigentlichen
> Funktionalität entkoppelt.

Das versuche ich ja bereits. Das Kommunikationsmodul z.B. bekommt nur 
einen Eingangs- und Ausgangspuffer, die Quelle ist egal. Dennoch braucht 
dieses Modul viele Informationen aus anderen Modulen.

Aber auch die hardwarespezifischen Dinge müssen konfigurierbar und 
modular bleiben, um Port, Device etc einstellen zu können.

Die Flash Geschichte wurmt mich, wie kommt man da von einem globalen 
Ansatz weg?

von W.S. (Gast)


Lesenswert?

jk schrieb:
> Aber auch die hardwarespezifischen Dinge müssen konfigurierbar und
> modular bleiben, um Port, Device etc einstellen zu können.

Nö. Hardwarespezifische Dinge sind eben HARDWARESPEZIFISCHE Dinge. Da 
ist nix modular und so.

W.S.

von Sheeva P. (sheevaplug)


Lesenswert?

jk schrieb:
> ich bin auf der Suche nach Literatur

http://shop.oreilly.com/product/0636920017776.do

Das ist zwar im Wesentlichen auf C bezogen, die Konzepte und Ideen 
lassen sich aber auch -- und oft viel eleganter -- mit C++ umsetzen. 
HTH, YMMV.

von A. S. (Gast)


Lesenswert?

Du hast 3 Themen angesprochen, für die es verschieden Lösungen gibt, 
jedoch nicht bei nur vagen Andeutungen.

Beispiel Flash: hier geht von Linker machen lassen über Verzeichnisse 
bis Quelltext-Parser alles mögliche. Es ist aber z.B. wichtig zu wissen, 
ob neue Software alte Parametersätze lesen können muss.

Beim Sensor oder auch bei den Kommunikationsprotokollen: Eine 
Generalisierung ist nur unter Kenntnis der bisherigen Anforderungen 
möglich. Die Verschiedenheit (Uart/CAN: beliebig lange Telegramme vs. 
feste Grenzen, P2P vs. Bus etc) macht einen "allgemeinen" Ansatz 
wertlos.

Wenn Du den Sensor mit 3 oder 4 direkten Zugriffsfunktionen ausreichend 
Steuern kannst (z.B. Reset, Bytes Lesen, Bytes schreiben), dann schreibe 
lieber 2 getrennte Treiber (SPI und I2C), die Dir Funktions- und 
Kontextpointer liefern, die Du nach der Initialsierung verwendest.

Denke auch über Code-Kopien nach. Nicht manuell, sondern automatisch in 
der Makeumgebung. Wenn Du konkrete Sensoren oder Hardware hast, dann 
kann direkter verdreifachter Code deutlich effektiver sein als jeweils 
was generisches mit Übergabe des Kontexts.

Und über alle Arten von Textfressern, die Dir z.B. das Parameter-Layout 
beim Make generieren, indem die jeweiligen Initialisierungen geparst 
werden. Bei größeren Quellen kann es auch sinnvoll sein, aus den 
C-Quellen bestimmte Zeilen herauszuparsen und daraus quasi ein 
"C-Skript" zu machen, also das zu einem C-File zusammenfügen und per gcc 
und Kommandozeile output zu generieren. Beispiel: Wenn Du wissen willst, 
wie groß "MAX_ANZAHL" ist, kannst Du den Original-Code vom 
Cross-Präprozessor bearbeiten lassen und dessen Output direkt in gcc 
verwenden ('printf("%i", MAX_ANZAHL;').

Gebe uns also ein Beispiel, egal ob Source-File oder Pseudocode.

von A. S. (Gast)


Lesenswert?

Ein Link noch:

https://www.duckware.com/bugfreec/index.html

Nichts was ich direkt so umsetzen würde, teils veraltet. Aber die 
Konzepte sind ein guter Start. Und m.W. der erste, der 
Compile-Time-Asserts in C propagiert hat.

von Ben W. (ben_w)


Lesenswert?

ich mag das openSource project chibiOS 
(http://www.chibios.org/dokuwiki/doku.php)

das sind 2 verschiedene RTOS kernels mit möglichst gleicher API und eine 
HAL.

leider hauptsächlich in C

von jk (Gast)


Lesenswert?

W.S. schrieb:
> jk schrieb:
>> Aber auch die hardwarespezifischen Dinge müssen konfigurierbar und
>> modular bleiben, um Port, Device etc einstellen zu können.
>
> Nö. Hardwarespezifische Dinge sind eben HARDWARESPEZIFISCHE Dinge. Da
> ist nix modular und so.
>
> W.S.

Ja, es ist auf eine MCU abgestimmt. Trotzdem muss es konfigurierbar 
sein.

An alle anderen: Vielen Dank, werde mir die Buchtipps anschauen!

@Achim: top, ich muss über ein einfaches Pseudocode Beispiel nachdenken, 
danke.

Ich habe gar nichts gegen C, im Gegenteil, es es mein 
Hauptentwicklungswerkzeug :)

von chris_ (Gast)


Lesenswert?

Nach einem wirklich schlüssigen Konzept für Plug- and Play Module suche 
ich auch schon länger.

Das Beispiel hier ist tatsächlich ein wenig von AUTOSAR inspiriert:

Beitrag "Re: Plug and Play Interface Konzept für Module in C"

Ich kenne es so, das dort die Module über die sogenannte RTE verknüpft 
werden.
Das kann dazu führen, dass die RTE dann zu einer riesigen Anzahl von 
Include Files führt, die dann die verschiedenen Interfaces miteinander 
verknüpfen.
Das sieht erst mal ziemlich umständlich aus und ist auch lästig beim 
Code verfolgen in einer IDE, weil die Verknüpfungen oft über "#defines" 
gemacht werden und dann die IDE dem Pfad nicht mehr folgen kann.
Mittlerweile scheint mir das aber ein gangbarer Weg, die Module wirklich 
zu entkoppeln.

von Flash Gordon (Gast)


Lesenswert?

> Die Flash Geschichte wurmt mich, wie kommt man da von einem globalen
> Ansatz weg?

Dateisystem!
Es muss nicht eins sein mit allen Schikanen, da gibt's auch ganz simple.
(z.B. RO von Daten welche at build Time C-Quellcode werden)


Steigen später die Ansprüche, kommt zwar ein raffinierterer FS-Treiber 
dazwischen, aber nach mount bleibt's bei /fopen(..)/ & Co.

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.