Author Topic: AVR family defines with avr-gcc?  (Read 5270 times)

0 Members and 1 Guest are viewing this topic.

Offline ralphdTopic starter

  • Frequent Contributor
  • **
  • Posts: 445
  • Country: ca
    • Nerd Ralph
AVR family defines with avr-gcc?
« on: August 22, 2015, 05:20:11 pm »
I want some code to be conditionally compiled for AVR families that have the same register layout, like the m88/168/328.  I know I can check for a set of CPU defines like:
__AVR_ATmega88__ || __AVR_ATmega168__ || __AVR_ATmega328__ ...

Is there a simpler way?  I looked through the avr-libc source and couldn't find anything.  avr-gcc has definitions for AVR families based on CPU instruction set (like those with/without mul), but I couldn't find anything that grouped them into those with compatible register layouts.
Unthinking respect for authority is the greatest enemy of truth. Einstein
 

Offline MarkL

  • Supporter
  • ****
  • Posts: 2203
  • Country: us
Re: AVR family defines with avr-gcc?
« Reply #1 on: August 22, 2015, 05:47:17 pm »
Take a look at the pre-define "__AVR_ARCH__".  It gets set to 1, 2, 25, 3, etc. depending on what's passed on "-mmcu=xxx".

There's some brief info available via "avr-gcc --target-help" on these base architecture types, but you may need to dig deeper into the avr-gcc source and/or docs to figure out if what you're trying to differentiate is represented.

If that doesn't do it, you can see all the defines by doing this, for example:

  touch foo.h; avr-cpp -dM -mmcu=attiny44 foo.h

Perhaps some other define can help you with your test.

 

Offline ralphdTopic starter

  • Frequent Contributor
  • **
  • Posts: 445
  • Country: ca
    • Nerd Ralph
Re: AVR family defines with avr-gcc?
« Reply #2 on: August 22, 2015, 06:02:33 pm »
Take a look at the pre-define "__AVR_ARCH__".  It gets set to 1, 2, 25, 3, etc. depending on what's passed on "-mmcu=xxx".

There's some brief info available via "avr-gcc --target-help" on these base architecture types, but you may need to dig deeper into the avr-gcc source and/or docs to figure out if what you're trying to differentiate is represented.

If that doesn't do it, you can see all the defines by doing this, for example:

  touch foo.h; avr-cpp -dM -mmcu=attiny44 foo.h

Perhaps some other define can help you with your test.

The ARCH defines are the ones that define the instruction set, like whether it has mul, etc.

Thanks for the avr-cpp suggestion.  I've tried it and am browsing the 1558 lines of output for -mmcu=atmega328p...
Unthinking respect for authority is the greatest enemy of truth. Einstein
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4288
  • Country: us
Re: AVR family defines with avr-gcc?
« Reply #3 on: August 23, 2015, 07:26:02 pm »
The arduino code checks for individual peripheral registers rather than chip type.  Ie, if you want to configure the second UART, rather than checking if the chip type is a 1284, just check for USR2A or whatever...

 

Offline ralphdTopic starter

  • Frequent Contributor
  • **
  • Posts: 445
  • Country: ca
    • Nerd Ralph
Re: AVR family defines with avr-gcc?
« Reply #4 on: August 23, 2015, 07:39:38 pm »
The arduino code checks for individual peripheral registers rather than chip type.  Ie, if you want to configure the second UART, rather than checking if the chip type is a 1284, just check for USR2A or whatever...

I've decided to try something similar to that.  I'm thinking of:
Code: [Select]
#if defined(PORTC) && (PORTC == _SFR_IO8(0x08))

for  the m48/88/168/328 series as well as the t48/88, which have an identical pinout for PORTB, PORTC, and PORTD.

for the t25/45/85 and t13 I think the following will work:
Code: [Select]
#elif (PORTB == _SFR_IO8(0x18))
Unthinking respect for authority is the greatest enemy of truth. Einstein
 

Offline ralphdTopic starter

  • Frequent Contributor
  • **
  • Posts: 445
  • Country: ca
    • Nerd Ralph
Re: AVR family defines with avr-gcc?
« Reply #5 on: August 29, 2015, 09:56:47 pm »
The arduino code checks for individual peripheral registers rather than chip type.  Ie, if you want to configure the second UART, rather than checking if the chip type is a 1284, just check for USR2A or whatever...

I've decided to try something similar to that.  I'm thinking of:
Code: [Select]
#if defined(PORTC) && (PORTC == _SFR_IO8(0x08))

Turns out this is not so easy. The macro expansion of PORTC gives an expression that CPP doesn't like.  So I tried stringifying:
Code: [Select]
#if defined(PORTC) && (STR(PORTC) == "_SFR_IO8(0x08)")

Which still doesn't work:
avrlib/Wiring.h:28:33: error: token ""(*(volatile uint8_t *)((0x08) +0x20))"" is not valid in preprocessor expressions

Then I tried the address operator '&', but that is only a binary AND operator in CPP:
Code: [Select]
#if defined(PORTC) && (&(PORTC) == &(_SFR_IO8(0x08)))
error: operator '&' has no left operand

