Conditional syntax for different MCU not working

Go To Last Post
20 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Folks,

I'm trying to make my code work easily for different pin-compatible chips. I did my prototyping on an ATmega168 and have moved to an ATmega8 but would like to make the code work for both.

The only difference is register names for timers and interrupts. I'm trying to use a conditional block at the top to read in the MCU definition from the makefile and define register names accordingly. Here's what I've come up with:

#if MCU == atmega8			//ATmega8

  //INT0 register definitions
  #define EXT_INT_CONTROL	MCUCR
  #define EXT_INT_SELECT 	GICR

  //Timer0 register definitions
  #define TIMER0_CTRL_REG	TCCR0
  #define TIMER0_INT_MASK	TIMSK

  //Timer2 register definitions
  #define TIMER2_CTRL_REG	TCCR2
  #define TIMER2_INT_MASK	TIMSK

#elif MCU == atmega168			//ATmega168

  //INT0 register definitions
  #define EXT_INT_CONTROL	EICRA
  #define EXT_INT_SELECT 	EIMSK

  //Timer0 register definitions
  #define TIMER0_CTRL_REG	TCCR0B
  #define TIMER0_INT_MASK	TIMSK0

  //Timer2 register definitions
  #define TIMER2_CTRL_REG	TCCR2B
  #define TIMER2_INT_MASK	TIMSK2

#endif

Works fine if MCU is atmega8, but when I change it atmega168 the #elif condition isn't working as you can see by the compiler errors:

Compiling: ping-pong-clock.c
avr-gcc -c -mmcu=atmega168 -I. -g -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=ping-pong-clock.lst  -std=gnu99 ping-pong-clock.c -o ping-pong-clock.o
ping-pong-clock.c: In function "˜init':
ping-pong-clock.c:250: error: "˜GICR' undeclared (first use in this function)
ping-pong-clock.c:250: error: (Each undeclared identifier is reported only once
ping-pong-clock.c:250: error: for each function it appears in.)
ping-pong-clock.c: In function "˜initTimers':
ping-pong-clock.c:267: error: "˜TIMSK' undeclared (first use in this function)
ping-pong-clock.c:268: error: "˜TCCR0' undeclared (first use in this function)
ping-pong-clock.c:271: error: "˜TCCR2' undeclared (first use in this function)
make: *** [ping-pong-clock.o] Error 1

Any idea if there's a way to get this working?

Thanks!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

MCU is neither "atmega8" nor "atmega168".
It is either "__AVR_ATmega8__" or "__AVR_ATmega168__".

Look here for the relation between -mmcu and MCU:
http://www.nongnu.org/avr-libc/u...

Stefan Ernst

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sternst wrote:
MCU is neither "atmega8" nor "atmega168".
It is either "__AVR_ATmega8__" or "__AVR_ATmega168__".

Look here for the relation between -mmcu and MCU:
http://www.nongnu.org/avr-libc/u...

Right, but my makefile defines MCU:

# Microcontroller Type
# MCU = attiny13
# MCU = attiny2313
# MCU = atmega8
MCU = atmega168

Then passes that as the mmcu arguement:

ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS)

So shouldn't I be able to use the value of MCU in my C file?

At any rate, I tried your changes and still get the same compiler error.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

So shouldn't I be able to use the value of MCU in my C file?

If you want to do that pass it in with -D. But given that -mmcu= leads to the __AVR_ATsomething__ that Stefan mentioned then why reinvent the wheel? I just do stuff like:

int uart_putc(char c, FILE *unused) {
#ifdef __AVR_ATmega168__
	while (!(UCSR0A & (1<<UDRE0)));
	UDR0 = c;
#else
	while (!(UCSRA & (1<<UDRE)));
	UDR = c;
#endif
	return 0;
}

that #else could just as easily be:

#elif defined(__AVR_ATmega16__)

etc.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

When you use that particular string in the Makefile that eventually goes as a -mmcu=atmega8 to avr-gcc.

So you do your conditionals with:

#if   defined(__AVR_ATmega8__)
...
#elif defined(__AVR_ATmega168__)
...
#elif defined(__AVR_ATmega328p__)
...
#else
#error unknown chip
#endif

The preprocessor cannot compare strings with ==
However some other Compiler 'driver' programs parse the strings and #define a numeric value.
You can use == on numeric values.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you all for the help. #if defined() was exactly what I needed. Here's the working code snippit:

#if defined(__AVR_ATmega8__)			//ATmega8

  //INT0 register definitions
  #define EXT_INT_CONTROL	MCUCR
  #define EXT_INT_SELECT 	GICR

  //Timer0 register definitions
  #define TIMER0_CTRL_REG	TCCR0
  #define TIMER0_INT_MASK	TIMSK

  //Timer2 register definitions
  #define TIMER2_CTRL_REG	TCCR2
  #define TIMER2_INT_MASK	TIMSK

