Page 1 of 1

alternative to usbSetInterrupt with HID

Posted: Mon Apr 20, 2009 4:29 am
by psc
Hi everyone,

I hope someone will take the time to enlight me. I want to avoid installation of a driver, so i am using HID (joystick). I am running V-USB on an atmega164p @ 20 mhz. My reportBuffer is 12 bytes. This is how i send the report:

Code: Select all

while (!usbInterruptIsReady()) {
   wdt_reset();
   usbPoll();
}
usbSetInterrupt(reportBuffer, 8);
while (!usbInterruptIsReady()) {
   wdt_reset();
   usbPoll();
}
usbSetInterrupt(secondreportBuffer, 8);


This takes 16ms to finish. It's a bit too long, i would like to achieve the lowest latency possible. Since bulk endpoints are not allowed for low speed devices and the fact that i am using the HID protocol and not libusb, what are my choices? I was reading about usbFunctionRead(), would it work and be faster?

Thank you very much for any information,
Patrick

Re: alternative to usbSetInterrupt with HID

Posted: Wed Apr 22, 2009 11:53 am
by christian
I doubt that you can make this faster with this descriptor size...

Re: alternative to usbSetInterrupt with HID

Posted: Wed Apr 22, 2009 4:42 pm
by psc
Finally i've decided to use Custom class device. I am not sure about the following code, but i am sharing it (maybe someone will tell me that it's not good). I can send 12 bytes in 8 ms and the speed of main() { } is not affected when i don't care about sending important value, avoiding this:

In order to keep the "device sends data spontaneously" semantics, you pass interrupt and bulk data by calling usbSetInterrupt() or usbSetInterrupt3() for endpoint 1 and 3 respectively. Up to 8 bytes may be passed in one call. The driver keeps the data in a buffer until it is requested by the host.


Code: Select all

volatile unsigned char sent = 0;

uchar usbFunctionSetup(uchar data[8])
{
   switch (data[1]) {      
      case CMD_POLL:   
         usbMsgPtr = usb_reply;
         sent = 1;
         return sizeof(usb_reply);
         break;
...

int main(void)
{
   wdt_enable(WDTO_1S);
   hardwareInit();
   usbInit();
   sei();

   uchar send = 0;

   while(1) {
      wdt_reset();
      usbPoll();

      //send important value
      if(bit_is_clear(PIND, 5)) {
         usb_reply[0] = 33;
         send = 1;
      }

      //send NOT important value
      usb_reply[1] = 66;

      //hack to avoid using usbInterruptIsReady()
      if(send == 1) {
         while(sent == 0) {
            wdt_reset();
            usbPoll();
            if(sent == 1) {
               break;
            }
         }
      }
      send = sent = 0;
   }
   return 0;
}

Re: alternative to usbSetInterrupt with HID

Posted: Fri Apr 24, 2009 11:12 am
by christian
I'm not sure I understand what you want to do. Do you send a CMD_POLL setup request after receipt of each interrupt packet from the host to acknowledge the receipt? And why should this be faster or better than using usbInterruptIsReady()?

Re: alternative to usbSetInterrupt with HID

Posted: Fri Apr 24, 2009 6:11 pm
by psc
Hi Christian,

I am trying to save times in communication between the firmware and the host.

The host application is sending CMD_POLL every 10 ms:

Code: Select all

nBytes = usb_control_msg(x->dev_handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, CMD_POLL, 0, 0, (char *)buffer, sizeof(buffer), 10);

The firmware reply like this:

Code: Select all

static uint8_t usb_reply[12];
uchar usbFunctionSetup(uchar data[8]) {
   switch (data[1]) {
      case CMD_POLL:   
            usbMsgPtr = usb_reply;
            return sizeof(usb_reply);

Using this method there's no way to be sure that an "important" usb_reply[] is sent, because the main() { } is running as fast as possible always updating usb_reply[]. A solution would be to use usbSetInterrupt() but only 8 bytes can be passed in one call, so i would need 2 calls. Instead by checking if an important usb_reply[] need to be send and checking if it's sent, it's possible to pass 12 bytes in 1 CMD_POLL.

Does it make any sense?
Cheers,
Patrick

Re: alternative to usbSetInterrupt with HID

Posted: Sat Apr 25, 2009 11:58 am
by christian
If you poll from the host, you don't need the interrupt endpoint at all. You can read chunks of 12 bytes at once (well, the driver splits it up into 8 byte chunks for you). And you could use a flag to indicate whether the current buffer has already been transferred.

However, I really doubt that polling is faster than the interrupt endpoint solution. It may be faster on a particular host/operating system combination, but not in general.

You may try to reduce the polling interval for the interrupt endpoint. Most operating systems accept intervals of less than 10 ms, I think.