Forum: Mikrocontroller und Digitale Elektronik Wie wiederverwendbaren (C) Code für verschiedene AVRs


von adrock (Gast)


Lesenswert?

Hallo,

vorab: Sollte es zu diesem Thema bereits irgendwo etwas geben was passt, 
bitte gerne verlinken. Zumindest auf die Schnelle habe ich hier nichts 
gefunden.

Was ich mir vorstelle:

Oft hat man sowohl in C als auch ASM das "Problem", dass man zum einen 
wiederverwendbaren Code haben möchte, sich aber viele Sachen was die 
Hardware betrifft zwischen verschiedenen Projekten variieren.

Beispiel:

Ich habe eine tolle PWM Ansteuerung in ASM geschrieben. In einem Projekt 
hängen die LEDs an Port A/B, im anderen Projekt an Port B/C. Mal ist es 
eine 4x4 Matrix, mal eine 8x8 Matrix etc.

Natürlich kann man jetzt hingehen und den Code so generisch 
programmieren, das viele Sachen erst zur Laufzeit parametriert werden. 
Aber das kostet wieder Zeit. Viel sinnvoller wäre es doch, die 
"Rahmenbedingungen" per #define zur Übersetzungszeit anzugeben.

Und wie macht man DAS nun genau am besten?

Den Sourcecode "includen" finde ich unsauber, da auch dadurch jedesmal 
alles eingebundenene mit neu übersetzt wird.

Kann ich (in Atmel Studio 6) den Sourcecode aus einem anderen 
Verzeichnis ziehen, die Objektdatei aber im aktuellen Arbeitsverzeichnis 
erstellen lassen?

Also z.B. für die Übersetzung folgende Struktur haben:

MyProject\main.c -> MyProject\main.o
Common\superpwm.c -> MyProject\superpwm.o

Wobei der Sourcecode in Common\superpwm.c ein #include 
"superpwm_config.h" machen soll, aus dem er die Parametrierung (welche 
Ports, Anzahl der LEDs etc.) zieht, und diese Includedatei soll 
natürlich ebenfalls aus dem MyProjekt-Verzeichnis kommen.

Und dann alles zum fertigen elf/hex in MyProject verlinken.

Ich hoffe es ist klar geworden was ich erreichen möchte? Unter Linux 
würde ich einfach im Projektverzeichnis einen (Soft-)Link auf den 
gemeinsam zu nutzenden Sourcecode erstellen: superpwm.c -> 
/home/bla/common/superpwm.c

Aber es ist ja nunmal Windows (XP), und da sind Links nicht ganz so 
einfach zu machen.

Viele Grüße
Markus

von Achim M. (minifloat)


Lesenswert?

adrock schrieb:
> Viel sinnvoller wäre es doch, die
> "Rahmenbedingungen" per #define zur Übersetzungszeit anzugeben.

Es ist keine schlechte Idee, möglichst viele Sachen von vornherein als 
#define anzulegen. Bei günstiger Benennung der Makros kommentiert sich 
später der Code von selbst.

adrock schrieb:
> Aber es ist ja nunmal Windows (XP), und da sind Links nicht ganz so
> einfach zu machen.

Warum nicht einfach in der Nähe der AVR-GCC-Standard-Lib deine eigene 
codesammlung anlegen? An die kommt man dann per #include 
<meinelib/lalala.h> genau so einfach ran.

Ich machs immer erstmal so, dass ich mir die Sachen, die ich woanders 
schonmal funktionierend habe, einfach mit ins aktuelle 
Projektverzeichnis mit rein ziehe und im makefile mit eintrage. Dass das 
jetzt 200ms länger zum neu dazukompilieren braucht, stört mich nicht 
weiter. Projekte werden nur im Ganzen archiviert. Wenn ich was an den 
Schnipseln ändere, wird das im Projekt so verankert. Sonst müsste ich 
moch eine eigene Versionskontrolle für meine Schnipsel aufmachen... Kann 
ja sein, dass ein Schnipsel plötzlich nicht mehr abwärtskompatibel 
ist...

Hat sich ein Codeschnipsel bewährt, kommen .c und .h Datei in einen 
"Snippets" Ordner. Da ist dann alles thematisch und funktional geordnet 
drin. Wenn an einem Snippet optimiert wurde und ich halte es für nötig, 
das mit zu sichern, wird die Neuerung nicht nur im aktuellen Projekt 
sondern auch im Snippets-Ordner eingepflegt.

mf mf

PS: In FAT32 kann man Hardlinks setzen bzw. "dazupfuschen". Das geht nur 
solange gut, bis jemand den Datenbereich woanders hinschiebt oder 
löscht. BUMM! Es gibt nämlich imho keinen Link-Count...

von Josef (Gast)


Lesenswert?

für jede Hardware ein eigene include Datei anlegen und je nach HW 
includen:

ZB:

Hardware1.c

#define LEDPORT  PORTB
#define LED1     LEDPORT.2
...

#define MATRIXPORT PINC
#define ROW1       MATRIXPORT.0
#define ROW2       MATRIXPORT.1

