Teensy 4.x Unique_ID

PaulS

Well-known member
Triggered by a recent discussion about a Teensy 4 unique MAC address, I wondered whether the i.MX RT1060 processor on the Teensy 4.x also has a unique chip serial number like the MK20DX256 chip on a Teensy 3.1/3.2.
Yes, there is:
1728933712340.png


Here is a piece of code to read out that 64-bit Unique_ID:
C++:
// from i.MX RT1060 Processor Reference Manual, Rev 3
// see "Table 22-9 Fusemap Descriptions", page 1301, Fuse Address 0x420 - 0x410: UNIQUE_ID[63:0]
//
// see also Chapter "23.6.1.1 OCOTP memory map", page 1319,
// OTP Bank0 Word1 (Configuration and Manufacturing Info) (CFG0)
// OTP Bank0 Word2 (Configuration and Manufacturing Info) (CFG1)

#define CFG0 (*(const uint32_t *)0x401F4410)
#define CFG1 (*(const uint32_t *)0x401F4420)

void setup() {
  Serial.begin(115200);
  while (!Serial) {};
  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH);  // just to show that board is active
  delay(1000);
  Serial.print("Reading Unique_ID from hardware: ");

  char Unique_ID[18];
  sprintf(Unique_ID, "%08lX %08lX", CFG0, CFG1);
  Serial.println(Unique_ID);

  Serial.println("About to reset in 3 secs...");
  delay(3000);
  SCB_AIRCR = 0x05FA0004;  // software reset
}

void loop() {
}

Ran this code on different Teensy 4.x's.
Teensy 4.0:
6147A86E 3912C1D7
65F82969 390949D2
64FC9020 441D81D7
Teensy 4.1:
65F8296A 353599D2

Paul
 
a piece of code to read out that 64-bit Unique_ID:
3 sec reset is annoying :( :)

Three T_4.1's here on the desk:
Reading Unique_ID from hardware: 5D7586E8 121059D7
Reading Unique_ID from hardware: 65F8296A 0E18B1D2
Reading Unique_ID from hardware: 5D45D01C 0F1299D7 >> Ser# 9706370
>> And a fourth one nearby gave - SO CLOSE:
Reading Unique_ID from hardware: 5D45D01C 183291D7>> Ser# 9706380 <<

Some are various age and perhaps PJRC locked units from one Beta or another ...
 
Added reading out the serial# as well:
C++:
// from i.MXRT1060 Processor Reference Manual, Rev 3
// see "Table 22-9 Fusemap Descriptions", page 1301, Fuse Address 0x420 - 0x410: UNIQUE_ID[63:0]
//
// see also Chapter "23.6.1.1 OCOTP memory map", page 1319,
// 23.6.1.11 OTP Bank0 Word1 (Configuration and Manufacturing Info)(CFG0)
// 23.6.1.12 OTP Bank0 Word2 (Configuration and Manufacturing Info)(CFG1)
// 23.6.1.21 OTP Bank4 Word2 (MAC Address)(MAC0)

#define CFG0 (*(const uint32_t *)0x401F4410)
#define CFG1 (*(const uint32_t *)0x401F4420)
#define MAC0 (*(const uint32_t *)0x401F4620)

void setup() {
  Serial.begin(115200);
  while (!Serial) {};

  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH);  // just to show that board is active

  Serial.print("Reading Unique_ID from hardware: ");
  char Unique_ID[18];
  sprintf(Unique_ID, "%08lX %08lX", CFG0, CFG1);
  Serial.println(Unique_ID);

  Serial.print("Reading Serial# from hardware: ");
  uint32_t SN;
  SN = MAC0 & 0xFFFFFF;
  Serial.println(SN);
}

void loop() {
}

Here are the results:
Teensy 4.0:
6147A86E 3912C1D7 >>Ser# 1285495
65F82969 390949D2 >>Ser# 641249
64FC9020 441D81D7 >>Ser# 1500360
Teensy 4.1:
65F8296A 353599D2 >>Ser# 768059

Just checking: is my understanding of obtaining the serial# via the MAC0 register correct?
I wonder whether there is a kind of checksum on the Unique_ID. And it seems all ID's end in either D2 or D7.

Paul
 
The flash memory chip also has a unique 64 bit number.

It's documented on page 66 (67th page of the PDF) of this datasheet:

Here's code to read it.

Code:
void setup()
{
  while (!Serial) ; // wait for serial monitor
  delay(100);

  const uint32_t *id = read_flash_id();
  if (id) {
    Serial.printf("Winbond ID: %08X %08X", id[0], id[1]);
  } else {
    Serial.println("error");
  }
  pinMode(13, OUTPUT);
}

void loop()
{
  digitalToggle(13);
  delay(800);
}


#define LUT0(opcode, pads, operand) (FLEXSPI_LUT_INSTRUCTION((opcode), (pads), (operand)))
#define LUT1(opcode, pads, operand) (FLEXSPI_LUT_INSTRUCTION((opcode), (pads), (operand)) << 16)
#define CMD_SDR         FLEXSPI_LUT_OPCODE_CMD_SDR
#define READ_SDR        FLEXSPI_LUT_OPCODE_READ_SDR
#define PINS1           FLEXSPI_LUT_NUM_PADS_1

const uint32_t *read_flash_id()
{
  static uint32_t buf[3];
  FLEXSPI_LUTKEY = FLEXSPI_LUTKEY_VALUE;
  FLEXSPI_LUTCR = FLEXSPI_LUTCR_UNLOCK;
  FLEXSPI_LUT36 = LUT0(CMD_SDR, PINS1, 0x4B) | LUT1(READ_SDR, PINS1, 1);
  FLEXSPI_LUT37 = 0;
  FLEXSPI_INTR = FLEXSPI_INTR_IPRXWA;
  FLEXSPI_IPRXFCR = FLEXSPI_IPRXFCR_CLRIPRXF | FLEXSPI_IPRXFCR_RXWMRK(1);
  FLEXSPI_IPCR0 = 0;
  FLEXSPI_IPCR1 = FLEXSPI_IPCR1_ISEQID(9) | FLEXSPI_IPCR1_IDATSZ(12);
  FLEXSPI_IPCMD = FLEXSPI_IPCMD_TRG;
  elapsedMicros timeout = 0;
  while ((FLEXSPI_IPRXFSTS & 0xFF) < 2) {
    if (FLEXSPI_INTR & FLEXSPI_INTR_IPCMDERR) {
      FLEXSPI_INTR = FLEXSPI_INTR_IPCMDERR | FLEXSPI_INTR_IPCMDDONE;
      return NULL;
    }
    if (timeout > 250) return NULL;
  }
  buf[0] = FLEXSPI_RFDR0;
  buf[1] = FLEXSPI_RFDR1;
  buf[2] = FLEXSPI_RFDR2;
  FLEXSPI_INTR = FLEXSPI_INTR_IPCMDDONE;
  return buf + 1;
}
 
Last edited:
Back
Top