Redesign of Synopsys device transmission
Changes: - checking if tx buffer empty interrupt is masked - process more than one packet in isr - mask tx buffer empty just after all bytes were written - use of transmit_fifo_packet instead of transmit_packet
This commit is contained in:
		@@ -195,7 +195,7 @@ void dcd_init (uint8_t rhport)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  // Programming model begins in the last section of the chapter on the USB
 | 
					  // Programming model begins in the last section of the chapter on the USB
 | 
				
			||||||
  // peripheral in each Reference Manual.
 | 
					  // peripheral in each Reference Manual.
 | 
				
			||||||
  USB_OTG_FS->GAHBCFG |= USB_OTG_GAHBCFG_TXFELVL | USB_OTG_GAHBCFG_GINT;
 | 
					  USB_OTG_FS->GAHBCFG |= USB_OTG_GAHBCFG_GINT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // No HNP/SRP (no OTG support), program timeout later, turnaround
 | 
					  // No HNP/SRP (no OTG support), program timeout later, turnaround
 | 
				
			||||||
  // programmed for 32+ MHz.
 | 
					  // programmed for 32+ MHz.
 | 
				
			||||||
@@ -374,7 +374,6 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
 | 
				
			|||||||
                            ((total_bytes & USB_OTG_DIEPTSIZ_XFRSIZ_Msk) << USB_OTG_DIEPTSIZ_XFRSIZ_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;
 | 
					    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.
 | 
					    // Enable fifo empty interrupt only if there are something to put in the fifo.
 | 
				
			||||||
    if(total_bytes != 0) {
 | 
					    if(total_bytes != 0) {
 | 
				
			||||||
      dev->DIEPEMPMSK |= (1 << epnum);
 | 
					      dev->DIEPEMPMSK |= (1 << epnum);
 | 
				
			||||||
@@ -539,46 +538,27 @@ static void receive_packet(xfer_ctl_t * xfer, /* USB_OTG_OUTEndpointTypeDef * ou
 | 
				
			|||||||
  xfer->short_packet = (xfer_size < xfer->max_size);
 | 
					  xfer->short_packet = (xfer_size < xfer->max_size);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Write a data packet to EPIN FIFO
 | 
					// Write a single data packet to EPIN FIFO
 | 
				
			||||||
static void transmit_packet(xfer_ctl_t * xfer, USB_OTG_INEndpointTypeDef * in_ep, uint8_t fifo_num) {
 | 
					static void transmit_fifo_packet(uint8_t fifo_num, uint8_t * src, uint16_t len){
 | 
				
			||||||
  usb_fifo_t tx_fifo = FIFO_BASE(fifo_num);
 | 
						usb_fifo_t tx_fifo = FIFO_BASE(fifo_num);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  uint16_t remaining = (in_ep->DIEPTSIZ & USB_OTG_DIEPTSIZ_XFRSIZ_Msk) >> USB_OTG_DIEPTSIZ_XFRSIZ_Pos;
 | 
						// Pushing full available 32 bit words to fifo
 | 
				
			||||||
  xfer->queued_len = xfer->total_len - remaining;
 | 
						uint16_t full_words = len >> 2;
 | 
				
			||||||
 | 
						for(uint16_t i = 0; i < full_words; i++){
 | 
				
			||||||
 | 
							*tx_fifo = (src[3] << 24) | (src[2] << 16) | (src[1] << 8) | src[0];
 | 
				
			||||||
 | 
							src += 4;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  uint16_t to_xfer_size = (remaining > xfer->max_size) ? xfer->max_size : remaining;
 | 
						// Write the remaining 1-3 bytes into fifo
 | 
				
			||||||
  uint8_t to_xfer_rem = to_xfer_size % 4;
 | 
						uint32_t tmp_word = 0;
 | 
				
			||||||
  uint16_t to_xfer_size_aligned = to_xfer_size - to_xfer_rem;
 | 
						switch(len & 0x0003){
 | 
				
			||||||
 | 
							case 3: tmp_word |= src[2] << 16;
 | 
				
			||||||
  // Buffer might not be aligned to 32b, so we need to force alignment
 | 
							case 2: tmp_word |= src[1] << 8;
 | 
				
			||||||
  // by copying to a temp var.
 | 
							case 1: tmp_word |= src[0];
 | 
				
			||||||
  uint8_t * base = (xfer->buffer + xfer->queued_len);
 | 
								*tx_fifo = tmp_word;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
  // This for loop always runs at least once- skip if less than 4 bytes
 | 
							default: break;
 | 
				
			||||||
  // to send off.
 | 
						}
 | 
				
			||||||
  if(to_xfer_size >= 4) {
 | 
					 | 
				
			||||||
    for(uint16_t i = 0; i < to_xfer_size_aligned; i += 4) {
 | 
					 | 
				
			||||||
      uint32_t tmp = base[i] | (base[i + 1] << 8) | \
 | 
					 | 
				
			||||||
        (base[i + 2] << 16) | (base[i + 3] << 24);
 | 
					 | 
				
			||||||
      (* tx_fifo) = tmp;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Do not read beyond end of buffer if not divisible by 4.
 | 
					 | 
				
			||||||
  if(to_xfer_rem != 0) {
 | 
					 | 
				
			||||||
    uint32_t tmp = 0;
 | 
					 | 
				
			||||||
    uint8_t * last_32b_bound = base + to_xfer_size_aligned;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    tmp |= last_32b_bound[0];
 | 
					 | 
				
			||||||
    if(to_xfer_rem > 1) {
 | 
					 | 
				
			||||||
      tmp |= (last_32b_bound[1] << 8);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if(to_xfer_rem > 2) {
 | 
					 | 
				
			||||||
      tmp |= (last_32b_bound[2] << 16);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    (* tx_fifo) = tmp;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void read_rx_fifo(USB_OTG_OUTEndpointTypeDef * out_ep) {
 | 
					static void read_rx_fifo(USB_OTG_OUTEndpointTypeDef * out_ep) {
 | 
				
			||||||
@@ -677,17 +657,37 @@ static void handle_epin_ints(USB_OTG_DeviceTypeDef * dev, USB_OTG_INEndpointType
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // XFER FIFO empty
 | 
					      // XFER FIFO empty
 | 
				
			||||||
      if ( in_ep[n].DIEPINT & USB_OTG_DIEPINT_TXFE )
 | 
					      if ( (in_ep[n].DIEPINT & USB_OTG_DIEPINT_TXFE) && (dev->DIEPEMPMSK & (1 << n)) )
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        // DIEPINT's TXFE bit is read-only, software cannot clear it.
 | 
					        // DIEPINT's TXFE bit is read-only, software cannot clear it.
 | 
				
			||||||
        // It will only be cleared by hardware when written bytes is more than
 | 
					        // It will only be cleared by hardware when written bytes is more than
 | 
				
			||||||
        // - 64 bytes or
 | 
					        // - 64 bytes or
 | 
				
			||||||
        // - Half of TX FIFO size (configured by DIEPTXF)
 | 
					        // - Half of TX FIFO size (configured by DIEPTXF)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        transmit_packet(xfer, &in_ep[n], n);
 | 
					      	// Packets to be processed
 | 
				
			||||||
 | 
					      	uint16_t tx_packet_amount = (in_ep[n].DIEPTSIZ & USB_OTG_DIEPTSIZ_PKTCNT_Msk) >> USB_OTG_DIEPTSIZ_PKTCNT_Pos;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      	// Process every single packet (only whole packets can be written to fifo)
 | 
				
			||||||
 | 
					      	for(uint16_t i = 0; i < tx_packet_amount; i++){
 | 
				
			||||||
 | 
					      		// amount of bytes EP still needs to transfer
 | 
				
			||||||
 | 
					      		uint16_t tx_remaining = (in_ep[n].DIEPTSIZ & USB_OTG_DIEPTSIZ_XFRSIZ_Msk) >> USB_OTG_DIEPTSIZ_XFRSIZ_Pos;
 | 
				
			||||||
 | 
					      		// Packet can not be larger than ep max size
 | 
				
			||||||
 | 
					      		uint16_t packet_size = (tx_remaining > xfer->max_size) ? xfer->max_size : tx_remaining;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      		// It's only possible to write full packets into FIFO. Therefore DTXFSTS register of current
 | 
				
			||||||
 | 
					      		// EP has to be checked if the buffer can take another WHOLE packet
 | 
				
			||||||
 | 
					      		if(packet_size > ((in_ep[n].DTXFSTS & USB_OTG_DTXFSTS_INEPTFSAV_Msk) << 2)){
 | 
				
			||||||
 | 
					      			break;
 | 
				
			||||||
 | 
					      		}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      		xfer->queued_len = xfer->total_len - tx_remaining;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      		// Push packet to Tx-FIFO
 | 
				
			||||||
 | 
										transmit_fifo_packet(n, (xfer->buffer + xfer->queued_len), packet_size);
 | 
				
			||||||
 | 
					      	}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Turn off TXFE if all bytes are written.
 | 
					        // Turn off TXFE if all bytes are written.
 | 
				
			||||||
        if (xfer->queued_len == xfer->total_len)
 | 
					        if (((in_ep[n].DIEPTSIZ & USB_OTG_DIEPTSIZ_XFRSIZ_Msk) >> USB_OTG_DIEPTSIZ_XFRSIZ_Pos) == 0)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          dev->DIEPEMPMSK &= ~(1 << n);
 | 
					          dev->DIEPEMPMSK &= ~(1 << n);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user