...
Hardware2.c

#define LEDPORT  PORTA
#define LED1     LEDPORT.2
...

#define MATRIXPORT PINB
#define ROW1       MATRIXPORT.0
#define ROW2       MATRIXPORT.1

von adrock (Gast)


Lesenswert?

Hmmm...

ok, also das mit dem einfach include von "mylib/source.h" geht schonmal 
schief, wenn man gemischt C und ASM Code in einem Projekt mischt - was 
ich ab und zu mache (zeitkritische Sachen in ASM, den Rest in C).

Aber hey, das bringt mich auf eine Idee:

Ich mache in das Projekt einfach eine Art "stub" Datei. Also angenommen 
ich habe in meiner Lib zwei tolle Sachen:

mylib\pwm\fastpwm.S
mylib\math\circle.c

Und möchte beide in meinem Projekt nutzen, dann mache ich

myproject\_fastpwm.S

Inhalt z.B.:

#define ROWPORT PORTA
#define COLPORT PORTB
#define NUMROW 4
#define NUMCOL 4
#include "mylib\fastpwm.S"

und

myproject\_circle.c

Inhalt dann einfach nur:

#include "mylib\circle.c"


So habe ich keine Links, verweise aber dennoch immer auf den aktuellen 
Sourcecode in meiner Lib :-) Und die notwendigen Definitionen für die 
Hardware habe ich auch gleich mit drin.

Grüße
Markus

von adrock (Gast)


Lesenswert?

PS: Sollte natürlich heissen:

#include "mylib\pwm\fastpwm.S"

und

#include "mylib\math\circle.c"

Aber ich glaube so kann man das gut handlen. Sogar die Abhängigkeiten 
sollten hinhauen. So wird nicht unnütz immer das gleiche wieder 
übersetzt, wenn garkeine Änderungen vorhanden sind.

Grüße
Markus

von Roland H. (batchman)


Lesenswert?

> Den Sourcecode "includen" finde ich unsauber, da auch dadurch jedesmal
> alles eingebundenene mit neu übersetzt wird.

Das geht wg. "static inline" und C++ templates mittlerweile gar nicht 
mehr anders. Das hat mit "unsauber" wenig zu tun, weil es der Compiler 
so vorgibt.

> Kann ich (in Atmel Studio 6) den Sourcecode aus einem anderen
> Verzeichnis ziehen, die Objektdatei aber im aktuellen Arbeitsverzeichnis
> erstellen lassen?

Wie es im Studio aussieht, weiß ich nicht. Bei GNU makefiles ist es 
VPATH.

Damit mache ich es prinzipiell so, wie Du skizziert hast.

> Unter Linux
> würde ich einfach im Projektverzeichnis einen (Soft-)Link auf den
> gemeinsam zu nutzenden Sourcecode erstellen: superpwm.c ->
> /home/bla/common/superpwm.c

VPATH erledigt dies, das sollte dann auch unter Windows funktionieren. 
Symlinks innerhalb von SW-Projekten, evtl. noch im Zusammenspiel mit 
Versionskontrollsystemen ... kann gut gehen, muss aber nicht.

> Ich machs immer erstmal so, dass ich mir die Sachen, die ich woanders
> schonmal funktionierend habe, einfach mit ins aktuelle
> Projektverzeichnis mit rein ziehe und im makefile mit eintrage.

Und da ist nie ein Bug drin? Und es wird nie ergänzt?

> Wenn an einem Snippet optimiert wurde und ich halte es für nötig,
> das mit zu sichern, wird die Neuerung nicht nur im aktuellen Projekt
> sondern auch im Snippets-Ordner eingepflegt.

Wenn aber ein Bug gefunden wird, muss dies überall nachgezogen werden.
Refactoring macht auch keinen Spaß.

Der Vorteil mag darin liegen, dass eine neue oder geänderter Version 
andere Projekte nicht betrifft. Es kann auch übersichtlicher sein.

Hatte ich tatsächlich früher auch so gemacht, aber die Wartung war ein 
Graus. Inzwischen lebe ich damit, dass ein Querschläger irgendwo 
auftritt, der Schmerz ist m. E. geringer.

adrock schrieb:
> So habe ich keine Links, verweise aber dennoch immer auf den aktuellen
> Sourcecode in meiner Lib :-) Und die notwendigen Definitionen für die
> Hardware habe ich auch gleich mit drin.

Wie schon geschrieben, ich verwende VPATH. In den "common header files" 
wird grundsätzlich ein "config.hpp" inkludiert - das kommt im Prinzip 
vom Projekt. Damit sparst Du Dir die doppelten Dateien.

> Aber ich glaube so kann man das gut handlen. Sogar die Abhängigkeiten
> sollten hinhauen. So wird nicht unnütz immer das gleiche wieder
> übersetzt, wenn garkeine Änderungen vorhanden sind.

Das macht er auch nicht. Via VPATH werden die common-Geschichten 
virtuell eingebunden. Den Rest erledigt das Makefile ganz normal via 
Abhängigkeiten.

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.