Forum: Compiler & IDEs Verständnisproblem #if bei avr-gcc


von Jürgen S. (jsachs)


Lesenswert?

Hallo,

ich versuche zur Compile ZEit code für mehrere CPUs fest zu legen.

z.B.
1
#if MCU == atmega328p
2
    UDR0 = c;
3
#elif MCU == atmega1284p
4
    UDR0 = c;
5
#elif MCU == atmega32
6
    UDR = c;
7
#endif

Also nichts besonderes.

Ist MCU = atmega32 greift aber bereits #if MCU == atmega328p

Mache ich hier was falsch ?
So hatte ich das zumindest laut Anleitung verstanden.
Bisher hatte ich für jede CPU ein "#define _CPU2_" und dann nur noch
1
#if _CPU1_
2
    UDR0 = c;
3
#elif _CPU2_
4
    UDR0 = c;
5
#elif _CPU3_
6
    UDR = c;
7
#endif
Aber das ist ja nicht so toll...

Eventuell kann mir einer ja kurz die Erleuchtung geben.

Danke
Juergen

von Tom W. (nericoh)


Lesenswert?

müsste das erste #if nicht eher ein #ifdef sein?

edit: ne sry, das war Quatsch...

: Bearbeitet durch User
von g457 (Gast)


Lesenswert?

> Ist MCU = atmega32 greift aber bereits #if MCU == atmega328p

Dann haben die Defines atmega32 und atmega328p den selben Wert. Zeig mal 
jene Defines her.

von Tom W. (nericoh)


Lesenswert?

würde da auch Klammern setzen: #if (MCU == ...)

bin nicht sicher, ob der Präprozessor sonst nicht schon das #if MCU als 
wahr interpretiert (wenn MCU ungleich 0 ist)

von JSachs (Gast)


Lesenswert?

Die defines sollten passen, werden ja von gcc als cpu Auswahl genutzt.
Also
MCU=atmega32

Gruß
Juergen

von g457 (Gast)


Lesenswert?

> Die defines sollten passen

Das glaube ich nicht. Schau Dir mal die Defines
1
__AVR_ATmega328P__
 und co an.

von Wilhelm M. (wimalopaan)


Lesenswert?

Der cpp kann keine(!) Stringvergleiche. Er kann nur numerisches.

von Wilhelm M. (wimalopaan)


Lesenswert?


von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Jürgen S. schrieb:

> z.B.#if MCU == atmega328p
>     UDR0 = c;
> #elif MCU == atmega1284p
>     UDR0 = c;
> #elif MCU == atmega32
>     UDR = c;
> #endif

Schreib' das mal so um:
1
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega1284P__)
2
     UDR0 = c;
3
#elif defined(__AVR_ATmega32__)
4
     UDR = c;
5
#else
6
#   error Unhandled MCU type
7
#endif

Dann kommst du komplett mit der durch den AVR-GCC bereits vorgegebenen
Infrastruktur aus und musst dir keine eigenen #defines erst erfinden.

von JSachs (Gast)


Lesenswert?

Danke, probiere ich sobald ich daheim bin.

Den define für die MCU brauche ich trotzdem fur den cpu Typ.

Oder habe ich da was übersehen?

Gruß
Juergen

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

JSachs schrieb:
> Den define für die MCU brauche ich trotzdem fur den cpu Typ.

Nein, die Makros wie
1
__AVR_ATmega1284P__

etc. erzeugt der AVR-GCC intern selbst aus der übergebenen Option
-mmcu=atmega1284p.

von Rainer B. (katastrophenheinz)


Lesenswert?

... und in der UART-Lib von P. Fleury gibt's das Ganze schon fertig 
aufgebaut und getestet:

http://homepage.hispeed.ch/peterfleury/uartlibrary.zip

Und wenn du den Quellcode nur dafür hernimmst, um zu gucken, wie man 
sinnvoll mit dem #define für den Prozessortyp umgeht.

Das #define für den AVR-Typ legt der Preprozessor für dich an, je 
nachdem welches Target du mit der gcc-Kommadozeilenoption -mmcu=... oder 
per Setting in deiner IDE auswählst ( was letztendlich auch auf die 
Kommandozeilenoption hinausläuft).

: Bearbeitet durch User
von Jürgen S. (jsachs)


Lesenswert?

Jörg W. schrieb:
> JSachs schrieb:
>> Den define für die MCU brauche ich trotzdem fur den cpu Typ.
>
> Nein, die Makros wie
>
>
1
__AVR_ATmega1284P__
>
> etc. erzeugt der AVR-GCC intern selbst aus der übergebenen Option
> -mmcu=atmega1284p.

