# How can I detect which arduino board (or which controller) in software?

I have a project that I want to work on either a Uno or a Mega (or even a Due) and it would be nice if I didn't need two versions of the software. For example, on a Mega, to use SoftwareSerial, you have to use different pins than the ones on an Uno. See the docs on Software Serial. Anyway, it would be nice to detect that I'm using an Uno so I can just use pins 4 and 5 for TX/RX and if I'm using a Mega the software will detect and just use pins 10 and 11 (and of course, I'll have to wire it up differently but at least the software will be the same).

# Run time

To my knowledge you cannot detect the board type, but you can read the ATmega device ID. Check this question how it can be done: Can an ATmega or ATtiny device signature be read while running? Notice though when using this method, several register assignments will change, not just the pinout. Therefore your code may get significantly more complex. The advantage is that if you manage to work around all changing register assignments and other hardware dependencies, you can use a single .hex file to program your devices directly from avrdude.

# Compile time

Another way to figure out the board/controller type is at compile time. Basically you compile parts of the code or set macros depending on the device type configured in the Arduino IDE. Check this code sniplet for an example:

#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#define DEBUG_CAPTURE_SIZE 7168
#define CAPTURE_SIZE 7168
#elif defined(__AVR_ATmega328P__)
#define DEBUG_CAPTURE_SIZE 1024
#define CAPTURE_SIZE 1024
#else
#define DEBUG_CAPTURE_SIZE 532
#define CAPTURE_SIZE 532
#endif

The code sniplet was shamelessly copied from https://github.com/gillham/logic_analyzer/wiki Check that code for some some more device specific trickery.

Depending on your host's operating system, the supported controller types can be found in the following file:

• Linux: /usr/lib/avr/include/avr/io.h
• Windows: ...\Arduino\hardware\tools\avr\avr\include\avr\io.h

The use of C-preprocessor (by which the above code is handled) is probably out of scope for this site. http://stackoverflow.com would be the better place for detailed questions.

If you are on Linux you can easily find all supported controller types by typing:

grep 'defined (__AVR' /usr/lib/avr/include/avr/io.h | sed 's/^[^(]*($$[^)]*$$)/\1/'
• ..\Arduino\hardware\tools\avr\avr\include\avr\io.h for windows – mpflaga Feb 18 '13 at 21:17
• @mpflaga I updated the answer. Thnx for your input. – jippie Feb 18 '13 at 21:21
• All AVR-specific predefined macros are listed in the avr-libc documentation. – Ignacio Vazquez-Abrams Aug 26 '15 at 4:04
• So how does the Arduino IDE get the board info?(Tools > Get Board Info) I was hoping to do a string check from a serial connection, so the correct COM port can be automatically selected when my application starts. Because obviously, the IDE can do this, any idea if they use the methods above? – n00dles Jun 4 '17 at 2:15
• @n00dles Above described methods are different from what you want. It is probably worth its own question on Arduino.SE. I can't check the Get Board Info, it is not in the Arduino version I have available. – jippie Jun 4 '17 at 8:25

As stated in the Arduino hardware specification, the Arduino IDE now defines a macro for each board, as defined in the boards.txt build.board property. That value is appended to ARDUINO_ so, for example, the macros for the boards you're interested in are:

• Uno: ARDUINO_AVR_UNO
• Mega 2560: ARDUINO_AVR_MEGA2560
• Due: ARDUINO_SAM_DUE

Example of how you can use these macros in your code:

#if defined(ARDUINO_AVR_UNO)
//Uno specific code
#elif defined(ARDUINO_AVR_MEGA2560)
//Mega 2560 specific code
#elif defined(ARDUINO_SAM_DUE)
//Due specific code
#else
#error Unsupported hardware
#endif
• I'd say this is the more simplest and straight-to-the-point answer to the question. Wish it was the accepted one. – Erutan409 Jul 1 '18 at 21:03

An easy way to do board sniffing is to use a library such as ArduinoManager. With this you can very easily get the board name and features https://github.com/backupbrain/ArduinoBoardManager

It uses the technique described above to reveal lots of information about almost every Arduino board, so it's great for making projects that might get deployed on a lot different environments.

#include "ArduinoBoardManager.h"

ArduinoBoardManager arduino = ArduinoBoardManager(); // required if you want to know the board name and specific features

void setup() {
Serial.begin(9600);

Serial.print("Board is compatible with Arduino ");
Serial.println(arduino.BOARD_NAME);

Serial.println("Speed/SRAM/Flash: ");
Serial.print(ArduinoBoardManager::MAX_MHZ);
Serial.println(ArduinoBoardManager::SRAM_SIZE);
Serial.println(ArduinoBoardManager::FLASH_SIZE);

// Board features (multiple serial ports on Mega, for example)
if (arduino.featureExists(ArduinoBoardManager::FEATURE_MULTIPLE_SERIAL)) {
Serial.println("Your board supports multiple serial connections");
}

}

void loop() {
}

The resulting output on Arduino Uno is:

Board is compatible with Arduino UNO

Speed/SRAM/Flash:
16000000
2048
33554432

The process for making this library (including example code) to determine an Arduino board model and version is described in detail on my blog.

For all boards compatible with Arduio Due

#if defined (__arm__) && defined (__SAM3X8E__) // Arduino Due compatible
// your Arduino Due compatible code here
#endif

If you just want to target the Arduino Due (leaving out compatible boards), you can use

#if defined (_VARIANT_ARDUINO_DUE_X_)
// your Arduino Due code here
#endif

(This is defined in the Arduino Due's variant.h file.)

Since the Arduino Due is a different processor family (ARM) than the AVR's, you won't be able to use the same executable for all three. But you can have the same source code (assuming the syntax for reading a port is the same across both the AVR and ARM parts), and just two executables (since the same one will run on both the Uno and Mega without recompiling).

You can determine the board type at runtime without having to recompile, by choosing two digital pins that are not already being used by your program on any of the boards and tie them high or low as a board ID. For example, if the pins you choose are PC1 and PC3:

PC1   PC3   Board ID
0     0      Uno
0     1      Mega
1     0      Due
1     1      spare

Then just read the port on power up and set a variable in your program.

Another scheme that can be used, which ties up only one pin, is to use an analog input pin and use a resistor divider, choosing resistors such that you get different voltages in say, 0.25V increments. I have used that technique to specify not only a board type, but also a board revision for the same board (which in a sense is a new board type).