From 8d18d6077bb1100e0f5ac5b3a11b807751d93149 Mon Sep 17 00:00:00 2001 From: hathach Date: Sun, 26 Apr 2020 22:14:59 +0700 Subject: [PATCH] turn off TX FIFO Empty for EPIN if all bytes are written fix dcd synopsys issue with usbnet #289 --- src/portable/st/synopsys/dcd_synopsys.c | 60 +++++++++++++++---------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/src/portable/st/synopsys/dcd_synopsys.c b/src/portable/st/synopsys/dcd_synopsys.c index 9c167222..a86d0757 100644 --- a/src/portable/st/synopsys/dcd_synopsys.c +++ b/src/portable/st/synopsys/dcd_synopsys.c @@ -291,9 +291,10 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) if(dir == TUSB_DIR_OUT) { - out_ep[epnum].DOEPCTL |= (1 << USB_OTG_DOEPCTL_USBAEP_Pos) | \ - desc_edpt->bmAttributes.xfer << USB_OTG_DOEPCTL_EPTYP_Pos | \ - desc_edpt->wMaxPacketSize.size << USB_OTG_DOEPCTL_MPSIZ_Pos; + out_ep[epnum].DOEPCTL |= (1 << USB_OTG_DOEPCTL_USBAEP_Pos) | + (desc_edpt->bmAttributes.xfer << USB_OTG_DOEPCTL_EPTYP_Pos) | + (desc_edpt->wMaxPacketSize.size << USB_OTG_DOEPCTL_MPSIZ_Pos); + dev->DAINTMSK |= (1 << (USB_OTG_DAINTMSK_OEPM_Pos + epnum)); } else @@ -321,11 +322,12 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) // - Offset: GRXFSIZ + 16 + Size*(epnum-1) // - IN EP 1 gets FIFO 1, IN EP "n" gets FIFO "n". - in_ep[epnum].DIEPCTL |= (1 << USB_OTG_DIEPCTL_USBAEP_Pos) | \ - epnum << USB_OTG_DIEPCTL_TXFNUM_Pos | \ - desc_edpt->bmAttributes.xfer << USB_OTG_DIEPCTL_EPTYP_Pos | \ - (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? USB_OTG_DOEPCTL_SD0PID_SEVNFRM : 0) | \ - desc_edpt->wMaxPacketSize.size << USB_OTG_DIEPCTL_MPSIZ_Pos; + in_ep[epnum].DIEPCTL |= (1 << USB_OTG_DIEPCTL_USBAEP_Pos) | + (epnum << USB_OTG_DIEPCTL_TXFNUM_Pos) | + (desc_edpt->bmAttributes.xfer << USB_OTG_DIEPCTL_EPTYP_Pos) | + (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? USB_OTG_DOEPCTL_SD0PID_SEVNFRM : 0) | + (desc_edpt->wMaxPacketSize.size << USB_OTG_DIEPCTL_MPSIZ_Pos); + dev->DAINTMSK |= (1 << (USB_OTG_DAINTMSK_IEPM_Pos + epnum)); // Both TXFD and TXSA are in unit of 32-bit words. @@ -352,9 +354,9 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t uint8_t const dir = tu_edpt_dir(ep_addr); xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir); - xfer->buffer = buffer; - xfer->total_len = total_bytes; - xfer->queued_len = 0; + xfer->buffer = buffer; + xfer->total_len = total_bytes; + xfer->queued_len = 0; xfer->short_packet = false; uint16_t num_packets = (total_bytes / xfer->max_size); @@ -365,21 +367,23 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t num_packets++; } - // IN and OUT endpoint xfers are interrupt-driven, we just schedule them - // here. + // IN and OUT endpoint xfers are interrupt-driven, we just schedule them here. if(dir == TUSB_DIR_IN) { // A full IN transfer (multiple packets, possibly) triggers XFRC. - in_ep[epnum].DIEPTSIZ = (num_packets << USB_OTG_DIEPTSIZ_PKTCNT_Pos) | \ - ((total_bytes & USB_OTG_DIEPTSIZ_XFRSIZ_Msk) << USB_OTG_DIEPTSIZ_XFRSIZ_Pos); + in_ep[epnum].DIEPTSIZ = (num_packets << USB_OTG_DIEPTSIZ_PKTCNT_Pos) | + ((total_bytes & USB_OTG_DIEPTSIZ_XFRSIZ_Msk) << USB_OTG_DIEPTSIZ_XFRSIZ_Pos); + in_ep[epnum].DIEPCTL |= USB_OTG_DIEPCTL_EPENA | USB_OTG_DIEPCTL_CNAK; + // Enable fifo empty interrupt only if there are something to put in the fifo. if(total_bytes != 0) { dev->DIEPEMPMSK |= (1 << epnum); } } else { // Each complete packet for OUT xfers triggers XFRC. - out_ep[epnum].DOEPTSIZ |= (1 << USB_OTG_DOEPTSIZ_PKTCNT_Pos) | \ - ((xfer->max_size & USB_OTG_DOEPTSIZ_XFRSIZ_Msk) << USB_OTG_DOEPTSIZ_XFRSIZ_Pos); + out_ep[epnum].DOEPTSIZ |= (1 << USB_OTG_DOEPTSIZ_PKTCNT_Pos) | + ((xfer->max_size & USB_OTG_DOEPTSIZ_XFRSIZ_Msk) << USB_OTG_DOEPTSIZ_XFRSIZ_Pos); + out_ep[epnum].DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK; } @@ -535,6 +539,7 @@ static void receive_packet(xfer_ctl_t * xfer, /* USB_OTG_OUTEndpointTypeDef * ou xfer->short_packet = (xfer_size < xfer->max_size); } +// Write a data packet to EPIN FIFO static void transmit_packet(xfer_ctl_t * xfer, USB_OTG_INEndpointTypeDef * in_ep, uint8_t fifo_num) { usb_fifo_t tx_fifo = FIFO_BASE(fifo_num); @@ -658,21 +663,30 @@ static void handle_epout_ints(USB_OTG_DeviceTypeDef * dev, USB_OTG_OUTEndpointTy static void handle_epin_ints(USB_OTG_DeviceTypeDef * dev, USB_OTG_INEndpointTypeDef * in_ep) { // DAINT for a given EP clears when DIEPINTx is cleared. // IEPINT will be cleared when DAINT's out bits are cleared. - for(uint8_t n = 0; n < EP_MAX; n++) { - xfer_ctl_t * xfer = XFER_CTL_BASE(n, TUSB_DIR_IN); + for ( uint8_t n = 0; n < EP_MAX; n++ ) + { + xfer_ctl_t *xfer = XFER_CTL_BASE(n, TUSB_DIR_IN); - if(dev->DAINT & (1 << (USB_OTG_DAINT_IEPINT_Pos + n))) { + if ( dev->DAINT & (1 << (USB_OTG_DAINT_IEPINT_Pos + n)) ) + { // IN XFER complete (entire xfer). - if(in_ep[n].DIEPINT & USB_OTG_DIEPINT_XFRC) { + if ( in_ep[n].DIEPINT & USB_OTG_DIEPINT_XFRC ) + { in_ep[n].DIEPINT = USB_OTG_DIEPINT_XFRC; - dev->DIEPEMPMSK &= ~(1 << n); // Turn off TXFE b/c xfer inactive. dcd_event_xfer_complete(0, n | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true); } // XFER FIFO empty - if(in_ep[n].DIEPINT & USB_OTG_DIEPINT_TXFE) { + if ( in_ep[n].DIEPINT & USB_OTG_DIEPINT_TXFE ) + { in_ep[n].DIEPINT = USB_OTG_DIEPINT_TXFE; transmit_packet(xfer, &in_ep[n], n); + + // Turn off TXFE if all bytes are written. + if (xfer->queued_len == xfer->total_len) + { + dev->DIEPEMPMSK &= ~(1 << n); + } } } }