AVR family defines with avr-gcc? - Page 1
Forum section: electronics / general

author: ralphd
author_rank: Frequent Contributor
timestamp: August 22, 2015, 05:20:11 pm
content: 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.

author: MarkL
author_rank: Unknown
timestamp: August 22, 2015, 05:47:17 pm
content: 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.hPerhaps some other define can help you with your test.

author: ralphd
author_rank: Frequent Contributor
timestamp: August 22, 2015, 06:02:33 pm
content: Quote from: MarkL on August 22, 2015, 05:47:17 pmThe 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...

author: westfw
author_rank: Super Contributor
timestamp: August 23, 2015, 07:26:02 pm
content: 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...

author: ralphd
author_rank: Frequent Contributor
timestamp: August 23, 2015, 07:39:38 pm
content: Quote from: westfw on August 23, 2015, 07:26:02 pmI've decided to try something similar to that. I'm thinking of:Code:#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:#elif (PORTB == _SFR_IO8(0x18))

author: ralphd
author_rank: Frequent Contributor
timestamp: August 29, 2015, 09:56:47 pm
content: Quote from: ralphd on August 23, 2015, 07:39:38 pmTurns out this is not so easy. The macro expansion of PORTC gives an expression that CPP doesn't like. So I tried stringifying:Code:#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 expressionsThen I tried the address operator '&', but that is only a binary AND operator in CPP:Code:#if defined(PORTC) && (&(PORTC) == &(_SFR_IO8(0x08)))error: operator '&' has no left operandInstead I'm going to try to come up with a combination of simple #if defined(xxx) && !defined(yyy) ...

author: westfw
author_rank: Super Contributor
timestamp: August 30, 2015, 08:22:47 am
content: 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:#if defined(TCCR4A) && defined(TCCR4B) && defined(TCCR4D) /* beginning of timer4 block for 32U4 and similar */sbi(TCCR4B, CS42); // set timer4 prescale factor to 64sbi(TCCR4B, CS41);sbi(TCCR4B, CS40);sbi(TCCR4D, WGM40); // put timer 4 in phase- and frequency-correct PWM modesbi(TCCR4A, PWM4A); // enable PWM mode for comparator OCR4Asbi(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 64sbi(TCCR4B, CS40);sbi(TCCR4A, WGM40); // put timer 4 in 8-bit phase correct pwm mode#endifYou 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:/* 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:#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...)

author: ralphd
author_rank: Frequent Contributor
timestamp: August 31, 2015, 03:00:40 pm
content: Quote from: westfw on August 30, 2015, 08:22:47 amI'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:#if defined(PORTC)// m48/88/168/328 and t48/88#include "Wiring-xx8.h"#elif defined(PORTB) && !defined(PORTA)// 8-pin t13 and tinyx5#endifQuoteThought of that too, but header file names (and their include guards) can change. Or avr-libc could switch to using #pragma once.QuoteThat's what I'm avoiding since it requires maintenance whenever a new compatible part comes out.QuoteDo tell...