Wednesday, September 10, 2008

PIC USB Serial Number

The Communications device class (CDC) in the Microchip USB framework does not set iSerialNumber, so what ends up happening is that every time you plug in the device it gets a random COM port assigned to it. These code modifications allow you to set iSerialNumber from EEProm which will allow the device to come up as the same COM Port on both linux and windows. This also has the advantage that it allows the serial number to be set during testing via usb instead of compile time, which is handy if you are making a bunch of boards.


usb_descriptors.c

//Serial Number string descriptor
ram struct{BYTE bLength;BYTE bDscType;WORD string[8];}sd003={
sizeof(sd003),USB_DESCRIPTOR_STRING,
{'d','e','a','d','b','e','e','f'}
};

//Array of string descriptors
BYTE *USB_SD_Ptr[]=
{
(BYTE *)&sd000,
(BYTE *)&sd001,
(BYTE *)&sd002,
(BYTE *)&sd003
};


main.c

This is where the values are loaded from the EEProm.

void InitializeSystem(void)
{
struct dscinfo {
BYTE bLength;
BYTE bDscType;
WORD string[8];
};
struct dscinfo *ptr;
int i;
ptr = (struct dscinfo *)USB_SD_Ptr[3];
EECON1bits.CFGS = 0;
EECON1bits.EEPGD = 0;
for (i=0;i<8;i++) {
EEADR = 0x00 + i;
EECON1bits.RD = 1;
ptr->string[i] = EEDATA;
}

...


usb_device.c

void USBStdGetDscHandler(void)
{
if(SetupPkt.bmRequestType == 0x80)
{
inPipes[0].info.Val = USB_INPIPES_ROM | USB_INPIPES_BUSY | USB_INPIPES_INCLUDE_ZERO;

switch(SetupPkt.bDescriptorType)
{
case USB_DESCRIPTOR_DEVICE:
#if !defined(USB_USER_DEVICE_DESCRIPTOR)
inPipes[0].pSrc.bRom = (ROM BYTE*)&device_dsc;
#else
inPipes[0].pSrc.bRom = (ROM BYTE*)USB_USER_DEVICE_DESCRIPTOR;
#endif
inPipes[0].wCount.Val = sizeof(device_dsc);
break;
case USB_DESCRIPTOR_CONFIGURATION:
#if !defined(USB_USER_CONFIG_DESCRIPTOR)
inPipes[0].pSrc.bRom = *(USB_CD_Ptr+SetupPkt.bDscIndex);
#else
inPipes[0].pSrc.bRom = *(USB_USER_CONFIG_DESCRIPTOR+SetupPkt.bDscIndex);
#endif
inPipes[0].wCount.Val = *(inPipes[0].pSrc.wRom+1);                // Set data count
break;
case USB_DESCRIPTOR_STRING:
inPipes[0].info.Val = USB_INPIPES_RAM | USB_INPIPES_BUSY | USB_INPIPES_INCLUDE_ZERO;
inPipes[0].pSrc.bRam = *(USB_SD_Ptr+SetupPkt.bDscIndex);
inPipes[0].wCount.Val = *inPipes[0].pSrc.bRam;                    // Set data count
break;
default:
inPipes[0].info.Val = 0;
break;
}//end switch
}//end if
}//end USBStdGetDscHandler


usb_device.h
//Array of string descriptors
extern BYTE *USB_SD_Ptr[];

No comments: