Serial Number of Teensy 3.1

Status
Not open for further replies.

carcaes1

Well-known member
Hi guys

One question. Is possible get the Serial Number of one teensy 3.1 or chip?

If it is possible, how can i do it? which command?

Thanks in advance
 
I'd recommend disabling interrupts while manipulating the flash controller. That may be overly paranoid, but it's such a short time for something you probably only do once, so the cost is low.
 
With this code will be enough?

Code:
void loop()
{
  noInterrupts();

  read_mac();

  interrupts();
  
  "PROGRAM CODE"

}
 
Note: the "read_mac()" contributed function yields 6 of of the 8 bytes. The 6 are intended for use with the ethernet controllers such as WiZnet (other than the 5500 chip) that do not come with a pre-assigned MAC address.

The 8 byte unique ID number given by PJRC can be had with Teensy3 code such as this:
Code:
static uint8_t myID[8];

void read_EE(uint8_t word, uint8_t *buf, uint8_t offset)  {
	noInterrupts();
	FTFL_FCCOB0 = 0x41;             // Selects the READONCE command
	FTFL_FCCOB1 = word;             // read the given word of read once area

	// launch command and wait until complete
	FTFL_FSTAT = FTFL_FSTAT_CCIF;
	while(!(FTFL_FSTAT & FTFL_FSTAT_CCIF))
		;
	*(buf+offset+0)	= FTFL_FCCOB4;
	*(buf+offset+1) = FTFL_FCCOB5;       
	*(buf+offset+2) = FTFL_FCCOB6;       
	*(buf+offset+3) = FTFL_FCCOB7;       
	interrupts();
}

		
void read_myID() {
	read_EE(0xe,myID,0); // should be 04 E9 E5 xx, this being PJRC's registered OUI
	read_EE(0xf,myID,4); // xx xx xx xx

}

void print_myID()  {
	Serial.printf(" ID byte = %d decimal, from ", myID[7]);
	for (int i=0; i < sizeof(myID); i++)
		Serial.printf("%02X:", myID[i]);
}
 
Last edited:
Note: the "read_mac()" contributed function yields 6 of of the 8 bytes.

The upper byte of the OUI is unused.

In theory, the serial number is 32 bits. But at the rate we've been assigning the serial numbers, the low 24 bits will not overflow for well over 600 years!
 
FYI: If the serial number is used to derive an Ethernet MAC address, the most significant byte has some IEEE defined coding.
as shown in the graphic, here
http://en.wikipedia.org/wiki/MAC_address

Bit 2, if set to 1, means the MAC address is locally administered; Not registered with the IEEE.
So if you prefer, you can set this bit and all other bits/bytes are up to you to choose, for your LAN. Just make sure you make each device unique. And don't use that MAC address for an edge router to a public network. With NATing routers, this is never an issue.

But since Teensy 3's have a unique serial number, you might use that number to derive the 6 byte Ethernet MAC address. The PJRC OUI group is 04 E9 E5 as the 3 MSBs. The lower 3 bytes can be the the lowest 3 of the 8 byte serial number. These 3 bytes (24 bits) are an ascending number used to serialize each Teensy, per Paul.

An "OUI" is 64 bits. An Ethernet MAC address (48 bits) can be derived from an OUI, and an OUI may have other purposes too.

Technically, one should have approval by PJRC to use addresses in their block starting with 04 E9 E5 - perhaps a blanket statement by PJRC that it be used only for certain purposes beyond the 64 bit product serial number.
 
Technically, one should have approval by PJRC to use addresses in their block starting with 04 E9 E5 - perhaps a blanket statement by PJRC that it be used only for certain purposes beyond the 64 bit product serial number.

PJRC paid for "04 E9 E5" to allow every Teensy 3.x project to have a proper mac address for use with ethernet chips like W5100 & W5200. OUIs have other purposes, but PJRC's main intention was mac addresses with ethernet and other network protocols that require mac addresses.

Our purpose is to facilitate developing hobbyist, academic and even commercial projects. If you're planning to use the PJRC OUI for some other purpose, please discuss it here. If you're buying PJRC-made Teensy boards and using the number from the permanent memory, and if your use isn't something prohibited by IEEE or USA law, odds are good PJRC will approve of your use (whether you really need PJRC's approval is a good question). Obviously I can't make a blanket statement about uses I don't even anticipate, but I can tell you we paid for an official OUI from IEEE specifically for ethernet and networking projects using Teensy3.

When/if the serial number ever increments past 16777215 (in approx 670+ years at the current rate), PJRC will need to obtain a new OUI to replace "04 E9 E5". I have a lot of plans for future developments on the Teensy platform. This is probably the least urgent of all the possible pending issues!
 
Last edited:
Not yet

I am using teensyduino. And i don't know if write these code in a new library or use it in my sketch.
Or if there is some existent library that use it.

thanks
 
Last edited:
The code on #7 appears to be able to simply copy into your sketch in Arduino.

Then you could just call its print_myID() function, perhaps like this:

Code:
void setup() {
}
void loop() {
  print_myID();
  delay(1000);
}

It's ok to try stuff. That's how you learn things. I'd highly recommend giving this a try.

If it doesn't work and you need help, please spend a few minutes to compose a good question, with a screenshot or exact copy of any error message, or a precise description of what went wrong. Short questions lacking details are impossible to answer. Detailed questions with specific info are the way to get good help here!
 
