Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 13 of 13

Thread: Production serial number, Teensy 4

  1. #1
    Senior Member
    Join Date
    Apr 2018
    Location
    Eastern Time, USA
    Posts
    311

    Production serial number, Teensy 4

    Hi,

    Is there a production compatible way to set serial numbers for the Teensy 4?

    I think the most convenient solution would be if we could write over the serial number in the image flashed to the board.

    Another, might be if there is a command-line build. If so, we could use a define.

    Is there any hope for any of these idea?

    Thank you

  2. #2
    Senior Member
    Join Date
    Apr 2020
    Location
    DFW area in Texas
    Posts
    583
    Quote Originally Posted by DrM View Post
    Hi,

    Is there a production compatible way to set serial numbers for the Teensy 4?

    I think the most convenient solution would be if we could write over the serial number in the image flashed to the board.

    Another, might be if there is a command-line build. If so, we could use a define.

    Is there any hope for any of these idea?

    Thank you
    Can't tell for sure which of the following you are looking to do:

    1) access an existing unique serial number for each Teensy

    2) overwrite any existing unique serial number for each Teensy with your own unique serial number

    3) create your own unique serial number storage for each Teensy

    Also, which T4 ??

    For #1, each T4.1 has a unique MAC address. Would that work as a unique serial number for your intended use ??

    For #3, would a simple #define be sufficient for your intended use ??

    Also for #3, you could just program your unique serial number into EEPROM. Would that work for your intended use ??

    Also for #3, there are a few non-volatile bytes which can be utilized in the RTC (may require the attachment of the backup battery). Would that work for your intended use ??

    Hope that helps . . .

    Mark J Culross
    KD5RXT

  3. #3
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    17,109
    Teensy Serial number is derived from a fixed read only MAC value on each chip set by NXP at the factory: ...\hardware\teensy\avr\cores\teensy4\usb_desc.c
    Code:
    void usb_init_serialnumber(void)
    {
    	char buf[11];
    	uint32_t i, num;
    
    	num = HW_OCOTP_MAC0 & 0xFFFFFF;
    	// 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;
    }
    With a CORES edit the stored/reported serial number could be anything code can do.

  4. #4
    Senior Member
    Join Date
    Apr 2018
    Location
    Eastern Time, USA
    Posts
    311
    So, turning on verbose, I managed to capture the following from the IDE. It seems informative, although there are more than a few mysteries, for example why it repeats the compilation three times each time adding one more library. (I am guessing the ide created the directory /tmp/arduino_build_5983 and that it hangs around until it is closed). But, at any rate, it seems to produce and load an image that boots.

    Is it feasible to simply run this to prepare boards and just add another define, something like -DSN=<serialnumber> ?



    Code:
    /home/nelson/Arduino/arduino-1.8.19/arduino-builder \
        -dump-prefs \
        -logger=machine \
        -hardware /home/nelson/Arduino/arduino-1.8.19/hardware \
        -tools /home/nelson/Arduino/arduino-1.8.19/tools-builder \
        -tools /home/nelson/Arduino/arduino-1.8.19/hardware/tools/avr \
        -built-in-libraries /home/nelson/Arduino/arduino-1.8.19/libraries \
        -libraries /home/nelson/Arduino/Sketchbook/libraries \
        -fqbn=teensy:avr:teensy40:usb=serial,speed=600,opt=o2std,keys=en-us \
        -vid-pid=16C0_0483 \
        -ide-version=10819 \
        -build-path /tmp/arduino_build_598263 \
        -warnings=none \
        -build-cache /tmp/arduino_cache_936807 \
        -verbose \
        /home/nelson/Projects/TeensySpectrometer/Firmware/SpectrometerILX511_SPI/SpectrometerILX511_SPI.ino
    
    /home/nelson/Arduino/arduino-1.8.19/arduino-builder \
        -compile \
        -logger=machine \
        -hardware /home/nelson/Arduino/arduino-1.8.19/hardware \
        -tools /home/nelson/Arduino/arduino-1.8.19/tools-builder \
        -tools /home/nelson/Arduino/arduino-1.8.19/hardware/tools/avr \
        -built-in-libraries /home/nelson/Arduino/arduino-1.8.19/libraries \
        -libraries /home/nelson/Arduino/Sketchbook/libraries \
        -fqbn=teensy:avr:teensy40:usb=serial,speed=600,opt=o2std,keys=en-us \
        -vid-pid=16C0_0483 \
        -ide-version=10819 \
        -build-path /tmp/arduino_build_598263 \
        -warnings=none \
        -build-cache /tmp/arduino_cache_936807 \
        -verbose \
        /home/nelson/Projects/TeensySpectrometer/Firmware/SpectrometerILX511_SPI/SpectrometerILX511_SPI.ino
    
    /home/nelson/Arduino/arduino-1.8.19/hardware/teensy/../tools/arm/bin/arm-none-eabi-g++ \
        -E -CC -x c++ -w -g -Wall -ffunction-sections -fdata-sections -nostdlib -std=gnu++14 -fno-exceptions \
        -fpermissive -fno-rtti -fno-threadsafe-statics -felide-constructors -Wno-error=narrowing -mthumb \
        -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 \
        -D__IMXRT1062__ -DTEENSYDUINO=157 -DARDUINO=10819 -DARDUINO_TEENSY40 -DF_CPU=600000000 -DUSB_SERIAL -DLAYOUT_US_ENGLISH \
        -I/home/nelson/Arduino/arduino-1.8.19/hardware/teensy/avr/cores/teensy4 \
        /tmp/arduino_build_598263/sketch/SpectrometerILX511_SPI.ino.cpp \
        -o /dev/null
    
    /home/nelson/Arduino/arduino-1.8.19/hardware/teensy/../tools/arm/bin/arm-none-eabi-g++ \
        -E -CC -x c++ -w -g -Wall -ffunction-sections -fdata-sections -nostdlib -std=gnu++14 -fno-exceptions \
        -fpermissive -fno-rtti -fno-threadsafe-statics -felide-constructors -Wno-error=narrowing -mthumb \
        -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 \
        -D__IMXRT1062__ -DTEENSYDUINO=157 -DARDUINO=10819 -DARDUINO_TEENSY40 -DF_CPU=600000000 -DUSB_SERIAL -DLAYOUT_US_ENGLISH \
        -I/home/nelson/Arduino/arduino-1.8.19/hardware/teensy/avr/cores/teensy4 \
        -I/home/nelson/Arduino/arduino-1.8.19/hardware/teensy/avr/libraries/ADC \
        /tmp/arduino_build_598263/sketch/SpectrometerILX511_SPI.ino.cpp \
        -o /dev/null
    
    /home/nelson/Arduino/arduino-1.8.19/hardware/teensy/../tools/arm/bin/arm-none-eabi-g++ \
        -E -CC -x c++ -w -g -Wall -ffunction-sections -fdata-sections -nostdlib -std=gnu++14 -fno-exceptions \
        -fpermissive -fno-rtti -fno-threadsafe-statics -felide-constructors -Wno-error=narrowing -mthumb \
        -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 \
        -D__IMXRT1062__ -DTEENSYDUINO=157 -DARDUINO=10819 -DARDUINO_TEENSY40 -DF_CPU=600000000 -DUSB_SERIAL -DLAYOUT_US_ENGLISH \
        -I/home/nelson/Arduino/arduino-1.8.19/hardware/teensy/avr/cores/teensy4 \
        -I/home/nelson/Arduino/arduino-1.8.19/hardware/teensy/avr/libraries/ADC \
        -I/home/nelson/Arduino/arduino-1.8.19/hardware/teensy/avr/libraries/EEPROM \
        /tmp/arduino_build_598263/sketch/SpectrometerILX511_SPI.ino.cpp \
        -o /dev/null
    
    /home/nelson/Arduino/arduino-1.8.19/hardware/teensy/../tools/arm/bin/arm-none-eabi-g++ \
        -E -CC -x c++ -w -g -Wall -ffunction-sections -fdata-sections -nostdlib -std=gnu++14 -fno-exceptions \
        -fpermissive -fno-rtti -fno-threadsafe-statics -felide-constructors -Wno-error=narrowing -mthumb \
        -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 \
        -D__IMXRT1062__ -DTEENSYDUINO=157 -DARDUINO=10819 -DARDUINO_TEENSY40 -DF_CPU=600000000 -DUSB_SERIAL -DLAYOUT_US_ENGLISH \
        -I/home/nelson/Arduino/arduino-1.8.19/hardware/teensy/avr/cores/teensy4 \
        -I/home/nelson/Arduino/arduino-1.8.19/hardware/teensy/avr/libraries/ADC \
        -I/home/nelson/Arduino/arduino-1.8.19/hardware/teensy/avr/libraries/EEPROM \
        /tmp/arduino_build_598263/sketch/SpectrometerILX511_SPI.ino.cpp \
        -o /tmp/arduino_build_598263/preproc/ctags_target_for_gcc_minus_e.cpp
    
    /home/nelson/Arduino/arduino-1.8.19/tools-builder/ctags/5.8-arduino11/ctags \
        -u --language-force=c++ -f - --c++-kinds=svpf --fields=KSTtzns --line-directives \
        /tmp/arduino_build_598263/preproc/ctags_target_for_gcc_minus_e.cpp
    
    /home/nelson/Arduino/arduino-1.8.19/hardware/teensy/../tools/precompile_helper \
        /home/nelson/Arduino/arduino-1.8.19/hardware/teensy/avr/cores/teensy4 \
        /tmp/arduino_build_598263 /home/nelson/Arduino/arduino-1.8.19/hardware/teensy/../tools/arm/bin/arm-none-eabi-g++ \
        -x c++-header -O2 -g -Wall -ffunction-sections -fdata-sections -nostdlib -MMD -std=gnu++14 -fno-exceptions \
        -fpermissive -fno-rtti -fno-threadsafe-statics -felide-constructors -Wno-error=narrowing -mthumb \
        -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 \
        -D__IMXRT1062__ -DTEENSYDUINO=157 -DARDUINO=10819 -DARDUINO_TEENSY40 -DF_CPU=600000000 -DUSB_SERIAL -DLAYOUT_US_ENGLISH \
        -I/home/nelson/Arduino/arduino-1.8.19/hardware/teensy/avr/cores/teensy4 \
        /tmp/arduino_build_598263/pch/Arduino.h \
        -o /tmp/arduino_build_598263/pch/Arduino.h.gch
    
    /home/nelson/Arduino/arduino-1.8.19/hardware/teensy/../tools/arm/bin/arm-none-eabi-g++ \
        -c -O2 -g -Wall -ffunction-sections -fdata-sections -nostdlib -MMD -std=gnu++14 -fno-exceptions \
        -fpermissive -fno-rtti -fno-threadsafe-statics -felide-constructors -Wno-error=narrowing -mthumb \
        -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 \
        -D__IMXRT1062__ -DTEENSYDUINO=157 -DARDUINO=10819 -DARDUINO_TEENSY40 -DF_CPU=600000000 -DUSB_SERIAL -DLAYOUT_US_ENGLISH \
        -I/tmp/arduino_build_598263/pch \
        -I/home/nelson/Arduino/arduino-1.8.19/hardware/teensy/avr/cores/teensy4 \
        -I/home/nelson/Arduino/arduino-1.8.19/hardware/teensy/avr/libraries/ADC \
        -I/home/nelson/Arduino/arduino-1.8.19/hardware/teensy/avr/libraries/EEPROM \
        /tmp/arduino_build_598263/sketch/SpectrometerILX511_SPI.ino.cpp \
        -o /tmp/arduino_build_598263/sketch/SpectrometerILX511_SPI.ino.cpp.o
    
    /home/nelson/Arduino/arduino-1.8.19/hardware/teensy/../tools/arm/bin/arm-none-eabi-gcc \
        -O2 -Wl,--gc-sections,--relax \
        -T/home/nelson/Arduino/arduino-1.8.19/hardware/teensy/avr/cores/teensy4/imxrt1062.ld -mthumb \
        -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 \
        -o /tmp/arduino_build_598263/SpectrometerILX511_SPI.ino.elf \
        /tmp/arduino_build_598263/sketch/SpectrometerILX511_SPI.ino.cpp.o \
        /tmp/arduino_build_598263/libraries/ADC/ADC.cpp.o \
        /tmp/arduino_build_598263/libraries/ADC/ADC_Module.cpp.o \
        /tmp/arduino_build_598263/libraries/ADC/AnalogBufferDMA.cpp.o \
        /tmp/arduino_build_598263/libraries/EEPROM/EEPROM.cpp.o \
        /tmp/arduino_build_598263/../arduino_cache_936807/core/core_52ce2e9d62f4f696f626411e3c70716d.a \
        -L/tmp/arduino_build_598263 -larm_cortexM7lfsp_math -lm -lstdc++
    
    /home/nelson/Arduino/arduino-1.8.19/hardware/teensy/../tools/arm/bin/arm-none-eabi-objcopy \
        -O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings \
        --change-section-lma .eeprom=0 \
        /tmp/arduino_build_598263/SpectrometerILX511_SPI.ino.elf \
        /tmp/arduino_build_598263/SpectrometerILX511_SPI.ino.eep
    
    /home/nelson/Arduino/arduino-1.8.19/hardware/teensy/../tools/arm/bin/arm-none-eabi-objcopy \
        -O ihex -R .eeprom \
        /tmp/arduino_build_598263/SpectrometerILX511_SPI.ino.elf /tmp/arduino_build_598263/SpectrometerILX511_SPI.ino.hex
    
    /home/nelson/Arduino/arduino-1.8.19/hardware/teensy/../tools/teensy_secure encrypthex TEENSY40 /tmp/arduino_build_598263/SpectrometerILX511_SPI.ino.hex
    
    /home/nelson/Arduino/arduino-1.8.19/hardware/teensy/../tools/teensy_post_compile \
        -file=SpectrometerILX511_SPI.ino -path=/tmp/arduino_build_598263 \
        -tools=/home/nelson/Arduino/arduino-1.8.19/hardware/teensy/../tools/ \
        -board=TEENSY40
    
    /home/nelson/Arduino/arduino-1.8.19/hardware/teensy/../tools/stdout_redirect \
        /tmp/arduino_build_598263/SpectrometerILX511_SPI.ino.sym \
        /home/nelson/Arduino/arduino-1.8.19/hardware/teensy/../tools/arm/bin/arm-none-eabi-objdump -t \
        -C /tmp/arduino_build_598263/SpectrometerILX511_SPI.ino.elf
    
    /home/nelson/Arduino/arduino-1.8.19/hardware/teensy/../tools/teensy_size \
        /tmp/arduino_build_598263/SpectrometerILX511_SPI.ino.elf
    
    /home/nelson/Arduino/arduino-1.8.19/hardware/teensy/../tools/teensy_post_compile \
        -file=SpectrometerILX511_SPI.ino \
        -path=/tmp/arduino_build_598263 \
        -tools=/home/nelson/Arduino/arduino-1.8.19/hardware/teensy/../tools \
        -board=TEENSY40 \
        -reboot \
        -port=/dev/ttyACM0 -portlabel=/dev/ttyACM0 -portprotocol=serial

  5. #5
    Senior Member
    Join Date
    Apr 2018
    Location
    Eastern Time, USA
    Posts
    311
    @defragster Thank you. That sounds great. What is CORES edit, and how do I do it? Could I set the manufacturer and product strings too?

  6. #6
    Senior Member
    Join Date
    Apr 2018
    Location
    Eastern Time, USA
    Posts
    311
    BTW, the interrupts and timers are running fantastically well. Thank you to everybody for fantastic help.

  7. #7
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    17,109
    Quote Originally Posted by DrM View Post
    So, turning on verbose, I managed to capture the following from the IDE. It seems informative, although there are more than a few mysteries, for example why it repeats the compilation three times each time adding one more library. (I am guessing the ide created the directory /tmp/arduino_build_5983 and that it hangs around until it is closed). But, at any rate, it seems to produce and load an image that boots.
    ...
    The IDE does some pre-processing work to find and locate the needed libraries and organize the INO's and pre-define for the user functions declared after use, so the user need not do that. In lieu of a MAKE created and maintained by the user - the IDE dynamically discovers needed sources in this multi pass process.

  8. #8
    Senior Member
    Join Date
    Apr 2018
    Location
    Eastern Time, USA
    Posts
    311
    @defragster Great. So here is what works so far, and what I am thinking to do.

    The code snipped below, works. So, the idea is modify the above script to add the following to define the serial number string for each compilation.

    (i.e., to the -Dstuff that it already does, just append the following -DthisPRODUCT_SERIAL_NUMBER=something -DthisPRODUCT_SERIAL_NUMBER _LEN=itslengths)

    What do you think?


    Code:
    #define thisMANUFACTURER_NAME {'s','o','m','e','_','v','e','n','d','o','r','x'}
    #define thisMANUFACTURER_NAME_LEN 12
    
    #define thisPRODUCT_NAME {'s','o','m','e','p','r','o','d','u','c','t','x'}
    #define thisPRODUCT_NAME_LEN 12
    
    #ifndef thisPRODUCT_SERIAL_NUMBER 
    #define thisPRODUCT_SERIAL_NUMBER { '0','0','0','0','0','0','0','0','0','0','0','0' }
    #define thisPRODUCT_SERIAL_NUMBER_LEN 12
    #endif
    
    extern "C"
    {
      struct usb_string_descriptor_struct_manufacturer
      {
        uint8_t bLength;
        uint8_t bDescriptorType;
        uint16_t wString[thisMANUFACTURER_NAME_LEN];
      };
    
      usb_string_descriptor_struct_manufacturer usb_string_manufacturer_name = {
        2 + thisMANUFACTURER_NAME_LEN * 2,
        3,
        thisMANUFACTURER_NAME
      };
      
      struct usb_string_descriptor_struct_product
      {
        uint8_t bLength;
        uint8_t bDescriptorType;
        uint16_t wString[thisPRODUCT_NAME_LEN];
      };
    
      usb_string_descriptor_struct_product usb_string_product_name = {
        2 + thisPRODUCT_NAME_LEN * 2,
        3,
        thisPRODUCT_NAME
      };
    
      struct usb_string_descriptor_struct_serial_number
      {
        uint8_t bLength;
        uint8_t bDescriptorType;
        uint16_t wString[thisPRODUCT_SERIAL_NUMBER_LEN];
      };
    
      usb_string_descriptor_struct_serial_number usb_string_serial_number =
        {
          2 + thisPRODUCT_SERIAL_NUMBER_LEN * 2, 
          3,
          thisPRODUCT_SERIAL_NUMBER
        };
    }

  9. #9
    Senior Member
    Join Date
    Apr 2018
    Location
    Eastern Time, USA
    Posts
    311
    Sorry, I made an edit, the above is now what I actually have running.

  10. #10
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    27,951
    Those early gcc commands are with "-E", which gcc documents as "Preprocess only; do not compile, assemble or link". Arduino uses this to discover which libraries are actually needed. Old versions of Arduino only parsed the main .ino file and used simple regex patterns. Modern Arduino IDE looks in all the .cpp files. Running the preprocessor (gcc -E) is required to properly deal with #ifdef surrounding a #include. Each new include discovered could have more #define lines, so the process of faithfully finding all actually included files is iterative.

    The data in HW_OCOTP_MAC0 is written by PJRC during product testing. NXP ships IMXRT chips with those fuse bits all zeros.

    Fuse memory is not erasable. Once a 0 bit is changed to 1, it can never go back to 0. Additionally, certain groups of fuses have a write-inhibit fuse bit, which once changed to 1 restricts any further changes within that group. Altering the fase-based mac address is impossible by software.

    The USB code initializes a memory buffer with the serial number converted to USB string format. If you overwrite that buffer, you can cause anything you like to be transmitted in the USB string descriptor when your PC asks for the serial number. The trick is you must do this before the PC requests that descriptor. Unfortunately there is no simple way to do this without editing the core library. The middle startup hook runs before the 20 ms delay and USB initialization and late hook runs just before C++ constructors. The serial number string buffer is written during USB initialization, so anything you do from the middle hook will be overwritten. The late hook might still work, but if your PC is fast it could be too late by that point.

    Perhaps in future versions we should break the USB initialization into 2 steps, to put initialization of USB descriptor buffers before the middle startup hook.

  11. #11
    Senior Member
    Join Date
    Apr 2018
    Location
    Eastern Time, USA
    Posts
    311
    @PaulStoffregen Hi Paul, thank you. I think I have go this part under control for the time being. I am about to post another more serious question on another thread/

  12. #12
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    17,109
    Quote Originally Posted by PaulStoffregen View Post
    ...
    The data in HW_OCOTP_MAC0 is written by PJRC during product testing. NXP ships IMXRT chips with those fuse bits all zeros.
    ...
    Opps - knew note was a bit wrong as PJRC gets to control Ser# progression.

    Also wondered about User code timing with a hook versus CORES edit - and noticed there is a 'weak' on the related Ser# string?

  13. #13
    Senior Member
    Join Date
    Apr 2018
    Location
    Eastern Time, USA
    Posts
    311
    @defragster Yep, I used that. I think I found it mentioned in one of your old posts and then tracked it down in Paul's source codes.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •