Hi all, I have been working with a usb device for a few years though it is a bit bang implementation (v-usb), thus a bit limited. I do not however feel the firmware only driver is my issue.
I wanted to add a send method for an LCD I have on a game controller. All aspects of the game controller work fine including filling the LCD screen with progmem data. My attempt to do this was with the usb.dll or a "usb-libusb" from a older ddk lib. The code to send was quite simple.
usbSetReport(dev, USB_HID_REPORT_TYPE_FEATURE,somedata, sizeof(somedata)))
I found I had to send my data in two chucks because there is a 128 byte max. From the best I can tell and from sniffing the USB data, this is a control transfer and it does not seem to be using an interrupt. Here is my descriptor for those IDs.
0x06, 0x00, 0xff, // USAGE_PAGE (Generic Desktop)
0x09, 0x01, // USAGE (Vendor Usage 1)
0xa1, 0x01, // COLLECTION (Application)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
0x75, 0x08, // REPORT_SIZE (8)
0x85, 0x11, // REPORT_ID (17)
0x95, 0x06, // REPORT_COUNT (6)
0x09, 0x00, // USAGE (Undefined)
0xb2, 0x02, 0x01, // FEATURE (Data,Var,Abs,Buf)
0x85, 0x12, // REPORT_ID (18)
0x95, 0x83, // REPORT_COUNT (131)
0x09, 0x00, // USAGE (Undefined)
0xb2, 0x02, 0x01, // FEATURE (Data,Var,Abs,Buf)
0xc0 // END_COLLECTION
Now as far as v-usb goes, I need to use long transfers and it populates the data in 8 byte chucks. The LCD does fill up but never the same and always in a block un-arranged pattern. At times, less then %5 it fills up the entire image. So some of that data is getting out of wack.
this is the screen shot of the usbLyzer data. See the red (stalls), sorry I had the wrong controller highlighted at the time of the snap shot.
From what I know the stall indicate the following.
When a device receives a request that is undefined, is inappropriate given the current setting or state of the device, or uses values that are inappropriate for the particular request, then a Request Error exists. The device handles a Request Error by returning a STALL PID to the next DATA or STATUS stage, preferably at the next DATA stage transaction.
Since it's random and not every send that errors,
"a request that is undefined" and
"values that are inappropriate for the particular request" must not be the issue, thus my error must be
"inappropriate given the current setting or state of the device". So I believe its how I'm using the v-usb driver. They do have a crc option that gets enabled in their usbconfig but it does not help. I did notice it took much longer to attempt to fill the screen. So I do not think crc is my issue. As far as I can tell, it seem like the packets that get delivered are intact, just not all of them are sent (maybe rejected).
So a bit about my code.
my usbFunctionSetup passes on all USBRQ_HID_SET_REPORT's to my usbFunctionWrite
if(rq->bRequest == USBRQ_HID_SET_REPORT) return USB_NO_MSG;
then I handle my report 18 (set) like this
if ( data[0] == 18)
{
return handleSendData ( data );
}
char handleSendData(uchar *data)
{
//0 hold report buffer
//these go in transfers...
if (data[2]== 0x24)
{
//dc lcd
bytesRemaining = 116;//120 + this byte.
needMoreThen8Data=0x24;//set flag
currentAddress = 4;//can only load 4 in here.
for (char i=0;i<4;i++) lcd_data[i] = data[i+4];
return 0;
}
else if (data[2]== 0x25)
{
//dc lcd two
bytesRemaining = 68;//71 remaing
needMoreThen8Data=0x25;//set flag (use same flag)
currentAddress = 123;//can only load 4 in here.
for (char i=119;i<123;i++) lcd_data[i] = data[i+4];
return 0;
}
return 1;
}
As I mentioned I need to do 128 then the remainder. This code is just for the first 4 bytes because of the header info. So the driver passes the remainder payload back to the usbFunctionWrite. so in that function I also have
if(needMoreThen8Data)
{
if(bytesRemaining == 0) {needMoreThen8Data=0;return 1;}//finished
if(len > bytesRemaining) len = bytesRemaining;
if(needMoreThen8Data==0x12)
for (char i=currentAddress;i<currentAddress+8;i++)
{mapper[i] = data[j]; j++;}
if(needMoreThen8Data==0x24 || needMoreThen8Data==0x25)
{
for (unsigned char i=currentAddress;i<currentAddress+8;i++)
{lcd_data[i] = data[j]; j++;}
//if (needMoreThen8Data==0x25)
_lcdNeedsWrite = 1;
}
currentAddress += len;
bytesRemaining -= len;
if(bytesRemaining == 0) {needMoreThen8Data=0;return 1;}//finished
return 0;
}
One thing worth a mention here is that the entire time this is going on my normal usb poll operation runs. So far I have not attached this to the problem. It does not seem to be the culprit. There is no problem skipping this during a transfer but I can not stop this for more the 8 ms as the USB will die on me. My gamepad data payload is more the 8 bytes so I do it in two pulls as v-usb is only 1.1
while (!usbInterruptIsReady()) usbPoll(); usbSetInterrupt( reportBuffer, 8);
cli();
if (!_autoPause) curGamepad->doWork();//always less then 8 ms
sei();
while (!usbInterruptIsReady()) usbPoll(); usbSetInterrupt((void *)&reportBuffer + 8, 8);//2 extra are for ps3 see descriptor notes
I have tried omitting all of this and the problem remains but felt I should mention it.
Also here is how I set up my pipes.
9, /* sizeof(usbDescriptorConfiguration): length of descriptor in bytes */
USBDESCR_CONFIG, /* descriptor type */
18 + 7 * USB_CFG_HAVE_INTRIN_ENDPOINT + /*7 * USB_CFG_HAVE_INTRIN_ENDPOINT3*/ + 7 + 9, 0,
/* total length of data returned (including inlined descriptors) */
1, /* number of interfaces in this configuration */
1, /* index of this configuration */
0, /* configuration name string index */
USB_CFG_IS_SELF_POWERED, /* attributes */
USB_CFG_MAX_BUS_POWER/2, /* max USB current in 2mA units */
/* interface descriptor follows inline: */
9, /* sizeof(usbDescrInterface): length of descriptor in bytes */
USBDESCR_INTERFACE, /* descriptor type */
0, /* index of this interface */
0, /* alternate setting for this interface */
1 + USB_CFG_HAVE_INTRIN_ENDPOINT ,//+ USB_CFG_HAVE_INTRIN_ENDPOINT3, /* endpoints excl 0: number of endpoint descriptors to follow */
USB_CFG_INTERFACE_CLASS,
USB_CFG_INTERFACE_SUBCLASS,
USB_CFG_INTERFACE_PROTOCOL,
0, /* string index for interface */
9, /* sizeof(usbDescrHID): length of descriptor in bytes */
USBDESCR_HID, /* descriptor type: HID */
0x10, 0x01, /* BCD representation of HID version */
0x00, /* target country code */
0x01, /* number of HID Report (or other HID class) Descriptor infos to follow */
0x22, /* descriptor type: report */
USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH, 5, /* total length of report descriptor *///
//#endif
#if USB_CFG_HAVE_INTRIN_ENDPOINT /* endpoint descriptor for endpoint 1 */
7, /* sizeof(usbDescrEndpoint) */
USBDESCR_ENDPOINT, /* descriptor type = endpoint */
0x81, // bulk IN endpoint number 1
0x03, /* attrib: Interrupt endpoint */
8, 0, /* maximum packet size */
0x08, /* in ms*/
//the output.
7, // sizeof(usbDescrEndpoint)
5, // descriptor type = endpoint
0x01, // out endpoint number 2
0x03, // attrib: Interrupt endpoint
8, 0, // maximum packet size
0x08, // in ms
#endif
I have asked for help over at avr-freaks, the v-usb board, and my good old friends at microchip. No one seems to be able to help. I'm sure its the way I'm using v-usb but the project is about 18 files and the main alone is huge. If there is something more I can add let me know. I welcome any ideas at all, I don't play expect, I'm human and I make many mistakes. They are how I learn.