Custom Teensy Write Once Memory "Burn" Direction needed

Status
Not open for further replies.

crees

Well-known member
I have been searching for some time about any information on how to "burn" a MAC address/Serial into a fixed spot on the MK20 Chip. I would like to uniquely identify the chip without having the ability to change it again. Thanks
 
That is already done by PJRC. Each Teensy comes with a unique MAC/Serial #

I believe this is the case with Teensy Purchased from authorized sources. However I purchased the Bootloader chip from pjrc but sourced my own MK20 Chip. I believe the its the MK20 chip that has the "burned" serial number in it? I did run a MAC script from the forum and all I get is the FF:FF:FF...... response.
 
I have reached the next phase of my project and looking for answers on how to set the unique ID on my custom Teensy based boards. One main reason is the USB uses this to uniquely identify it. My project will use multiple USB connections and each of them using the 4294967295 (highest number) as its intentity is throwing my software off. I could go in and perhaps change some of the way the USB library sends this info while uploading code but it complicates things when I need to use a common firmware among multiple boards. Any help on how to set this would be appreciated. I recall that this field is also a write once and cannot be changed.
 
Indeed write once area - not seen it explained - though it is in the Manual

A quick fix might be to go into the USB segment where the number is read and return a unique number. You could put one into EEPROM on each and read and return that to keep them unique from the same source code?

If you edit this : usb_init_serialnumber(void) in usb_desc.c that should work.

Perhaps edit at the end and something like "if (num == 4294967295 )" then read from the prepared EEPROM space and use that number?

I did another test the other day and EEPROM read seemed to be usable at the early time when USB was being woke.


I thought about that when I got the Alpha T_3.6 board that didn't get a Serial# written but never did it.
 
Indeed write once area - not seen it explained - though it is in the Manual

A quick fix might be to go into the USB segment where the number is read and return a unique number. You could put one into EEPROM on each and read and return that to keep them unique from the same source code?

If you edit this : usb_init_serialnumber(void) in usb_desc.c that should work.

Perhaps edit at the end and something like "if (num == 4294967295 )" then read from the prepared EEPROM space and use that number?

I did another test the other day and EEPROM read seemed to be usable at the early time when USB was being woke.


I thought about that when I got the Alpha T_3.6 board that didn't get a Serial# written but never did it.

Thanks defragster! That is probably what I will need to do. Very good suggestion! I also found some code on pulling the UUID of the chip so I have some method to utilize that in creating unique ID's etc.
 
UID :: Yeah - I found that once too - lots of bits!:
Code:
#ifndef __MKL26Z64__  // Seems valid for T_3.x family
	unsigned long chipNum[4] = { SIM_UIDH, SIM_UIDMH, SIM_UIDML, SIM_UIDL };
#else // T_LC skips one value
	unsigned long chipNum[4] = { 0L, SIM_UIDMH, SIM_UIDML, SIM_UIDL };
#endif
 
UID :: Yeah - I found that once too - lots of bits!:
Code:
#ifndef __MKL26Z64__  // Seems valid for T_3.x family
	unsigned long chipNum[4] = { SIM_UIDH, SIM_UIDMH, SIM_UIDML, SIM_UIDL };
#else // T_LC skips one value
	unsigned long chipNum[4] = { 0L, SIM_UIDMH, SIM_UIDML, SIM_UIDL };
#endif

Yes! I don't dare just use one block.... Hmmmm
 
Did you get a working way to show a unique Serial # from code?

Yes! and thank you! It will be better anyways. My code is on my work machine I will need to post what I was able to do but just as you suggest I added a if statement and told it to use a custom number if all values were FF: etc.. I have not incorporated reading values from eeprom yet but it should work ok.
 
Great to know it works.

If you try EEPROM you might use what I did here: Configure-USB-after-sketch-has-already-loaded

Working in the core's c code the EEPROM wasn't visible when built - so I put the function shown there in my sketch and called that from the core code. Then it seemed to be getting called about 50 times during USB enumeration - so as noted later I should have made that read just the first time to a static and return the static each time after the first when it was set. Where this code is on serial # read won't likely have that repeating issue.

The other good thing is this offers a work around so you might get BOLD and read the manual on writing the one time area with a serial number, and worst case mess up a processor or two and have to have those continue to use this software correction. I never tried it because I didn't have that 'luxury' so I didn't want to try without a good reason. If you do that would be nice to see.
 
Great to know it works.

If you try EEPROM you might use what I did here: Configure-USB-after-sketch-has-already-loaded

Working in the core's c code the EEPROM wasn't visible when built - so I put the function shown there in my sketch and called that from the core code. Then it seemed to be getting called about 50 times during USB enumeration - so as noted later I should have made that read just the first time to a static and return the static each time after the first when it was set. Where this code is on serial # read won't likely have that repeating issue.

The other good thing is this offers a work around so you might get BOLD and read the manual on writing the one time area with a serial number, and worst case mess up a processor or two and have to have those continue to use this software correction. I never tried it because I didn't have that 'luxury' so I didn't want to try without a good reason. If you do that would be nice to see.

Finally getting to trying out the eeprom read. I see your code in the other example as a void function. I am not clear yet on how to call it into the core code from my sketch and making it a static, this is good stuff and is what I need to learn more . Thanks!
 
Maybe I should consider an edit to the USB code, to have it return a serial number based on NXP/Freescale's unique IDs when the program-once memory is blank?
 
Maybe I should consider an edit to the USB code, to have it return a serial number based on NXP/Freescale's unique IDs when the program-once memory is blank?

That would be fantastic for those with custom Teensy boards! In my case I will be having several on a USB hub and need an efficient way to have each one with their own "ID". EEPROM is one way (still working on it) but I like your suggestion even better.

crees
 
That would be better than void (-1 ) info as the Ser# is used by TyCommander. I wondered about doing that but wasn't sure how the bits mapped to get a unique number
 
I added to the existing code to pull part of the MCU id (third segment) and use that as the ID. This is found around line 1451 from usb_desc.c

This section basically checks the location where the teensy serial number is written (write once memory) If it reads FFFFFFFF (4294967295) then its a MCU without a teensy SN. If true then it will use part of the 32 bit SIM_UIDML MCU ID

There are examples of the MCU ID that I have pulled from different boards.

Array 128-bit UniqueID from chip: 95710000-E0CD002F-002C5008-49634E45
Array 128-bit UniqueID from chip: 95710000-E0CD002F-000D5008-49634E45

The part that changes and is unique is the third set (SIM_UIDML)




Code:
void usb_init_serialnumber(void)
{
	char buf[11];
	uint32_t i, num;

	__disable_irq();
#if defined(HAS_KINETIS_FLASH_FTFA) || defined(HAS_KINETIS_FLASH_FTFL)
	FTFL_FSTAT = FTFL_FSTAT_RDCOLERR | FTFL_FSTAT_ACCERR | FTFL_FSTAT_FPVIOL;
	FTFL_FCCOB0 = 0x41;
	FTFL_FCCOB1 = 15;
	FTFL_FSTAT = FTFL_FSTAT_CCIF;
	while (!(FTFL_FSTAT & FTFL_FSTAT_CCIF)) ; // wait
	num = *(uint32_t *)&FTFL_FCCOB7;
	
	//If num = FFFFFFFF.. then we must have a MCU that has no burned serial number (Custom Teensy?)
	//if so lets use SIM_UIDML (part of MCU Serial Number) instead
	if (num == 4294967295) {
		num = SIM_UIDML;
	}

#elif defined(HAS_KINETIS_FLASH_FTFE)
	kinetis_hsrun_disable();
	FTFL_FSTAT = FTFL_FSTAT_RDCOLERR | FTFL_FSTAT_ACCERR | FTFL_FSTAT_FPVIOL;
	*(uint32_t *)&FTFL_FCCOB3 = 0x41070000;
	FTFL_FSTAT = FTFL_FSTAT_CCIF;
	while (!(FTFL_FSTAT & FTFL_FSTAT_CCIF)) ; // wait
	num = *(uint32_t *)&FTFL_FCCOBB;
	kinetis_hsrun_enable();
	//unsigned char mpcnum[num];
	
	//If num = FFFFFFFF.. then we must have a MCU that has no burned serial number (Custom Teensy?)
	//if so lets use SIM_UIDML (part of MCU Serial Number) instead
	if (num == 4294967295) {
	num = SIM_UIDML;
	}
#endif
	__enable_irq();
	// add extra zero to work around OS-X CDC-ACM driver bug
	if (num < 10000000) num = num * 10;
	ultoa(num, buf, 10);
	for (i=0; i<10; i++) {
		char c = buf[i];
		if (!c) break;
		usb_string_serial_number_default.wString[i] = c;
	}
	usb_string_serial_number_default.bLength = i * 2 + 2;
}
 
Last edited:
I added to the existing code to pull part of the MCU id (third segment) and use that as the ID.
...

I have a PJRC K66 Beta board for T_3.6 that has no programmed serial # that returns the -1 value. I put this code in and indeed it works … except during reset, which includes after upload when the bootloader seems to push out what it read from that area.

I made a note here.

More notes there but TyCommander isn't happy about the way the # shifts on reset as it is expecting continuity through reset. Koromix could probably incorporate an exception for that - but it may affect other things too?
 
Resetting the hard pin on the teensy seems fine and reboots the board with the same serial number.

I need to test this function

_reboot_Teensyduino()

However Tycommander Reset invokes the bootloader and as you have found it injects code for the MCU to use the write once for USB ID. But If I hit reset again it goes back to the correct ID. Thoughts?

That brings me to thought.... can the bootloader be updated by the pjrc team to check for empty SN and if so use CPU ID?
 
My idea was to see if Koromix can see a path - and has the time - to handle the 'cusp' with a continuously connected device on same port - when it goes across '-1'

If the bootloader can read the Ser# from one time - perhaps it can also get the MCU info - but that would be for Paul - and he's working on critical stuff as needed and getting the T_4 ready to ship … and this would be down the list.

I assume the one time write is do-able and documented - but the only such MCU I have is the PJRC Beta K66 T_3.6 (commemorative) board I wouldn't want to risk.
 
Status
Not open for further replies.
Back
Top