MicroMod Custom serial number

Dogbone06

Well-known member
I'm trying to have a custom serial number presented over the USB protocol. It works but there is a small issue.
EDIT: Serial numbers are unique and read from the EEPROM at boot.

I use this in setup of my code, so it's triggered quite early at boot:

Code:
extern "C"
{
  
    struct usb_string_descriptor_struct
    {
      uint8_t bLength;
      uint8_t bDescriptorType;
      uint16_t wString[22];
    };

    usb_string_descriptor_struct usb_string_serial_number =
    {
      12,
      3,
      {0,0,0,0,0,0,0,0,0,0}
    };
}

void setUSBserialNo(long Serial)
{
	char buf[11];
	uint32_t i, num;

	num = Serial;
	// 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.wString[i] = c;
	}
	usb_string_serial_number.bLength = i * 2 + 2;
}

setUSBserialNo("12345678");

The problem I face now is that my flash tool (build with Luni's awesome libTeensySharp) doesn't like this solution.
Devices reboots into halfkay just as it should, but the program doesn't detect that unless I unplug and plug back in my device (it's battery powered so stays in halfkay).

So you might think it's a problem with my custom flash tool, which may very well be the case.
If I don't do the custom serial number code above, it all works fine.

I would greatly appreciate any help to solve the last little hurdle.
Thanks! :eek:
 
Last edited:
Wondering if you simply want a fixed serial number if you could simply not use the default one?

That is in usb_desc.c you have:

Code:
extern struct usb_string_descriptor_struct usb_string_serial_number
        __attribute__ ((weak, alias("usb_string_serial_number_default")));

...

struct usb_string_descriptor_struct usb_string_serial_number_default = {
        12,
        3,
        {0,0,0,0,0,0,0,0,0,0}
};

If different file if you just not use this default one and instead simiply define
Code:
struct usb_string_descriptor_struct usb_string_serial_number = {
        12,
        3,
        {0,0,0,0,0,0,0,0,0,0}
};
But replace the 0s, with your wanted value and update the size field to what you need. But again not sure if this is really what you want or not.
 
Wondering if you simply want a fixed serial number if you could simply not use the default one?

That is in usb_desc.c you have:

Code:
extern struct usb_string_descriptor_struct usb_string_serial_number
        __attribute__ ((weak, alias("usb_string_serial_number_default")));

...

struct usb_string_descriptor_struct usb_string_serial_number_default = {
        12,
        3,
        {0,0,0,0,0,0,0,0,0,0}
};

If different file if you just not use this default one and instead simiply define
Code:
struct usb_string_descriptor_struct usb_string_serial_number = {
        12,
        3,
        {0,0,0,0,0,0,0,0,0,0}
};
But replace the 0s, with your wanted value and update the size field to what you need. But again not sure if this is really what you want or not.

I should have been clearer above, sorry about that.
The serial number cannot be fixed, it's read from the EEPROM so it's different on all devices.

Wonder why the tool doesn't detect it after reboot. Perhaps some fancy windows-usb-refresh thing could solve it, that's what I'm looking into now.
 
Disclaimer: I didn't work on TeensySharp for years and I could be wrong.

When TeensySharp reboots the board it triggers the process and then waits until a board with the same serialnumber but the halfkay PID appears on the bus. IIRC the bootloader will not use your serialnumber but uses its own (the original one). So, after rebooting the serial number changes and TeensySharp doesn't recognise the board as the one which it just rebooted.

Any reason why you want to change the serial number in the first place? Can't you use the built in serialnumber?
 
Disclaimer: I didn't work on TeensySharp for years and I could be wrong.

When TeensySharp reboots the board it triggers the process and then waits until a board with the same serialnumber but the halfkay PID appears on the bus. IIRC the bootloader will not use your serialnumber but uses its own (the original one). So, after rebooting the serial number changes and TeensySharp doesn't recognise the board as the one which it just rebooted.

Any reason why you want to change the serial number in the first place? Can't you use the built in serialnumber?

Thank you Luni for replying. Makes total sense, and I suspected something with the serial number.

I need to have my own serial numbers because of revisions in the code. Different functions and such. I've considered using the OEM serial numbers but that would require a database instead. My own serial numbers work on range where the first 3 numbers are revision and hardware and such.
You see above how I change the serial for the Teensy over the USB. Is it possible to do the same for halfkey?
 
Paul could give a reliable answer, but I don't think you can change this. It is probably burnt in some read only memory. Couldn't you simply store your revision etc information in the EEPROM and send it on request to the PC?
 
Paul could give a reliable answer, but I don't think you can change this. It is probably burnt in some read only memory. Couldn't you simply store your revision etc information in the EEPROM and send it on request to the PC?

Let's hope he posts something, I'm stuck with this issue.
Yes that could be done, I just haven't found a good way of reliably make it work. But I'm also very much a noob when it comes to .exe programs, this is my first ever, it works fine in this configuration.
So having the serial number in the USB protocol makes it just work smoothly for me. Or well, almost lol.
 
Unfortunately changing this to other means of identification (e.g. same USB Port) would be quite some rework.

Reading/Writing to the serial port from a c# PC application is not really difficult. See here for examples: https://github.com/TeensyUser/doc/wiki/Serial

This example you linked is exactly what I need, thank you for that!
If Paul doesn't come in and save the day with his magic, then I will for sure use that link!
 
I should have been clearer above, sorry about that.
The serial number cannot be fixed, it's read from the EEPROM so it's different on all devices.

Wonder why the tool doesn't detect it after reboot. Perhaps some fancy windows-usb-refresh thing could solve it, that's what I'm looking into now.

The example from post #2 is just a set of characters - you could replace those in {0,0,0,0,0,0,0,0,0,0} from EEPROM reads.

That may need to be done before setup() when the USB is initialized in the startup_middle_hook(); before USB init.

See: Teensy-4-x-Hooks-before-setup()
 
Decided to play using p#2 and linked p#10 code.

Not sure if it is ideal, but it works.
Comment the '#define USE_REAL' to force a serial # of choice from sketch, Run UNCOMMENTED first to save desired to EEPROM.
Minimal edit to last two digits from EEPROM demonstrated - from factory 13287570 on this T_4.1 to arrive as 13287511.
>Still presents as factory stored Serial# during bootloader programming, then arrives to USB Host on restart.
Code:
#include "usb_names.h"
#include <EEPROM.h>

[B]#define USE_REAL 1 // Uncomment this to revert to actual serial # : saved desired in EEPROM[/B]
#ifdef USE_REAL
extern "C" usb_string_descriptor_struct usb_string_serial_number;  // usb_string_serial_number_default; // 13287570
#else
usb_string_descriptor_struct usb_string_serial_number = {
  // 13287570
  18,
  3,
  { 49, 51, 50, 56, 55, 53, 55, 48 }  // These have 'zero' bytes between as stored
};
#endif

/* ref: https://forum.pjrc.com/threads/72594-MicroMod-Custom-serial-number?p=324185&viewfull=1#post324185
struct usb_string_descriptor_struct usb_string_serial_number_default = {
        12,         3,        {0,0,0,0,0,0,0,0,0,0} };
*/

char *mySn = (char *)&usb_string_serial_number;

extern "C" void startup_middle_hook(void);
FLASHMEM void startup_middle_hook(void) {
#ifdef USE_REAL
  EEPROM.write(100, 49);  // Store a fake Number
  EEPROM.write(101, 49);  // Store a fake Number
#else
  mySn[14] = EEPROM.read(100);  // >> 13287511 : Only works with local copy as it gets overwritten after this otherwise
  mySn[16] = EEPROM.read(101);
  ;  // >> 13287511 : Only works with local copy as it gets overwritten after this otherwise
#endif
}

void setup() {
  Serial.begin(115200);
  while (!Serial && millis() < 14000)
    ;
  Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);
  if (CrashReport)
    Serial.print(CrashReport);
  Serial.print("------\n");
  Serial.printf("[0]=0x%x \t [1]=0x%x\n", mySn[0], mySn[1]);
  for (int ii = 2; ii < 2 + mySn[0]; ii++) {
    Serial.printf("ii=%2d: %X\t%d ::%c\n", ii, mySn[ii], mySn[ii], mySn[ii]);
  }
  Serial.print("------\n");
}

void loop() {
  // put your main code here, to run repeatedly:
}
 
Last edited:
Decided to play using p#2 and linked p#10 code.

Not sure if it is ideal, but it works.
Comment the '#define USE_REAL' to force a serial # of choice from sketch, Run UNCOMMENTED first to save desired to EEPROM.
Minimal edit to last two digits from EEPROM demonstrated - from factory 13287570 on this T_4.1 to arrive as 13287511.
>Still presents as factory stored Serial# during bootloader programming, then arrives to USB Host on restart.
Code:
#include "usb_names.h"
#include <EEPROM.h>

[B]#define USE_REAL 1 // Uncomment this to revert to actual serial # : saved desired in EEPROM[/B]
#ifdef USE_REAL
extern "C" usb_string_descriptor_struct usb_string_serial_number;  // usb_string_serial_number_default; // 13287570
#else
usb_string_descriptor_struct usb_string_serial_number = {
  // 13287570
  18,
  3,
  { 49, 51, 50, 56, 55, 53, 55, 48 }  // These have 'zero' bytes between as stored
};
#endif

/* ref: https://forum.pjrc.com/threads/72594-MicroMod-Custom-serial-number?p=324185&viewfull=1#post324185
struct usb_string_descriptor_struct usb_string_serial_number_default = {
        12,         3,        {0,0,0,0,0,0,0,0,0,0} };
*/

char *mySn = (char *)&usb_string_serial_number;

extern "C" void startup_middle_hook(void);
FLASHMEM void startup_middle_hook(void) {
#ifdef USE_REAL
  EEPROM.write(100, 49);  // Store a fake Number
  EEPROM.write(101, 49);  // Store a fake Number
#else
  mySn[14] = EEPROM.read(100);  // >> 13287511 : Only works with local copy as it gets overwritten after this otherwise
  mySn[16] = EEPROM.read(101);
  ;  // >> 13287511 : Only works with local copy as it gets overwritten after this otherwise
#endif
}

void setup() {
  Serial.begin(115200);
  while (!Serial && millis() < 14000)
    ;
  Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);
  if (CrashReport)
    Serial.print(CrashReport);
  Serial.print("------\n");
  Serial.printf("[0]=0x%x \t [1]=0x%x\n", mySn[0], mySn[1]);
  for (int ii = 2; ii < 2 + mySn[0]; ii++) {
    Serial.printf("ii=%2d: %X\t%d ::%c\n", ii, mySn[ii], mySn[ii], mySn[ii]);
  }
  Serial.print("------\n");
}

void loop() {
  // put your main code here, to run repeatedly:
}

So this makes it use the custom serial number in halfkay mode as well? Will certainly give this a try!
 
So this makes it use the custom serial number in halfkay mode as well? Will certainly give this a try!

No, once set to bootloader (RED LED on) the device reports as Factory PJRC serial number as seen here using TyCommander as SerMon.

Noted p#11 above:
>Still presents as factory stored Serial# during bootloader programming, then arrives to USB Host on restart.
... [with serial number generated by CODE in startup_middle_hook()]

This seems an artifact of the 1062 processor bootloader programming process ... to confirm if locked and what the secured key may be to confirm the HASH present locked/lockable or not. The computer obviously does see the transition - but at that point only the Teensy loader can communicate with the Teensy.

From a cold start it seems to proceed directly to the code to run and present the altered/desired serial number.
 
No, once set to bootloader (RED LED on) the device reports as Factory PJRC serial number as seen here using TyCommander as SerMon.

Noted p#11 above:

... [with serial number generated by CODE in startup_middle_hook()]

This seems an artifact of the 1062 processor bootloader programming process ... to confirm if locked and what the secured key may be to confirm the HASH present locked/lockable or not. The computer obviously does see the transition - but at that point only the Teensy loader can communicate with the Teensy.

From a cold start it seems to proceed directly to the code to run and present the altered/desired serial number.

Thanks for taking the time, I appreciate that!
The tool I use needs the halfkay to present the same serial number or else it wont work. So I think the only solution in my case is to skip the custom serial numbers and simply have it transmitted over serial instead.
 
So the 'tool' does the programming of the Teensy? Or just has to recognize them when the RED LED is lit (in bootloader)? Doubt that software fits in half a 'Kay anymore :)

Had not done this much before to see the results. Understood the runtime presented number could be changed (used to be in low level CORES code) as it comes from software, but indeed the bootloader RED LED presents the factory value.

The PJRC Ser# is unique and won't be changeable as presented when the RED LED is on so that seems to meet the needs. May be good as trusting the Ser# from a running device could be set to any value.
 
So the 'tool' does the programming of the Teensy? Or just has to recognize them when the RED LED is lit (in bootloader)? Doubt that software fits in half a 'Kay anymore :)

Had not done this much before to see the results. Understood the runtime presented number could be changed (used to be in low level CORES code) as it comes from software, but indeed the bootloader RED LED presents the factory value.

The PJRC Ser# is unique and won't be changeable as presented when the RED LED is on so that seems to meet the needs. May be good as trusting the Ser# from a running device could be set to any value.

The tool is like TeensyLoader alltho it's a fully custom tool that looks very nice for the user. Build on libTeensySharp.
Apparently libTeensySharp "saves" the serial number of the device and expects the same serial number when it boots into halfkay for programming. And because I had custom serial number going, it would not be the same in halfkay, bricking the tool.

So I have reverted back now to standard serial number and made the program communicate over serial to present the EEPROM serial number to the flash tool.
It needs that in order to determine what hardware it is.

So all and all, my situation is basically solved, but it would have been cool to be able to do it over the USB protocol.
 
Not sure if it would solve your desire to do over USB, but wondering about customizing the product name string instead of the serial number string
 
Not sure if it would solve your desire to do over USB, but wondering about customizing the product name string instead of the serial number string

That's a great idea, I will try it and see where it takes me and report back.

EDIT: It works! Thank you for such a great idea, I didn't think of that before.
I hope this thread is helpful for someone else with similar ideas/issues.

To all of you, thanks, great community! :cool:
 
Last edited:
Great a workable solution was found for use!

Was fun to actually code with the snippet from KurtE to get to p#11 - took some twists but haven't gotten something fun to do lately.
 
Great a workable solution was found for use!

Was fun to actually code with the snippet from KurtE to get to p#11 - took some twists but haven't gotten something fun to do lately.

A good community can achieve anything! :cool:

OFF TOPIC: Wanna do something fun? We got a custom NXP board with external PSRAM and FLASH, the idea is to make eLCD work with an RGB screen.
talk to @Rezo on here if you feel like that would be fun. I made the board, he has it in his possession, he's quite busy lately so he hasn't started on it yet.
 
A good community can achieve anything! :cool:

OFF TOPIC: Wanna do something fun? We got a custom NXP board with external PSRAM and FLASH, the idea is to make eLCD work with an RGB screen.
talk to @Rezo on here if you feel like that would be fun. I made the board, he has it in his possession, he's quite busy lately so he hasn't started on it yet.

Having worked with the eLCDIF module, I can tell you it's not going to work with PSRAM - it's too slow to keep up, even in direct 8-bit mode.
 
Having worked with the eLCDIF module, I can tell you it's not going to work with PSRAM - it's too slow to keep up, even in direct 8-bit mode.
We’ll use in internal RAM for now, just use small partial buffers.
But we do have a custom test board with SDRAMin development so can benefit from that when it’s ready
 
Having worked with the eLCDIF module, I can tell you it's not going to work with PSRAM - it's too slow to keep up, even in direct 8-bit mode.

Would you be able to share your work? It's always nice to see what others have done to learn. :)
Totally understand if you can't tho!
 
Back
Top