Skip to content

Unique ID

Each ATmega32U4 has an undocumented 10-byte fabrication ID in its signature row at offsets 0x0E0x17 (lot number, wafer number, X/Y coordinates). This ID is unique enough in practice to tell boards apart, but there is no manufacturer guarantee on global uniqueness or collision-freedom.

The stock Arduino AVR core ignores the signature row entirely. LUFA exposes these bytes as a 20-character hex USB serial via USE_INTERNAL_SERIAL, but that doesn’t help in the Arduino ecosystem.

Our script patches USBCore.cpp to read the signature row via boot_signature_byte_get() and installs a new board variant “Arduino Leonardo (FabID)” in the Arduino IDE. Selecting that variant automatically produces a per-chip USB serial — no sketch-level changes needed.

USBCore.cpp
[...]
const char* USBCore_GetFabricationId() {
static bool initialized = false;
static char id[19];
if (!initialized) {
for (uint8_t i = 0; i < 9; i++) {
uint8_t b = boot_signature_byte_get(0x0E + i + (i > 5 ? 1 : 0));
id[i * 2] = "0123456789ABCDEF"[b >> 4];
id[i * 2 + 1] = "0123456789ABCDEF"[b & 0x0F];
}
id[18] = '\0';
initialized = true;
}
return id;
}
[...]

Once patched, you can read the ID in two ways:

  • In a sketch — call USBCore_GetFabricationId() (see example below)
  • On the host — read the USB serial string, e.g. via PowerShell
print_fabid.ino
#include <Keyboard.h>
extern const char* USBCore_GetFabricationId();
void setup() {
// --- print serial number ----------
Serial.begin(9600);
delay(1000);
Serial.println(USBCore_GetFabricationId());
Serial.end();
// -------------------------
}
void loop() {
}