#elif defined(__AVR_ATmega168__)		//ATmega168

  //INT0 register definitions
  #define EXT_INT_CONTROL	EICRA
  #define EXT_INT_SELECT 	EIMSK

  //Timer0 register definitions
  #define TIMER0_CTRL_REG	TCCR0B
  #define TIMER0_INT_MASK	TIMSK0

  //Timer2 register definitions
  #define TIMER2_CTRL_REG	TCCR2B
  #define TIMER2_INT_MASK	TIMSK2

#endif
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

While I guess

#if defined(__AVR_ATmega8__)

is consitent, note that it can be shortened to:

#ifdef __AVR_ATmega8__

(same not true of the #elif though)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@Barney,

It is wise to put a #else, #error sequence in your conditional.

@Cliff,

#ifdef may be a shorthand but you cannot use it in expressions.

I rather like the #if, #elif, #else, #endif construction. It is easy to understand and maintain. I struggle with #if, #if, #endif, #endif nesting.

YMMV.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

#ifdef may be a shorthand but you cannot use it in expressions.

But __AVR_ATsomething__ is not an "expression". It's a unique symbol that is just defined as a result of the -mmcu= selection. It's either defined or it isn't.

Personally (because our coding standard mandates it) I almost always use #ifdef/#elif defined() for conditionally building code rather than #if.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Cliff,

#ifdef, #elif defined() is absolutely crazy!

#ifdef NAME is the direct equivalent of #if defined(NAME)

It is extremely likely that CPU conditionals apply to a family rather than a single device. e.g. mega88, mega88v, mega88p, mega88pa ...

I would have a full and frank discussion with your 'coding standard supremo'

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

#ifdef NAME is the direct equivalent of #if defined(NAME)

I know that - it's just quicker to type "#ifdef" than it is to type "#if defined()" - which was the point I was simply trying to make above. Obviously if the conditional code was dependent on more than one thing then "#if defined(one) && defined(other)" would be used.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

My apologies. I thought you were saying #if defined() was banned by your coding standard.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In the case you are unsure about what defines are set and what their values are, ask the oracle:

> echo | avr-gcc -E -dM - -mmcu=attin261 | grep __AVR

will print (4.5.x)

#define __AVR_2_BYTE_PC__ 1
#define __AVR_ARCH__ 25
#define __AVR_HAVE_8BIT_SP__ 1
#define __AVR 1
#define __AVR_HAVE_LPMX__ 1
#define __AVR_ATtiny261__ 1
#define __AVR__ 1
#define __AVR_HAVE_MOVW__ 1

avrfreaks does not support Opera. Profile inactive.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Not really on topic. But why would anyone ever need to type "echo |"? (except for me, right now)-

Edit: Oh. You want to send an empty program to avr-gcc? (If so, why don't you say that? (ok this isn't a unix forum, but anyway))

Last Edited: Tue. Feb 1, 2011 - 09:18 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I just pick any existing .c at random when using -E -dM, if one isn't to hand I'd just use touch to temporarily create one.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That's what I would do too. But does this "echo |" work in Windows? (doesn't the old DOS echo with no argument tell if echo is on or off?)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

But does this "echo |" work in Windows?

Not quite because "echo" used without parameters at a command prompt simply reports "ECHO is on" or "ECHO is off"

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
Quote:

But does this "echo |" work in Windows?

Not quite because "echo" used without parameters at a command prompt simply reports "ECHO is on" or "ECHO is off"

-E -dM direkts gcc to just preprocess and report defined macros. echo just gives some text, and as there is no compilation, gcc is cool about that.

The | pipes echo's output to the next application, avr-gcc in this case. The - in gcc's command line directs gcc to read the input file from stdin instead of from some file.

avrfreaks does not support Opera. Profile inactive.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It was just me being picky. I thought it was a strange way to do it, but it works just fine (in Linux at least).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

But does this "echo |" work in Windows?

You can use the Windows "type" cmd here in place of the unix "echo" cmd and the "find" cmd in place of the unix "grep"

C:\>type | avr-gcc -E -dM - -mmcu=attiny25 | c:\windows\system32\find "AVR"
The syntax of the command is incorrect.
#define __AVR_ATtiny25__ 1
#define __AVR_2_BYTE_PC__ 1
#define __AVR_ARCH__ 25
#define __AVR 1
#define __AVR_HAVE_LPMX__ 1
#define AVR 1
#define __AVR__ 1
#define __AVR_HAVE_MOVW__ 1
#define AVR 1
#define __AVR__ 1
#define __AVR_HAVE_MOVW__ 1