Eureka! First, here are my EEPROM read/write functions: //// // eeprom.h: eeprom read/write functions for PIC18F MCUs // Phil Pemberton // read the byte at from data EEPROM unsigned char eeGet(unsigned int addr); // write the byte to data EEPROM at address void eePut(unsigned int addr, unsigned char data); // read bytes of data from data EEPROM into the array void eeGetBlock(unsigned int addr, unsigned char *data, unsigned char count); // write bytes of data from the array into data EEPROM void eePutBlock(unsigned int addr, const unsigned char *data, unsigned char count); //// end eeprom.h //// // eeprom.c: eeprom read/write functions for PIC18F MCUs // Phil Pemberton #include // FIXME: change this for whatever chip is in use #include "eeprom.h" // read the byte at from data EEPROM unsigned char eeGet(unsigned int addr) { // load the address // EEADRH = (addr >> 8); EEADR = (addr & 0xff); // reading from data memory, not pgm flash EECON1bits.EEPGD = 0; EECON1bits.CFGS = 0; EECON1bits.RD = 1; return EEDATA; } void eePut(unsigned int addr, unsigned char data) { int old_gie; // load the address // EEADRH = (addr >> 8); EEADR = (addr & 0xff); // reading from data memory, not pgm flash EECON1bits.EEPGD = 0; EECON1bits.CFGS = 0; EECON1bits.WREN = 1; // critical write sequence old_gie = INTCONbits.GIE; INTCONbits.GIE = 0; _asm MOVLW 0x55 MOVWF EECON2,0 MOVLW 0xAA MOVWF EECON2,0 _endasm // do the write and wait for it to complete EECON1bits.WR = 1; while (EECON1bits.WR); // end of critical write sequence INTCONbits.GIE = old_gie; // disable EEPROM writes EECON1bits.WREN = 0; } void eeGetBlock(unsigned int addr, unsigned char *data, unsigned char count) { int x; for (x=0; x> 4]; usb_serial_str.string[i*2+1] = hexconv[snblock[i] & 0x0F]; } // set the descriptor length and type usb_serial_str.bLength = sizeof(usb_serial_str); usb_serial_str.bDscType = DSC_STR; // prepare the data transfer (which is done elsewhere) ctrl_trf_session_owner = MUID_USB9; pSrc.bRam = (byte*)&usb_serial_str; wCount._word = *pSrc.bRam; usb_stat.ctrl_trf_mem = _RAM; // Set memory type } break; }//end switch }//end if }//end USBStdGetDscHandler Now all you have to do is modify the device descriptor in usbdsc.c to link string descriptor 0xFF to the serial number field: // .... 0x0000, // Device release number in BCD format 0x01, // Manufacturer string index 0x02, // Product string index 0xff, // Device serial number string index [*] 0x01 // Number of possible configurations }; Now program the device serial number into EEPROM locations 0x00 thru 0x08, and when your device enumerates it'll have a serial number. This basically allows settings belonging to the device to follow it no matter which port it's on. For instance, if you've set up a CDC device and set it to use COM5, when you move it to another USB port, Windows should (in theory) realise it's the same device and allocate COM5 to it. Well, that's the theory anyway. Next job is to cook up a small app to make building string descriptors a little easier. Enter a string, get a descriptor, that sort of thing. Entering strings as single-quote/char/single-quote/comma gets really old, really fast. -- Phil. | (\_/) This is Bunny. Copy and paste Bunny piclist@philpem.me.uk | (='.'=) into your signature to help him gain http://www.philpem.me.uk/ | (")_(") world domination. -- http://www.piclist.com PIC/SX FAQ & list archive View/change your membership options at http://mailman.mit.edu/mailman/listinfo/piclist