nRF5340 - runtime change of iSerialNumber

Hi,
I wanted to change at runtime the iSerialNumber exposed by USB descriptor.
As Kenneth suggested (link), the solution has been to override the weak function in usb_descriptor.c

weak uint8_t *usb_update_sn_string_descriptor(void)
{
  snprintk(usb_serial_str, sizeof(usb_serial_str), USB_SERIALNUMBER_TEMPLATE,
    (uint32_t)(NRF_FICR->DEVICEADDR[1] & 0x0000FFFF)|0x0000C000,
    (uint32_t)NRF_FICR->DEVICEADDR[0]);

  return usb_serial_str;
}

with this one

uint8_t *usb_update_sn_string_descriptor(void)
{
  snprintk(usb_serial_str, sizeof(usb_serial_str), USB_SERIALNUMBER_TEMPLATE, sn_recovered_from_littlefs);

  return usb_serial_str;
}

The problem is that the override function is executed when the littlefs is still unmounted, thus sn_recovered_from_littlefs=0.
What's the storage location of the iSerialNumber "D0766E074450A9F0" the nRF5340 uses if untouched ?

  • It seems to be kept in global memory space which means it is different for different application. You can probably attempt to write a linker file to create a memory section and keep this structure defined in zephyr\subsys\usb\device\usb_descriptor.c

  • Hi Susheel

    Could you please expand a bit more your idea ?

    Consider that each board has a serial number, which is uniquely assigned at some stage of manufacturing. This serial number shall be persistently stored in flash, and assigned to iSerialNumber.  

  • If you want to persistently store the serial number in flash, then store it at know address (or key/value) location.

    inside usb_update_sn_string_descriptor, you can load the value in that address location to see if there is any data saved. If there is none, save the serial number and use that instead of sn_recovered_from_littlefs. 

    What's the storage location of the iSerialNumber "D0766E074450A9F0" the nRF5340 uses if untouched ?

    Right now, it seems it lives in the .bss section allocated by the compiler. Unless you created a linker script to save string_descr (in zephyr\subsys\usb\device\usb_descriptor.c)  at a specified location, you do not have control on where that is saved.

  • Hello Susheel,
    I've overridden the usb_update_sn_string_descriptor function for returning the actual serial number retrieved from settings subsystem, this way

    static uint8_t sn[sizeof(CONFIG_USB_DEVICE_SN) + 1];
    uint8_t *usb_update_sn_string_descriptor(void)
    {
    	int rc;
    	uint32_t val = COSMED_SN_DEFAULT;
    
    	memset(sn, 0, sizeof(sn));
    
    	rc = settings_subsys_init();
    	if (rc) {
    		LOG_ERR("error initializing settings subsys [%d]", rc);
    	} else {
    		rc = load_immediate_value("id/sn", &val, sizeof(val));
    		if (rc == -ENOENT) {
    			val = COSMED_SN_DEFAULT;
    		} else if (rc == 0) { 
    			printk("<id/sn> = %u\n", val);
    		} else {
    			LOG_ERR("error loading sn from settings [%d]", rc);
    		}
    	}
    
    	LOG_WRN("TODO: manage to store sn in settings from user input");
    	//rc = settings_save_one("id/sn", (const void *)&val, sizeof(val));
    
    	snprintk(sn, sizeof(sn), "%u", val);
    
    	return sn;
    }

    The very first print out of console is "error initializing settings subsys [-19]".
    This is a ENODEV return of settings_subsys_init().
    For some reason the settings subsystem cannot be initialized at such an early stage of start up.

    By the way, calling settings_subsys_init() at the beginning of main() doesn't rise this exception.

    A hand needed. Thanks in advance

Related