+ Reply to Thread
Results 1 to 2 of 2

Thread: XMC4500. USB-device. Zero-length packets in isochronous IN-endpoint - how to prevent?

  1. #1
    Intermediate Intermediate rst is on a distinguished road
    Join Date
    Nov 2016
    Location
    Latvia, Riga
    Posts
    23
    Points
    299.375

    XMC4500. USB-device. Zero-length packets in isochronous IN-endpoint - how to prevent?

    I need a fast real-time data stream from device (USB-device) to PC (USB-host). I use a large isochronous endpoint (packet length <= 1023 bytes).
    The data is transmitted, but very often in frame stream on the host side I get of zero-length packets (ZLP). Although I do not send ZLP from my device (I send all packets of a fixed length).
    Because of this, the flow rate decreases.
    How to transfer data into USB-core so that ZLP-s are absent?

    I write the data for transfer like this:
    Code:
    #define USBCFG_DMA 0
    
    #define B0 (1u << 0)
    #define B1 (1u << 1)
    #define B2 (1u << 2)
    ...
    #define B31 (1u << 31)
    
    //Writes number of bytes in to the USB IN endpoint.
    u32 UsbHwEpWrite(uint epa, void const *buf, u32 len)
    {
      UsbEp *ep = &udev.ep[epa & USB_EP_NUM_MSK];
      if (ep->state != ep->S_CFG) return 0;
      ep->xferBuf = (u8 *)buf;
      ep->xferTotal = len;
      ep->xferLen = ep->xferCnt = 0;
      ep->state = ep->S_IN;
      StartWriteXfer(ep);
      return ep->xferTotal;
    }
    
    //Start a new in transfer.
    //Based on the transfer values of the endpoint the in endpoint registers will be programmed to start a new in transfer
    //ep - Endpoint to start the transfer
    static void StartWriteXfer(UsbEp *ep)
    {
      uint i, n, e = ep->address & USB_EP_NUM_MSK;        //for isoc.ep ep->address == 0x81
      HwRegsUSB::T_DEP volatile *pdep = &USB.DIEP[e];
      n = maxTransferSize[__USAT(e, 1)];                  //for isoc.ep n == 65472
      if (ep->xferTotal - (i = ep->xferLen) < n) ep->xferLen = i = ep->xferTotal;
      else ep->xferLen = i += n;
      u32 j = 1 << 19; //number of packets. do not used, since i != 0 for isoc.ep
      if (i) {
        i -= ep->xferCnt;
        if (e) j = divCeil(i, ep->maxPacketSize) << 19;  //#define divCeil(a, b) (((a) + (b) - 1) / (b))
        j |= i;        //for isoc.ep for example: j == 0x803FF
        if (USBCFG_DMA) { //USBCFG_DMA==0
          u8 *s = ep->xferBuf + ep->xferCnt; //source address
          if (((u32)s & 3) || !IN_RANGE((u32)s, RAM_regionB_start, RAM_regionC_start + RAM_regionC_size - 1)) { //do not used, since the isochronous point data placed is in RAM
            memcpy(ep0buf.data, s, i);
            s = ep0buf.data;
          }
          pdep->DMA = (u32)s;  //USB.DIEPDMAx
        } else USB.DIEPEMPMSK |= 1 << e; //enable fifo empty interrupt
      }
      //Program size of transfer and enable endpoint
      pdep->TSIZ = j;          //USB.DIEPTSIZx
      pdep->CTL |= B26 | B31;  //USB.DIEPCTLx. set bits CNAK and EPEna
    }
    When data transfer to USB-host is completed, an interrupt occurs, which is processed by this code:

    Code:
    //Handles all interrupts for all in endpoints
    //The interrupt handler first checks, which endpoint has caused the interrupt and then
    //determines, which interrupt should be handled.
    static void HndIEPInt()
    {
      int i, e;
      u32 c, ie, ia = USB.DAINT & B16 - 1;
      while ((e = 31 - __CLZ(ia)) >= 0) {
        ia -= 1 << e;
        UsbEp *ep = &udev.ep[e];
        HwRegsUSB::T_DEP volatile *pdep = &USB.DIEP[e];
        ie = pdep->INT;     //USB.DIEPINTx
        ie &= (USB.DIEPEMPMSK >> e & 1) << 7 | DIEPMSK;  //enum {DIEPMSK = B0 | B1 | B2 | B3};
        if (!USBCFG_DMA) if (ie & B7) {
          //Write data to an endpoint fifo
          //The data from the ep->xferBuf gets copied in to the tx fifo of the endpoint until the buffer has been read
          //completely or the tx fifo is full. The transfer values are not updated.
          if (c = ep->xferLen - ep->xferCnt) { //calculate the length and the amount of dwords to copy based on the fifo status
            //add the unaligned bytes to the word count to compare with the fifo space
            if (c < (i = (pdep->TXFSTS & B16 - 1) << 2)) i = c;   //pdep->TXFSTS == USB.DTXFSTSx
            u32 volatile *fifo = FIFO_PTR(ep->txFifoNum);         //#define FIFO_PTR(epn) (u32 *)((u8 *)&USB + 0x1000 + (uint)(epn) * 0x1000)
            u8 *s = ep->xferBuf + (c = ep->xferCnt);
            for (ep->xferCnt = c + i; (i -= 4) >= 0; s += 4) *fifo = *(u32p8 *)s; //copy data dword wise
            if (i & 3) {
              c = 0;
              if ((i += 2) >= 0) {
                c = *(u16p8 *)s;
                s += 2;
              }
              if (i) c |= *s++ << __USAT(i << 4, 5);
              *fifo = c;
            }
          }
        }
        if (ie & B0) {
          if (USBCFG_DMA) if (!(pdep->TSIZ & B29 - 1)) ep->xferCnt = ep->xferLen;     //pdep->TSIZ == USB.DIEPTSIZx
          if (ep->xferTotal == ep->xferLen) {  //always true
            pdep->CTL = pdep->CTL & (B11 - 1 | B15 | 3 << 18 | B20 | 15 << 22) | B27; //USB.DIEPCTLx. set bit SNAK. I also tried not to set this bit after transfer was completed - but nothing changes
            ep->state = ep->S_CFG;
            if (!USBCFG_DMA) USB.DIEPEMPMSK &= ~(1 << e);   //Mask fifo empty interrupt
            UsbEventEndpoint(USB_EP_IN(e), USB_EVT_IN);     //Inside this function, a call of UsbHwEpWrite() is made to write the next data frame
          } else StartWriteXfer(ep); //start next step of transfer - never called for isoc.ep
        }
        if (USBCFG_DMA) if (ie & B2) trap(TRAP_USB | USB_ERR_AHB << 16, pdep->DMA);
        pdep->INT = ie; //USB.DIEPINTx
      }
    }
    remark:

    Code:
    struct UsbEp {
      enum { //endpoint's states
        S_VOID, //do not configured
        S_CFG,  //is configured
        S_IN,   //IN-transaction in progress
        S_OUT   //OUT-transaction in progress
      };
      union {
        struct {
          u8 type:2;            //The endpoint type
          u8 isStalled:1;       //Sets if the selected USB endpoint is stalled.
          u8 sendZLP:1;         //If set, a zero length packet will be send at the end of the transfer
        };
        u8 attr;
      };
      u8 volatile state;    //one from S_...
      u8 address;           //The endpoint address including: bits0...3 - endpoint number; bit7 - direction
      u8 txFifoNum;         //Endpoint transmit Fifo Number
      u16 maxPacketSize;    //The maximum size of packet for USB endpoint (due to FS Speed device only 64 Byte)
      u16 xferLen;          //The length of the current transfer
      u16 xferCnt;          //Bytes transfered of the current USB data transfer
      u16 xferTotal;        //The length of total data in buffer
      u8 *xferBuf;          //The buffer of the current transfer
    };
    
    typedef __packed u16 u16p8;
    typedef __packed s16 s16p8;
    typedef __packed u32 u32p8;
    typedef __packed s32 s32p8;
    typedef __packed u64 u64p8;
    typedef __packed s64 s64p8;
    typedef __packed u32 u32p16;
    typedef __packed s32 s32p16;
    typedef __packed u64 u64p16;
    typedef __packed s64 s64p16;
    typedef __packed u64 u64p32;
    typedef __packed s64 s64p32;

  2. #2
    Intermediate Intermediate rst is on a distinguished road
    Join Date
    Nov 2016
    Location
    Latvia, Riga
    Posts
    23
    Points
    299.375
    Question canceled. I studied the manual more thoroughly and independently solved this problem.
    For those members, who will be interested, I give a solution:
    In function StartWriteXfer() needs modify these lines:
    pdep->TSIZ = j;
    pdep->CTL |= B26 | B31;
    to:
    pdep->TSIZ = j;
    j = pdep->CTL;
    pdep->CTL = j | B26 | B31 | B29 >> (j >> 16 & 1);
    and after this action the extra ZLP no longer appear.
    Last edited by rst; Mar 12th, 2020 at 03:43 PM.

+ Reply to Thread

Tags for this Thread

Disclaimer

All content and materials on this site are provided “as is“. Infineon makes no warranties or representations with regard to this content and these materials of any kind, whether express or implied, including without limitation, warranties or representations of merchantability, fitness for a particular purpose, title and non-infringement of any third party intellectual property right. No license, whether express or implied, is granted by Infineon. Use of the information on this site may require a license from a third party, or a license from Infineon.


Infineon accepts no liability for the content and materials on this site being accurate, complete or up- to-date or for the contents of external links. Infineon distances itself expressly from the contents of the linked pages, over the structure of which Infineon has no control.


Content on this site may contain or be subject to specific guidelines or limitations on use. All postings and use of the content on this site are subject to the Usage Terms of the site; third parties using this content agree to abide by any limitations or guidelines and to comply with the Usage Terms of this site. Infineon reserves the right to make corrections, deletions, modifications, enhancements, improvements and other changes to the content and materials, its products, programs and services at any time or to move or discontinue any content, products, programs, or services without notice.