So ganz habe ich das nicht verstanden.......
Wenn ich folgendes machen möchte
1
AVRDUDE_FLAGS = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER)
Muss ich doch MCU definieren?
Wobei das ja für AVR_DUDE ist, nicht für gcc...
genauso habe ich das auch bei
1
# Combine all necessary flags and optional flags.
2
# Add target processor to flags.
3
ALL_CFLAGS = -mmcu=$(MCU) -W -Wall -I. $(CFLAGS) $(GENDEPFLAGS) $(CDEFS) $(CSTANDARD) -ffunction-sections -O$(OPT) 
4
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)
genutzt..


Oder gibt es einen define, der das bereits beinhaltet.
Wenn ich der Datei avr/io.h folge, kann ich da nichts entdecken, mit den 
jeweiligen includes natürlich.

Der Umbau auf:
1
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega1284P__)
2
     UDR0 = c;
3
#elif defined(__AVR_ATmega32__)
4
     UDR = c;
5
#else
6
#   error Unhandled MCU type
7
#endif
hat erst mal den Erfolg gebracht, trotzdem würde ich das noch weiter 
Optimieren wollen.
Nur so als Hinweis, es geht nicht nur UART, auch Interrupts un Co.
Trotzdem Danke für den Hinweis auf die UART Library.

Etwas Offtopic...
Kann mir einer sagen, wie ich bei einer Änderung einer bestimmten Datei 
einen "make clean" als erstes ausführen kann ?
Ein (Ausschnitt aus meinem Makefile)
1
build: $(GLOBAL_SRC_DIR/typeToBuild.makefile) elf hex bin eep lss sym size copyHttp finish
2
3
$(GLOBAL_SRC_DIR/typeToBuild.makefile):
4
  echo "type to Build changed, clean up project first"
5
  clean
brachte leider keinen Erfolg.

Gruss
Juergen

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Jürgen S. schrieb:

> Muss ich doch MCU definieren?

Ja, an einer Stelle schon.  Aber diese Variable namens MCU ist nur
innerhalb des Makefiles bekannt.  Von da wird er als -mmcu= an den
Compiler weitergereicht, und dieser wiederum baut sich intern dann
die Makros mit den Unterstrichen draus.

> Kann mir einer sagen, wie ich bei einer Änderung einer bestimmten Datei
> einen "make clean" als erstes ausführen kann ?
> Ein (Ausschnitt aus meinem Makefile)

> build: $(GLOBAL_SRC_DIR/typeToBuild.makefile) elf hex bin eep lss sym
> size copyHttp finish
>
> $(GLOBAL_SRC_DIR/typeToBuild.makefile):
>   echo "type to Build changed, clean up project first"
>   clean

Probier' es mal mit einer Hilfsdatei, die von der anderen abhängt:
1
build: stamp elf hex bin eep lss sym size copyHttp finish
2
3
stamp: $(GLOBAL_SRC_DIR/typeToBuild.makefile)
4
        $(MAKE) clean
5
        touch stamp

: Bearbeitet durch Moderator
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Jörg W. schrieb:
> Nein, die Makros wie
>
>
1
__AVR_ATmega1284P__
>
> etc. erzeugt der AVR-GCC intern selbst aus der übergebenen Option
> -mmcu=atmega1284p.

Inzwischen nicht mehr.  Während es sich bis avr-gcc v4.9 noch um 
Build-in Makros handelte und in entsprechenden Dumps daher steht
1
# 1 "<built-in>"
2
...
3
#define __AVR_ATmega1284P__ 1

ist das ab v5 nicht mehr so.  Die Macros werden qua specs File über die 
Kommandozeile definiert:
  
1
# 1 "<command-line>"
2
#define __AVR_ATmega1284P__ 1
 
Der entsprechende Eintrag aus specs-atmega1284p:
 
1
*cpp:
2
  -D__AVR_ATmega1284P__ -D__AVR_DEVICE_NAME__=atmega1284p

von Jürgen S. (jsachs)


Lesenswert?

Jörg W. schrieb:
> Jürgen S. schrieb:
>
>> Muss ich doch MCU definieren?
>
> Ja, an einer Stelle schon.  Aber diese Variable namens MCU ist /nur/
> innerhalb des Makefiles bekannt.  Von da wird er als -mmcu= an den
> Compiler weitergereicht, und dieser wiederum baut sich intern dann
> die Makros mit den Unterstrichen draus.
Jetzt wo ich es lese...
Klar, MCU war nur im Makefile bekannt...

Gut, jetzt mit dem
1
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega1284P__)
2
     UDR0 = c;
3
#elif defined(__AVR_ATmega32__)
4
     UDR = c;
5
#else
6
#   error Unhandled MCU type
7
#endif
ist es eh besser.

