v-usb not really good for control transfers after all.

General discussions about V-USB, our firmware-only implementation of a low speed USB device on Atmel's AVR microcontrollers
Post Reply
ulao
Rank 4
Rank 4
Posts: 481
Joined: Mon Aug 25, 2008 8:45 pm

v-usb not really good for control transfers after all.

Post by ulao » Fri Nov 10, 2017 5:59 pm

If anyone has looked in to the v-usb on the wire you will learn a few things...

sending the NACK consumes all the CPU time.and this can go on for quite a while. The host only stops sending IN packets right before the end of the frame, to avoid colliding with the 1 ms keep alive pulse. This finally leaves enough time for V-USB to process the data and prepare the TX buffer. This is extremely wasteful, since less than 10% of the USB bus traffic is actively transferring data and almost 90% of the CPU time is spent on “appeasing” the host. In the worst case, only one valid transmission can be processed per frame (1 ms). Since a low-speed USB data packet carries a maximum of 8 bytes, this limits the theoretical throughput to 8000 bytes/s and much less in practice due to additional protocol overhead. Although extremely ugly, it does work for V-USB.

this is not my original wording, complements to TIm for this. Though I see this is all very true. This does work out well if you have nothing you intend to do with the chip in any depth. For example, try running 300 us of ASM time sensitive code (were you need to cli) It simply will not work. If you try to place that ASM in the 1 ms window and not disable interrupts, the control transfer will run it over. Being they take seconds to complete, this likelihood goes way up.

Breaching the limits of v-usb... So in-part with tims research I devises a method I think is going to work.

pseudo code.

main
{
.
.

usbDisableAllRequests();//force NAK
EIMSK &= ~(1 << INT0);//disable int
do_ASM_sensitive_Code
EIMSK |= (1 << INT0); //enable int
usbEnableAllRequests();//free NAK condition.
.
.
}


asmcommon.lst change needed
sofError:
POP_RETI ;macro call
SBIC EIMSK, 1 ;if not set branch (int0)
RETI;was set
RET;was not


Idea here is that you can tell the driver to return NAK. This is ok but not if interrupts are disabled. So we change reti to ret in the SOF and allow it to constantly send NAK if the int. is cleared. This change will not effect any v-usb operation. It is only done if you disable the interrupt (could change to accept other pins) and in this case, this is best.


This is a work in progress... Thoughts

ulao
Rank 4
Rank 4
Posts: 481
Joined: Mon Aug 25, 2008 8:45 pm

Re: v-usb not really good for control transfers after all.

Post by ulao » Fri Nov 10, 2017 6:23 pm

One small addition. It may be wise to check for the interrupt arrest before enabling.

usbPoll(); //issue at least one for the check below
if (USB_INTR_PENDING & (1<<USB_INTR_PENDING_BIT)) // Usbpoll() collided with data packet
{
uint8_t ctr;

// loop takes 5 cycles
asm volatile(
" ldi %0,%1 \n\t"
"loop%=: sbis %2,%3 \n\t"
" ldi %0,%1 \n\t"
" subi %0,1 \n\t"
" brne loop%= \n\t"
: "=&d" (ctr)
: "M" ((uint8_t)(8.8f*(F_CPU/1.0e6f)/5.0f+0.5)), "I" (_SFR_IO_ADDR(USBIN)), "M" (USB_CFG_DMINUS_BIT)
);
USB_INTR_PENDING = 1<<USB_INTR_PENDING_BIT;
}

ulao
Rank 4
Rank 4
Posts: 481
Joined: Mon Aug 25, 2008 8:45 pm

Re: v-usb not really good for control transfers after all.

Post by ulao » Tue Nov 14, 2017 6:36 pm

Idea will not work because this function is only called based on the interrupt. I'd have to step back further. Unsure where to look at the moment, abandoning this idea for now.

ulao
Rank 4
Rank 4
Posts: 481
Joined: Mon Aug 25, 2008 8:45 pm

Re: v-usb not really good for control transfers after all.

Post by ulao » Wed Aug 01, 2018 1:55 pm

I was able to find a solution.

In the asm includes for your chip just add a flag. I used 0 for flag set, 1 for flag not set.

waitForJ:
clr r3;
sts _Control_Data, r3
//sbi PORTB, 2; ;debug
//cbi PORTB, 2; ;debug


debug it to see how it works. It constantly sets a flag when any data goes over the usb bus.

to use it I do this.

(make sure to run this code after the usb poll so things are lined up right).
_Control_Data=_Control_Data_not_set;
curGamepad->update();
if (_Control_Data == _Control_Data_set) _DoNotReport=1;


So if data was being sent when my code was running I skip reporting it to the host.


As I learned there is no free slots during setup packets. They can come at any time and can NACK for a long time. You must allow then to occur or the host gets angry. So let it happen and check after. At a spam rate of 2 ms apart, I sampled 10 updates skipped out of 100. That's not too bad... The only real gotcha here is that if you need to do anything longer then 300us it will not happen if the host needs to send any control transfers. I'd suggest one of two options. 1) scheduled a point where the host takes a break. I.E host sends report 1,2,3,4 then waits for some period of time. 2) make a get DND report to check when the client needs to do some work. This is no much good for timely work.

ulao
Rank 4
Rank 4
Posts: 481
Joined: Mon Aug 25, 2008 8:45 pm

Re: v-usb not really good for control transfers after all.

Post by ulao » Mon Aug 20, 2018 7:17 pm

Just want to add that the solution is no good once you have multiple devices. The flag is set off for any traffic. I guess I'd have to wait for the correct matching address but it may be too late at that point.

Post Reply