Hallo,
ich brauche für mein Projekt mehrere SPIs, so dass ich mindestens einen
'von Hand' relaisieren muss. Hierfür habe ich nach lektüre der
hardwaremäßigen Implemntierung folgendes für den Preprozessor
ausgedacht:
1
enumenSPIDataMode
2
{// Clk On at Idle Leading Edge Sample
3
SPI_MODE0,// 0 0
4
SPI_MODE1,// 0 1
5
SPI_MODE2,// 1 0
6
SPI_MODE3,// 1 1
7
};
8
9
enumenSPIDataDirection
10
{
11
SPI_MSB_FIRST=0,
12
SPI_LSB_FIRST
13
};
14
15
#define SPI_CREATE_SHIFT_FUNCTION( iSPIInstance, /* instance of SPI */\
WinAVRs gcc schluckt das ganze soweit.
Warum die Funktion als Makro?
Schon mit niedriger Optimierung weiss gcc, dass er gewisse Dinge nicht
wirklich kompilieren muss und die Bit-Schieberein selbst erledigen kann.
Es kommt geschmeidig kleiner footprint raus.
Vergeben tue ich auch nichts, weil ich die Port- und
Kommunikations-Einstellung nicht gedenke, während Laufzeit zu verändern.
Das ganze hat nur einen kleinen Haken: Der Debugger kennt die Funktion
SPIBitBangedShiftData0 nur als Ganzes und auf dem Simulator sehen
gewisse Dinge Totschleifen erschreckend ähnlich.
Um das zu testen, würde ich gerne die Ausgabe des Präprozessors in eine
Datei umleiten. Das kopiere ich mir für verschiedene Fälle heraus und
lasse das kompilieren.
In der Doku von gcc hab ich folgendes gefunden:
1
-o file Write output to file. This is the same as specifying file as the second non-option
2
argument to cpp. gcc has a different interpretation of a second non-option
3
argument, so you must use ‘-o’ to specify the output file.
Hm.. Das konfliktet mit dem Parameter für die Object-Datei.
Ich habe wirklich ehrlich gesucht, jedoch nichts brauchbares gefunden.
Also hat jemand einen Link oder..
Anstatt Makro ginge doch auch static inline?
Mit Debug-Stufe -g3 werden auch Infos für Makrodebugging erzeugt, aber
AFAIR unterstützen das nicht alle Debugger.
Um das Präcompile zu schreiben (%.i für C bzw. %.ii für C++) gibt man
gcc ein -save-temps und erhält Präprozess und Assembler-Ausgabe vom
Compiler im aktuellen Verzeichnis (anstatt als tmp-Dateien).
Das %.i kannst du abenso compilieren wie ein %.c, allerdings stehen das
Line-Direktiven drin, die auf die ursprüngliche Quelle verweisen.
Andreas Müller wrote:
> Hm.. Das konfliktet mit dem Parameter für die Object-Datei.
Nein, -o file gibt immer die primäre Ausgabedatei an. Wenn du mit
-c compilierst, ist das eine Objektdatei, wenn du mit -S compilierst,
ist es eine Assemblerdatei, und wenn du mit -E ,,compilierst'', dann
ist das eine Datei, die den präprozessierten C-Code enthält. Der dafür
übliche Suffix ist .i. (-E ohne -o file gibt den Code nach stdout
aus, dort kann man ihn mit "> dateiname" umlenken. avr-gcc -E ist
damit effektiv das gleiche wie das Kommando avr-cpp, was dir schon
genannt worden ist.)
>Anstatt Makro ginge doch auch static inline?
1. Mit welchem Typ soll ich PORTA übergeben?
2. Inline hilft in meinem Fall nicht, da ich Funktionspointer auf die
Funktionen anlegen möchte. Dann hat gcc keine Chance und bläht die
Funktion auf, da er nicht weiss, welche Werte die Parameter haben
werden.
@Jörg: Danke: jetzt fange ich an zu begreifen, was ich in der Doku zu
Beginn des Abschnitts über Präprozessor Optionen gelesen habe.
Andreas Müller wrote:
>>Anstatt Makro ginge doch auch static inline?>> 1. Mit welchem Typ soll ich PORTA übergeben?
DU müsstest dann die Adresse von PortA übergeben:
1
foo(uint8_tvolatile*port)
2
{
3
*port|=(1<<3);
4
}
5
6
foo(&PORTA);
Dann muss die Funktion aber geinlinet werden, ansonsten gibt das
hässlichen und vor allem nicht-atomaren Code.
> 2. Inline hilft in meinem Fall nicht, da ich Funktionspointer auf die> Funktionen anlegen möchte.
Kannst du mit Makros doch auch nicht.
Momentan verwendest du das Makro, um die Implementierung der Funktion zu
erzeugen.
Du könntest aber auch anstatt eine Implementierung zu erzeugen, eine
"allgemeine" Implementierung machen und in den Code einfügen lassen,
statisch verwendet wird das ja wohl nur an wenigen Stellen in der
Endanwendung.
Falls jedoch F-Zeiger gebraucht werden, dann ist eine Erzeugung der
Implementierung via Makro wohl nicht schlecht, sofern man nicht den
Überblick verliert :-)
>Kannst du mit Makros doch auch nicht.
hat doch mit dem Makro nichts zu tun. Ich habe lediglich eine Funktion
erzeugt. Ich sehe kein Problem, darauf einen Pointer zeigen zu lassen.
Ich habe das Makro noch ein bischen überarbeitet und bin sehr mit dem
Ergebnis zufrieden. Es ist schon genial was der Compiler alles so beim
Optimieren erkennt: In der oben angegebenen Version hatte ich als
Endekriterium verwendet, dass das letzte Bit aus der Maske rausgeschoben
wird (==0). Der Compiler erkennt, dass diese Schleife 8* durchlaufen
wird und legt dafür einen Schleifenzähler an. Dummerweise legt er diesen
Schleifenzähler 16Bit breit an. Daher habe ich noch einen 8Bit
Schleifenzähler angelegt, der von 8 runterzählt. Lässt man das mit -O3
kompilieren liegt das Ergebnis nur unweit von dem, was in Assembler
möglich gewesen wäre!