@@ -51,6 +51,7 @@ typedef struct {
5151 uint16_t total_len ;
5252 uint16_t max_size ;
5353 uint8_t interval ;
54+ uint8_t iso_retry ; // ISO retry counter
5455} xfer_ctl_t ;
5556
5657// This variable is modified from ISR context, so it must be protected by critical section
@@ -261,7 +262,13 @@ static void edpt_activate(uint8_t rhport, const tusb_desc_endpoint_t* p_endpoint
261262
262263 xfer_ctl_t * xfer = XFER_CTL_BASE (epnum , dir );
263264 xfer -> max_size = tu_edpt_packet_size (p_endpoint_desc );
264- xfer -> interval = p_endpoint_desc -> bInterval ;
265+
266+ const dwc2_dsts_t dsts = {.value = dwc2 -> dsts };
267+ if (dsts .enum_speed == DCFG_SPEED_HIGH ) {
268+ xfer -> interval = 1 << (p_endpoint_desc -> bInterval - 1 );
269+ } else {
270+ xfer -> interval = p_endpoint_desc -> bInterval ;
271+ }
265272
266273 // Endpoint control
267274 dwc2_depctl_t depctl = {.value = 0 };
@@ -400,7 +407,7 @@ static void edpt_schedule_packets(uint8_t rhport, const uint8_t epnum, const uin
400407 dwc2_depctl_t depctl = {.value = dep -> ctl };
401408 depctl .clear_nak = 1 ;
402409 depctl .enable = 1 ;
403- if (depctl .type == DEPCTL_EPTYPE_ISOCHRONOUS && xfer -> interval == 1 ) {
410+ if (depctl .type == DEPCTL_EPTYPE_ISOCHRONOUS ) {
404411 const dwc2_dsts_t dsts = {.value = dwc2 -> dsts };
405412 const uint32_t odd_now = dsts .frame_number & 1u ;
406413 if (odd_now != 0 ) {
@@ -643,6 +650,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t to
643650 xfer -> buffer = buffer ;
644651 xfer -> ff = NULL ;
645652 xfer -> total_len = total_bytes ;
653+ xfer -> iso_retry = xfer -> interval ; // Reset ISO retry counter to interval value
646654
647655 // EP0 can only handle one packet
648656 if (epnum == 0 ) {
@@ -680,6 +688,7 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t* ff, uint16_t
680688 xfer -> buffer = NULL ;
681689 xfer -> ff = ff ;
682690 xfer -> total_len = total_bytes ;
691+ xfer -> iso_retry = xfer -> interval ; // Reset ISO retry counter to interval value
683692
684693 // Schedule packets to be sent within interrupt
685694 // TODO xfer fifo may only available for slave mode
@@ -782,7 +791,7 @@ static void handle_bus_reset(uint8_t rhport) {
782791 dwc2 -> epout [0 ].doeptsiz |= (3 << DOEPTSIZ_STUPCNT_Pos );
783792 }
784793
785- dwc2 -> gintmsk |= GINTMSK_OEPINT | GINTMSK_IEPINT ;
794+ dwc2 -> gintmsk |= GINTMSK_OEPINT | GINTMSK_IEPINT | GINTMSK_IISOIXFRM ;
786795}
787796
788797static void handle_enum_done (uint8_t rhport ) {
@@ -1057,6 +1066,43 @@ static void handle_ep_irq(uint8_t rhport, uint8_t dir) {
10571066 }
10581067}
10591068
1069+ static void handle_incomplete_iso_in (uint8_t rhport ) {
1070+ dwc2_regs_t * dwc2 = DWC2_REG (rhport );
1071+ const dwc2_dsts_t dsts = {.value = dwc2 -> dsts };
1072+ const uint32_t odd_now = dsts .frame_number & 1u ;
1073+
1074+ // Loop over all IN endpoints
1075+ const uint8_t ep_count = dwc2_ep_count (dwc2 );
1076+ for (uint8_t epnum = 0 ; epnum < ep_count ; epnum ++ ) {
1077+ dwc2_dep_t * epin = & dwc2 -> epin [epnum ];
1078+ dwc2_depctl_t depctl = {.value = epin -> diepctl };
1079+ // Read DSTS and DIEPCTLn for all isochronous endpoints. If the current EP is enabled and the read value of
1080+ // DSTS.SOFFN is the targeted uframe number for this EP, then this EP has an incomplete transfer.
1081+ if (depctl .enable && depctl .type == DEPCTL_EPTYPE_ISOCHRONOUS && depctl .dpid_iso_odd == odd_now ) {
1082+ xfer_ctl_t * xfer = XFER_CTL_BASE (epnum , TUSB_DIR_IN );
1083+ if (xfer -> iso_retry > 0 ) {
1084+ xfer -> iso_retry -- ;
1085+ // Restart ISO transfe: re-write TSIZ and CTL
1086+ dwc2_ep_tsize_t deptsiz = {.value = 0 };
1087+ deptsiz .xfer_size = xfer -> total_len ;
1088+ deptsiz .packet_count = tu_div_ceil (xfer -> total_len , xfer -> max_size );
1089+ epin -> tsiz = deptsiz .value ;
1090+
1091+ if (odd_now ) {
1092+ depctl .set_data0_iso_even = 1 ;
1093+ } else {
1094+ depctl .set_data1_iso_odd = 1 ;
1095+ }
1096+ epin -> diepctl = depctl .value ;
1097+ } else {
1098+ // too many retries, give up
1099+ edpt_disable (rhport , epnum | TUSB_DIR_IN_MASK , false);
1100+ dcd_event_xfer_complete (rhport , epnum | TUSB_DIR_IN_MASK , 0 , XFER_RESULT_FAILED , true);
1101+ }
1102+ }
1103+ }
1104+ }
1105+
10601106/* Interrupt Hierarchy
10611107 DIEPINT DIEPINT
10621108 \ /
@@ -1156,6 +1202,12 @@ void dcd_int_handler(uint8_t rhport) {
11561202 // IEPINT bit read-only, clear using DIEPINTn
11571203 handle_ep_irq (rhport , TUSB_DIR_IN );
11581204 }
1205+
1206+ // Incomplete isochronous IN transfer interrupt handling.
1207+ if (gintsts & GINTSTS_IISOIXFR ) {
1208+ dwc2 -> gintsts = GINTSTS_IISOIXFR ;
1209+ handle_incomplete_iso_in (rhport );
1210+ }
11591211}
11601212
11611213#if CFG_TUD_TEST_MODE
0 commit comments