Unique ID within the underlying SAM3X8E processor

Hi all,

Has anyone else extracted the 128bit unique ID embedded within their SAM CPU?
It's NOT easy to access, so I doubt whether anyone using the Arduino IDE will have even TRIED, but it still pays to ask!
(The code to extract it MUST run from RAM and not FLASH. It requires sending the special STUI and SPUI 'commands' to the EFCO flash controller. Lastly, there's even a note in the Errata for the chip detailing the workaround required to enable reading the value at all!)

I'm a trifle 'concerned' that it might not actually prove to be as UNIQUE as one might expect?
I 'expected' a comparatively RANDOM jumble of 128 bits, but the ACTUAL value appears to be 16 ASCII characters.
In my (single) example, I've got 0x512031205752304D3130353137323039
Which is the ASCII code for: "Q 1 WROM10517209"

I'm hoping a LOT that the final 8 ASCII characters are indeed a unique (possibly sequentially assigned?) serial number.

I guess I'll have a better idea once I get my next DUE to play with... (While I know that flash endurance is pretty darned good these days, I'm making a SERIOUS effort to wear out mine... LOL)

There are several threads on this forum with code for extracting the ID.

Regards,
Ray L.

Thanx for that Ray.

I've (obviously?) 'rolled my own' unique-id extraction code since my project bypasses any and all Arduino firmware such that it truly runs on 'the raw iron'. (In my case, even the firmware that's resident within the ATMega16U2 will be 'wiped' thereby effectively disabling the programming port too).

When I initially searched this forum, I only found Unique-ID code for AVR based Arduinos (which used tricks like USB serial numbers etc), but I now see there ARE others who HAVE extracted the ID from a SAM and (thankfully), the value does indeed seem to be comparatively unique! Woohoo!

It's perhaps noteworthy to mention a .couple of potential 'traps' for others that are wanting to 'play' in the unique-ID area:
1: Read the datasheet errata. There's an explicit errata section describing a CORRECT method to read the Unique ID.
2: The code used to extract the unique ID temporarily maps the 128 bit unique value into the FLASH address space (i.e. 0x00080000 if you're reading it via EFC0) and thus your extraction code MUST NOT be running from that bank of flash. In my case, ALL of my code (even the interrupt vector table) resides in RAM. (I've made significant changes to the flash.ld linker script. LOL). I note that others here have extracted the unique ID from Flash bank 1 (EFC1) which I guess will also work (providing your .ino code entirely fits into the 256kB of bank 0).

What I have NOT done (at least not yet) is to test that I can still extract the Unique ID even when all of the pertinent SAM security 'features' have been enabled.

RayLivingston:
There are several threads on this forum with code for extracting the ID.

Regards,
Ray L.

for anyone else stumbling upon this, the code examples on the forums no longer compile with IDE 1.6.9.

i'm trying to solve it here invalid conversion from 'unsigned int' to 'Efc*' - Programming Questions - Arduino Forum

Something like this should read the Unique ID.

#define EEFC_FKEY 0x5A
#define EEFC_FMR_SCOD   (0x1ul << 16) 
#define IFLASH0_ADDR  0x00080000                               // Flash memory begins at 0x00080000
#define IFLASH1_ADDR ( IFLASH0_ADDR + IFLASH_SIZE / 2 )        // IFLASH1_ADDR  = 0x000C0000


__attribute__ ((section (".ramfunc")))
void ReadUniqueID( uint32_t * latch_buffer )
{
    char __FWS;
  
                                                                  // Set bit 16 of EEFC_FMR : See chap. 49.1.1.2 page 1442   
    EFC0->EEFC_FMR |= EEFC_FMR_SCOD;                              // Sequential code optimization disable
    
  __FWS = (EFC0->EEFC_FMR & EEFC_FMR_FWS_Msk)>>EEFC_FMR_FWS_Pos ; // Save FWS value
    EFC0->EEFC_FMR &=~ EEFC_FMR_FWS_Msk;
    EFC0->EEFC_FMR |= EEFC_FMR_FWS(6);                            // 6+1 wait states for read and write operations
    
   
    EFC0->EEFC_FMR &=~EEFC_FMR_FAM;                               // 128-bit access in read Mode only, to enhance access speed.
    
    while(!(EFC0->EEFC_FSR & EEFC_FSR_FRDY));                     // Send the  STUI command if FRDY bit is high to begin reading in flash
    EFC0->EEFC_FCR = EEFC_FCR_FKEY(EEFC_FKEY) | EFC_FCMD_STUI ;    
                                                                  //Wait till FRDY falls down
    while(EFC0->EEFC_FSR & EEFC_FSR_FRDY);   
                                                                  // The Unique Identifier is located in the first 128 bits of 
                                                                  // the Flash bank 0 in between 0x080000 and 0x08000C (and of the Flash bank 1 in between 0X0C0000 and 0x0C000C ??) 
    memcpy(latch_buffer, (void*)IFLASH0_ADDR, 16);                // Read first 128 bits ( 16 first bytes) in one shot beginning at address IFLASHIndex_ADDR
       
                                                                  // Send the SPUI command to stop reading in flash    
    EFC0->EEFC_FCR = EEFC_FCR_FKEY(EEFC_FKEY) | EFC_FCMD_SPUI ;
                                                                  // Wait till FRDY rises up
    while(!(EFC0->EEFC_FSR & EEFC_FSR_FRDY));
    
                                                                  // Clear bit 16 of EEFC_FMR : See chap. 49.1.1.2 page 1442
    EFC0->EEFC_FMR &= ~EEFC_FMR_SCOD;                             // Sequential code optimization enable
    
    EFC0->EEFC_FMR &=~ EEFC_FMR_FWS_Msk;                          // Restore FWS value
    EFC0->EEFC_FMR |= EEFC_FMR_FWS(__FWS);                        
   
}

void setup ()
{
Serial.begin (250000) ;
                /***********   Read Unique ID  ***************************/
    uint32_t latch_buffer[4]; 
    ReadUniqueID( latch_buffer ) ;
    Serial.println("Reading of the 128 bits unique identifier :"); Serial.print(" ID = " );
   
    for (byte b = 0 ; b < 4 ; b++)
     {
      Serial.print((uint32_t)latch_buffer[b], HEX) ;Serial.print((uint32_t)(latch_buffer[b]>>32), HEX);
     }
    
    
}

void loop() {}