alternative to usbSetInterrupt with HID

General discussions about V-USB, our firmware-only implementation of a low speed USB device on Atmel's AVR microcontrollers
Post Reply
psc
Rank 1
Rank 1
Posts: 32
Joined: Sat Nov 15, 2008 9:51 pm

alternative to usbSetInterrupt with HID

Post by psc » Mon Apr 20, 2009 4:29 am

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

christian
Objective Development
Objective Development
Posts: 1443
Joined: Thu Nov 09, 2006 11:46 am

Re: alternative to usbSetInterrupt with HID

Post by christian » Wed Apr 22, 2009 11:53 am

I doubt that you can make this faster with this descriptor size...

psc
Rank 1
Rank 1
Posts: 32
Joined: Sat Nov 15, 2008 9:51 pm

Re: alternative to usbSetInterrupt with HID

Post by psc » Wed Apr 22, 2009 4:42 pm

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;
}

christian
Objective Development
Objective Development
Posts: 1443
Joined: Thu Nov 09, 2006 11:46 am

Re: alternative to usbSetInterrupt with HID

Post by christian » Fri Apr 24, 2009 11:12 am

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()?

psc
Rank 1
Rank 1
Posts: 32
Joined: Sat Nov 15, 2008 9:51 pm

Re: alternative to usbSetInterrupt with HID

Post by psc » Fri Apr 24, 2009 6:11 pm

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

christian
Objective Development
Objective Development
Posts: 1443
Joined: Thu Nov 09, 2006 11:46 am

Re: alternative to usbSetInterrupt with HID

Post by christian » Sat Apr 25, 2009 11:58 am

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.

Post Reply