Das mit dem
>
1
> build: stamp elf hex bin eep lss sym size copyHttp finish
2
> 
3
> stamp: $(GLOBAL_SRC_DIR/typeToBuild.makefile)
4
>         $(MAKE) clean
5
>         touch stamp
6
>
hat genau einmal Funktioniert, sieht bei mir so aus.
1
# Change the build target to build a HEX file
2
build: whatToBuildDummy elf hex bin eep lss sym size copyHttp finish
3
4
whatToBuildDummy: $(GLOBAL_SRC_DIR/typeToBuild.makefile)
5
  echo "type to Build changed, clean up project first"
6
  echo "if you get an error abaout missing dependency file, simply compile again"
7
  $(MAKE) clean
8
  touch "whatToBuildDummy"
Das stelle ich jedoch mal hinten an.

Gruss
Juergen

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Johann L. schrieb:
>> erzeugt der AVR-GCC intern selbst aus der übergebenen Option
>> -mmcu=atmega1284p.
>
> Inzwischen nicht mehr.

OK, das war mir jetzt nicht so ganz genau klar.

Anyway, das Interface aus Nutzersicht hat sich ja dadurch nicht
geändert: er kann sich drauf verlassen, dass sein -mmcu= einen
entsprechenden Makro automatisch generiert, und man muss sich nicht
die Mühe machen, etwas vergleichbares „zu Fuß“ nachzubilden.

von S. R. (svenska)


Lesenswert?

Jürgen S. schrieb:
> Das mit dem
>>> build: stamp elf hex bin eep lss sym size copyHttp finish
>>
>> stamp: $(GLOBAL_SRC_DIR/typeToBuild.makefile)
>>         $(MAKE) clean
>>         touch stamp
>> hat genau einmal Funktioniert, sieht bei mir so aus.

Erstens:
Dein "make clean" muss das stamp-File auch löschen, sonst funktioniert 
das nur genau einmal. Du kannst aber statt auf ein Dummy-File auch auf 
"clean" verweisen lassen, und du solltest "clean" als ".PHONY" 
deklarieren. Außerdem macht dein Ansatz parallele Builds kaputt, weil 
"clean" an fremden Dateien rumspielt.

Zweitens:
Wenn du vor einem Build ein "make clean" brauchst, ist an deinem 
Buildsystem etwas kaputt. Erweitere dein Makefile mal lieber um 
richtiges Dependency Tracking (der gcc kann dir passende 
Makefile-Snippets erzeugen), dann funktioniert der Rebuild auch 
zuverlässig, wenn du einen Header änderst.

Beispiel (Auszugsweise):
1
OBJS = bla.o blub.o main.o
2
3
[...]
4
5
DEPS = $(OBJS:.o=.od)
6
.PHONY: all clean run
7
.PRECIOUS: $(OBJS) $(DEPS)
8
9
[...]
10
11
%.o: %.c
12
    $(CC) $(CFLAGS) -c -o $@ $<
13
    $(CC) $(CFLAGS) -MM -c $< > $@d
14
15
[...]
16
17
clean:
18
    rm -f $(MAIN) $(OBJS) $(DEPS)
19
20
-include $(DEPS)

Die beiden Compileraufrufe kann man sicherlich auch vereinigen, aber das 
habe ich bisher nicht gebraucht. Vermutlich geht's auch noch besser.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

S. R. schrieb:
> Wenn du vor einem Build ein "make clean" brauchst, ist an deinem
> Buildsystem etwas kaputt.

Naja, wenn man im Makefile (oder einem seiner Includes) irgendwelche
Parameter ändert, die das komplette Compilat beeinflussen, dann
bleibt einem eigentlich nicht viel anderes übrig, als vorher erstmal
alles zu löschen.

von S. R. (svenska)


Lesenswert?

Ja gut, das ist klar. Aber dann macht man vorher einmal "make clean" per 
Hand und gut ist. Mein Reflex ist in solchen Fällen "make clean run", 
weswegen ich clean auch nicht in NOTPARALLEL stehen habe; mit der Race 
Condition kann ich leben,

Ich hatte den TO so verstanden, dass es um eine Datei geht, die im 
Makefile nicht explizit auftaucht, aber trotzdem gebraucht wird. Das ist 
dann ein Fehler im Buildsystem, und implizit "make clean" aufrufen 
lassen ist ein hässlicher Workaround, der zudem parallele Builds bricht.

Wenn man ständig an den Makefiles rumspielt, könnte man natürlich auch 
Includes bauen, die die einzelnen Makefile.inc-Dateien verfolgen, und im 
Zweifelsfall dann "make" neu aufrufen... ;-)

von JSachs (Gast)


Lesenswert?

Genau das ist bei mir der Fall.

Dieses File definiert, was erzeugt wird.
Dadurch wird im Makefile Prozessor und Optionen definiert.
Außerdem werden durch das define bestimmt, was im Quellcode compiliert 
wird, eventuell die pin Konfiguration geändert usw.

Da hilft nur ein make Clean um sicher zu gehen.

Gruss
Juergen

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.