General discussions about V-USB, our firmware-only implementation of a low speed USB device on Atmel's AVR microcontrollers
-
psc
- Rank 1
- Posts: 32
- Joined: Sat Nov 15, 2008 9:51 pm
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
- Posts: 1443
- Joined: Thu Nov 09, 2006 11:46 am
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
- Posts: 32
- Joined: Sat Nov 15, 2008 9:51 pm
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
- Posts: 1443
- Joined: Thu Nov 09, 2006 11:46 am
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
- Posts: 32
- Joined: Sat Nov 15, 2008 9:51 pm
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
- Posts: 1443
- Joined: Thu Nov 09, 2006 11:46 am
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.