@@ -598,6 +598,19 @@ uint8_t USBDeviceClass::armRecv(uint32_t ep)
598
598
return usbd.epBank0ByteCount (ep);
599
599
}
600
600
601
+ // Timeout for sends
602
+ #define TX_TIMEOUT_MS 70
603
+
604
+ static char LastTransmitTimedOut[7 ] = {
605
+ 0 ,
606
+ 0 ,
607
+ 0 ,
608
+ 0 ,
609
+ 0 ,
610
+ 0 ,
611
+ 0
612
+ };
613
+
601
614
// Blocking Send of data to an endpoint
602
615
uint32_t USBDeviceClass::send (uint32_t ep, const void *data, uint32_t len)
603
616
{
@@ -619,6 +632,29 @@ uint32_t USBDeviceClass::send(uint32_t ep, const void *data, uint32_t len)
619
632
// Flash area
620
633
while (len != 0 )
621
634
{
635
+ if (usbd.epBank1IsReady (ep)) {
636
+ // previous transfer is still not complete
637
+
638
+ // convert the timeout from microseconds to a number of times through
639
+ // the wait loop; it takes (roughly) 23 clock cycles per iteration.
640
+ uint32_t timeout = microsecondsToClockCycles (TX_TIMEOUT_MS * 1000 ) / 23 ;
641
+
642
+ // Wait for (previous) transfer to complete
643
+ // inspired by Paul Stoffregen's work on Teensy
644
+ while (!usbd.epBank1IsTransferComplete (ep)) {
645
+ if (LastTransmitTimedOut[ep] || timeout-- == 0 ) {
646
+ LastTransmitTimedOut[ep] = 1 ;
647
+
648
+ // set byte count to zero, so that ZLP is sent
649
+ // instead of stale data
650
+ usbd.epBank1SetByteCount (ep, 0 );
651
+ return -1 ;
652
+ }
653
+ }
654
+ }
655
+
656
+ LastTransmitTimedOut[ep] = 0 ;
657
+
622
658
if (len >= EPX_SIZE) {
623
659
length = EPX_SIZE - 1 ;
624
660
} else {
@@ -637,10 +673,6 @@ uint32_t USBDeviceClass::send(uint32_t ep, const void *data, uint32_t len)
637
673
// RAM buffer is full, we can send data (IN)
638
674
usbd.epBank1SetReady (ep);
639
675
640
- // Wait for transfer to complete
641
- while (!usbd.epBank1IsTransferComplete (ep)) {
642
- ; // need fire exit.
643
- }
644
676
written += length;
645
677
len -= length;
646
678
data = (char *)data + length;
0 commit comments