Need to Read before Print - and it worked for me with Msg #7 code dropped in:

Code:
void loop() {
  // put your main code here, to run repeatedly:
  read_myID();
  print_myID();
  delay(1000);
}

Modified the Print to show Serial # as reported in USB (with '0' padded on the end):

Code:
unsigned long serialNum = 0;
void print_myID()  {
  int ii;
  Serial.printf(" ID byte = %d decimal, from ", myID[7]);
  for (ii = 0; ii < sizeof(myID); ii++) {
    if ( ii )
      Serial.printf(" :");
    Serial.printf("%02X", myID[ii]);
    if ( ii > 3)
      serialNum = (serialNum << 8) + myID[ii];
  }
  Serial.printf("   Serial# %lu0\n", serialNum);
}
 
Last edited:
Is there a unique meaning to what is printed as the "ID byte = " in the code in m# 7 above?
Serial.printf(" ID byte = %d decimal, from ", myID[7]);

Is there a way at run time to see what Teensy you are on [LC .vs. 3.1, etc]?
 
Last edited:
I'm not sure at run time, but at compile time there is a unique macro defined based on the CPU (note there are 2 leading and 2 trailing underscores in the processor specific macros):

  • Teensy 3.0: __MK20DX128__
  • Teensy 3.1: __MK20DX256__
  • Teensy LC: __MKL26Z64__

You would use it in conditional compilation:

Code:
#if !defined(CORE_TEENSY)
  Serial.println ("Danger Will Robinson, non-Teensy found");
#elif !defined(__arm__)
  Serial.println ("Running on a non-arm Teensy like the 2.0/2.1++");
#elif defined(__MKL26Z64__)
  Serial.println ("Running on a Teensy LC");
#elif defined(__MK20DX256__)
  Serial.println ("Running on a Teensy 3.1");
#elif defined(__MK20DX128__)
  Serial.println ("Running on a Teensy 3.0");
#else
  Serial.println ("Running on an unknown Teensy processor");
#endif
 
Last edited:
@defragster, post #17
"Modified the Print to show Serial # as reported in USB (with '0' padded on the end)"
Yes, I saw that the last 3 bytes of the Ethernet MAC address differ from the USB serialnumber by the extra trailing zero at the latter.
From both Teensy 3.1's I have here:
MAC address 04:E9:E5:01:45:32, reported USB serial# 832500,
MAC address 04:E9:E5:01:45:96, reported USB serial# 833500.

Do you have any idea why the reported USB serialnumber has an additional zero padded?

Thanks,
Paul


For reference the code I use to get the MAC address:
Code:
uint8_t mac[6];

void read(uint8_t word, uint8_t *mac, uint8_t offset) {
  FTFL_FCCOB0 = 0x41;             // Selects the READONCE command
  FTFL_FCCOB1 = word;             // read the given word of read once area

  // launch command and wait until complete
  FTFL_FSTAT = FTFL_FSTAT_CCIF;
  while (!(FTFL_FSTAT & FTFL_FSTAT_CCIF));

  *(mac + offset) =   FTFL_FCCOB5;     // collect only the top three bytes,
  *(mac + offset + 1) = FTFL_FCCOB6;   // in the right orientation (big endian).
  *(mac + offset + 2) = FTFL_FCCOB7;   // Skip FTFL_FCCOB4 as it's always 0.
}

void read_mac() {
  read(0xe, mac, 0);
  read(0xf, mac, 3);
}

void print_mac()  {
  size_t count = 0;
  for (uint8_t i = 0; i < 6; ++i) {
    if (i != 0) count += Serial.print(":");
    count += Serial.print((*(mac + i) & 0xF0) >> 4, 16);
    count += Serial.print(*(mac + i) & 0x0F, 16);
  }
}

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

void loop() {
}
 
processor specific macros:
  • Teensy 3.0: __MK20DX128__
  • Teensy 3.1: __MK20DX256__
  • Teensy LC: __MKL26Z64__

You would use it in conditional compilation:

Thanks for that compilation @MM - I've never come across it as such. Compile time makes sense since it won't cross compile&load anyhow.

@PaulS: I just made my sample match what I saw reported in TyQt - not sure if the '0' pad is right or why, or if it will break in future.
 
I take it that (unlike others) Freescale ARMs don't have a unique serial number in silicon or OTP memory and so PJRC had to DIY? E.g. the STM32F4's have a 96 bit unique ID.
 
Actually, it looks like there is unique chip serial number.
From the datasheet:
MK20DX256VLH7 datasheet page 1.png
And in the reference manual, the 4 32-bit registers that make up the 128-bit unique ID are described on page 265-267:
MK20DX256VLH7 ref manual page 256.png

Unfortunately, I'm not that familiar with coding C++ to access these registers.

Paul
 
Thanks for that compilation @MM - I've never come across it as such. Compile time makes sense since it won't cross compile&load anyhow.

Conditional compilation allows to bring in extra code that is only available on a particular machine. I use it for example to set constants for pin numbers, so for example using A3/17 for the neopixel pin on the LC, and pin 4 that I was using previously on the Teensy 3.0/3.1. I also for instance enable using EEPROM on Teensy 3.0/3.1 to save the last random number every so often to use as the seed the next time the Teensy is booted, but I don't do it on the Teensy LC, due to the implementation of EEPROM on the LC.
 
Status
Not open for further replies.
Back
Top