From aa6bb7aba69bf6820fb8b2c013eff37378a2809b Mon Sep 17 00:00:00 2001 From: cpldcpu Date: Sun, 5 Jan 2014 21:50:29 +0100 Subject: firmware: fix a timing bug in the usb driver SETUP/DATA timed out under Linux --- firmware/usbdrv/asmcommon.inc | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/firmware/usbdrv/asmcommon.inc b/firmware/usbdrv/asmcommon.inc index b7efadb..2551bab 100644 --- a/firmware/usbdrv/asmcommon.inc +++ b/firmware/usbdrv/asmcommon.inc @@ -82,9 +82,41 @@ se0: ; rjmp handleSetupOrOut ; fallthrough ;Setup and Out are followed by a data packet two bit times (16 cycles) after -;the end of SE0. The sync code allows up to 40 cycles delay from the start of -;the sync pattern until the first bit is sampled. That's a total of 56 cycles. +;the end of SE0. The sync code allows up to 40 cycles delay (5 bit times) from +;the start of the sync pattern until the first bit is sampled. That's a total of 56 cycles. + +; TB 2014-01-04 +; USB1.1 spec defines a minimum of two bit times and a maximum of 6.5 bit times +; between Setup/Out and Data. We have to make sure we also cover the upper end +; of the spec on a 16Mhz device. +; +; Bit times µs cycles @12Mhz cycles @16 Mhz +; minimum 2 1.33 16 21 +; maximum 6.5 4.33 52 69 +; meas. Win7 3 2.04 24 32 +; meas. Linux 5 3.5 40 53 +; +; Currently it is only checked at cycle 46..49 if another interrupt occured. This is +; too early for 16 Mhz and the interrupt will not catch the data packet if it is later +; than 4 bit times. +; +; fix: Introduce additional delay with timeout for the 16 und 16.5 Mhz version. +; The 12 and 12.8 Mhz versions are still fine without as the maximum delay is less than 46 cycles. +; +; The total time until the next packet may not exceed 2 (min) +5 (sync tolerance) bit times +; = 75 cycles @16Mhz to +; The minimum time to cover max. timeout is 6.5 bit times = 70 cycles @16 Mhz +; +; Additional delay = 70-46=24 cycles. -> going to 21 cycles to be safe. + handleSetupOrOut: ;[32] +; Delay, see above +#if (F_CPU >= 16000000) + ldi YL, 7 ; +USBdelay: + subi YL, 1 + brne USBdelay +#endif #if USB_CFG_IMPLEMENT_FN_WRITEOUT /* if we have data for endpoint != 0, set usbCurrentTok to address */ andi x3, 0xf ;[32] breq storeTokenAndReturn ;[33] @@ -94,6 +126,7 @@ storeTokenAndReturn: sts usbCurrentTok, token;[35] doReturn: POP_STANDARD ;[37] 12...16 cycles + USB_LOAD_PENDING(YL) ;[49] sbrc YL, USB_INTR_PENDING_BIT;[50] check whether data is already arriving rjmp waitForJ ;[51] save the pops and pushes -- a new interrupt is already pending -- cgit v1.2.3