Instead I'm going to try to come up with a combination of simple #if defined(xxx) && !defined(yyy) ...
Unthinking respect for authority is the greatest enemy of truth. Einstein
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4288
  • Country: us
Re: AVR family defines with avr-gcc?
« Reply #6 on: August 30, 2015, 08:22:47 am »
What are you actually trying to accomplish?  The Arduino code derives peripheral types from peripheral defines, without going through the intermediate step of guessing an exact chip (although that's implicit.)  For example:
Code: [Select]
#if defined(TCCR4A) && defined(TCCR4B) && defined(TCCR4D) /* beginning of timer4 block for 32U4 and similar */
    sbi(TCCR4B, CS42);        // set timer4 prescale factor to 64
    sbi(TCCR4B, CS41);
    sbi(TCCR4B, CS40);
    sbi(TCCR4D, WGM40);        // put timer 4 in phase- and frequency-correct PWM mode   
    sbi(TCCR4A, PWM4A);        // enable PWM mode for comparator OCR4A
    sbi(TCCR4C, PWM4D);        // enable PWM mode for comparator OCR4D
#else /* beginning of timer4 block for ATMEGA1280 and ATMEGA2560 */
#if defined(TCCR4B) && defined(CS41) && defined(WGM40)
    sbi(TCCR4B, CS41);        // set timer 4 prescale factor to 64
    sbi(TCCR4B, CS40);
    sbi(TCCR4A, WGM40);        // put timer 4 in 8-bit phase correct pwm mode
#endif

You MIGHT be able to get some traction out of the "io*x*" include files.  For example, there's an "iomx8.h" that defines the common symbols for mega48, mega88, and mega168.  It of course defines "_AVR_IOMX8_H_" as part of the usual "allow multiple includes of the same file" provisions.  But you'll notice that it's not included by iom328.h, iom328p.h, iom168p.h, and other "newer" chips that ARE in the same family.  I think that's because new chips have their io*.h files generated individually from xml files somewhere, while older io*.h files were put together manually. :-(

Your discovery about "expressions cpp doesn't like" means that an idea I had about defining UART structures based on checking distances between known registers won't work either :-(

It shouldn't be too hard to put together an "avrfamilyXX.h" that exhaustively puts all the chips you're interested in into families.
Code: [Select]
/* avrfamilymxx8.h - atmega48/88/168/328 family chips */
#ifdef __AVR_ATmega88__
#define __AVR_FAMILY_MXX8
#endif
#ifdef __AVR_ATmega168__
#define __AVR_FAMILY_MXX8
#endif
#ifdef __AVR_ATmega168p__
#define __AVR_FAMILY_MXX8
#endif
#ifdef __AVR_ATmega168pa__
#define __AVR_FAMILY_MXX8
#endif
#ifdef __AVR_ATmega168pb__
#define __AVR_FAMILY_MXX8
#endif
// etc
(ugly verbose format chosen for ease of editing and possible automatic generation...)
Then you could have your code include checks for all the families you're interested in handling, like:
Code: [Select]
#include "avrfamilymxx8.h"
#include "avrfamilytnxx8.h"
#include "avrfamilymxdip40.h"

You might be amused by my recent discovery about the new ATmega328pb.  Apparently it has a second uart and twi port.
That ends up meaning that "TWBR0" and "TWBR1" are bitmasks on the m328 and m328p, but SFR register pointers on 328pb!
(of course, it's a bit stupid that they're defined as bitmasks anywhere, since TWBR holds a byte quantity.  But still...)
 

Offline ralphdTopic starter

  • Frequent Contributor
  • **
  • Posts: 445
  • Country: ca
    • Nerd Ralph
Re: AVR family defines with avr-gcc?
« Reply #7 on: August 31, 2015, 03:00:40 pm »
What are you actually trying to accomplish?
I'm writing a library I'm calling picoWiring, which implements a subset of the Wiring API (digitalWrite, delay(), SPI), and is used from a standard build environment (avr-gcc & make).
Both Arduino and Wiring seem to define the pin mapping for each board, but I'm grouping things together.  What I have now is:
Code: [Select]
#if defined(PORTC)
// m48/88/168/328 and t48/88
#include "Wiring-xx8.h"
#elif defined(PORTB) && !defined(PORTA)
// 8-pin t13 and tinyx5
#endif

Quote
You MIGHT be able to get some traction out of the "io*x*" include files.  For example, there's an "iomx8.h" that defines the common symbols for mega48, mega88, and mega168.  It of course defines "_AVR_IOMX8_H_" as part of the usual "allow multiple includes of the same file" provisions.
Thought of that too, but header file names (and their include guards) can change.  Or avr-libc could switch to using #pragma once.

Quote
It shouldn't be too hard to put together an "avrfamilyXX.h" that exhaustively puts all the chips you're interested in into families.
Code: [Select]
/* avrfamilymxx8.h - atmega48/88/168/328 family chips */
#ifdef __AVR_ATmega88__
#define __AVR_FAMILY_MXX8
#endif
...

That's what I'm avoiding since it requires maintenance whenever a new compatible part comes out.

Quote
You might be amused by my recent discovery about the new ATmega328pb.  Apparently it has a second uart and twi port.

Do tell...
Unthinking respect for authority is the greatest enemy of truth. Einstein
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf