My aim is to acquire a unique serial number for my design and reuse it as an ID in different places for my Radio communication. I have used an Atmel SAM D21 series microcontroller on my design which on the 1st sight seemed to have a serial number when I followed the following path in Atmel Studio.

Menu > Tools > Device Programming > Device Information

But no traces of any serial numbers of any sort. Just a Device Signature which repeats on all the MCUs.

I am aware that we could use a Dallas One Wire Serial chip for this purpose and apparently some AVR series have an accessible serial number in them, but in the favor of reducing the BOM and the choice of MCU I am trying not to go that way.

In the meanwhile, even though that I haven't used the feature myself, I know that SAM D series have an integrated USB module in them. Considering that every USB module should have a unique serial number (unless I am wrong), is there a method to extract that SN?

Please let me know if there are any solutions you have in mind for this purpose.

  • \$\begingroup\$ generate a random number/string and save it to the eeprom upon the first boot. \$\endgroup\$
    – dandavis
    May 9, 2017 at 7:51

3 Answers 3


The SAMD21 processors do indeed have a unique ID, as explained in the "Serial Number" section in the "Memories" chapter in the Atmel SAMD21 datasheet. (This is currently section 10.3.3, page 46). The datasheet states

Each device has a unique 128-bit serial number which is a concatenation of four 32-bit words contained at the following addresses:
Word 0: 0x0080A00C
Word 1: 0x0080A040
Word 2: 0x0080A044
Word 3: 0x0080A048
The uniqueness of the serial number is guaranteed only when using all 128 bits.

USB devices are expected but not required to provide a serial number, but I am not aware of any microcontroller USB peripheral that incorporates a serial number directly—all the USB peripherals I know of merely allow the processor, if desired, to provide the serial number as part of the descriptor.

  • \$\begingroup\$ I have been trying your solution and initially I thought this might be a wrong approach but now I need to know what part I am doing wrong. My question is posted here, avrfreaks.net/forum/… \$\endgroup\$
    – Mehrad
    May 12, 2017 at 1:10
  • \$\begingroup\$ Someone on the Adafruit forum claimed the code at snip2code.com/Snippet/1031839/… worked for them—what are you doing differently? \$\endgroup\$ May 12, 2017 at 4:22
  • \$\begingroup\$ Seems Atmel forgot to add that region to the debugger definitions for some chips. Read the answer posted for my question for more details. Thanks for the help btw. \$\endgroup\$
    – Mehrad
    May 15, 2017 at 3:54

I found this same problem and wanted to share my solution. For SAML21, intialize the NVM (non volatile memory) and read the 32bit words at this addresses: 0x0080A00C 0x0080A040 0x0080A044 0x0080A048

uint32_t serialN[4];

nvm_read(INT_FLASH, 0x0080A00C, &serialN[0], 4);
nvm_read(INT_FLASH, 0x0080A040, &serialN[1], 4);
nvm_read(INT_FLASH, 0x0080A044, &serialN[2], 4);
nvm_read(INT_FLASH, 0x0080A048, &serialN[3], 4);

I looked everywhere and try lots of things until I finally got it right, thought I'd share it.


I am using the samC21, and this is how I did it

void vGenSerialNumberString( char * buffer )
    unsigned int * byte0;
    unsigned int * byte1;
    unsigned int * byte2;
    unsigned int * byte3;   
    static char format[] = "%08x%08x%08x%08x";
    byte0 =  0x0080A00C;
    byte1 =  0x0080A040;
    byte2 =  0x0080A044;
    byte3 =  0x0080A048;
    sprintf(buffer, format,*byte0, *byte1, *byte2, *byte3);

Pointers are dark magic, this is the way.

Thanks!! keep hacking

  • \$\begingroup\$ Yes, you don't need to use the ASF NVM functions. I would suggest a couple of improvements. 1) you are accessing 32bit words, not an 8bit byte; 2) as you are accessing a hardware register you should declare the pointers as volatile. Personally, I would do something like unique_id[0] = *(volatile uint32_t *)0x0080A00C but the result is the same. \$\endgroup\$
    – awjlogan
    Mar 11, 2021 at 6:49
  • \$\begingroup\$ Thanks for the answer, of course that volatile is a great way to do it. I have a question, isn't unsigned int and uint32_t the same lenght of bytes for this architecture? of course that explicitly saying 32 bites is better. Thank you again <3 \$\endgroup\$ Mar 26, 2021 at 17:34
  • 1
    \$\begingroup\$ Ah, sorry, it was just the terminology is a bit mixed up, nothing technically wrong. A byte is 8 bits while, as you say, unsigned int is 32 bits. So, using your original format, I would declare it as unsigned int * word0; etc. That was all :) \$\endgroup\$
    – awjlogan
    Mar 26, 2021 at 20:22
  • 1
    \$\begingroup\$ yeah, I'm gonna change the variable names for clarity. Thank you again for your wisdom dude! :D! \$\endgroup\$ Mar 29, 2021 at 13:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.