Verständnisproblem #if bei avr-gcc

#4776611
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
Moderator Persönliche Seite #4776694
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.
#4776708
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).
#4776819
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
Moderator Persönliche Seite #4776831
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
Persönliche Seite #4776937
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
#4777027
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
Moderator Persönliche Seite #4777088
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.
#4777751
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.
#4777796
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... ;-)
Gast #4777831
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren