cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
p.lerolland
Contributor
Contributor
4,564 Views
Registered: ‎02-24-2016

USB CDC Device Baremetal - Can't send more than 511 bytes

Hi,

 

Following this very good note, I successfully implemented the USB 2.0 communication between the computer and my board (after commenting out twice

 

if (XUsbPs_dTDIsActive(Ep->dTDHead)) {
	return XST_USB_NO_DESC_AVAILABLE;
}

in the XUsb_EpQueueRequest in the xusbps_endpoint.c file.

 

I was previously sending about 500 bytes, which worked absolutely great. But I am now trying to send about 530 bytes and it stopped working.

 

When sending upto 511 bytes, no problem, everything works great.

When sending 512 bytes, the system gets really slow (about 1/8 of the transactions initiated are go through).

When sending 513 or more bytes, the board does not sending anything.

 

I tried adjusting the endpoint 2 configuration in xusbps_cdc.c :

device_config.EpCfg[2].Out.Type		= XUSBPS_EP_TYPE_BULK;
device_config.EpCfg[2].Out.NumBufs	= 16;
device_config.EpCfg[2].Out.BufSize	= 512;
device_config.EpCfg[2].Out.MaxPacketSize	= 512;
device_config.EpCfg[2].In.Type		= XUSBPS_EP_TYPE_BULK;
device_config.EpCfg[2].In.NumBufs	= 16;
device_config.EpCfg[2].In.MaxPacketSize	= 1024;

but unfortunately it does not work. (I modified the In.MaxPacketSize because the board is configured as a CDC device, so sending data to the computer is consider IN endpoint from the host's perspective. I also tried to change the Out.MaxPacketSize just in case but without any success.)

I know that the problem does not come from the computer because I successfully read packets of 530 bytes from a PIC32 MCU.

 

Did someone ever encountered this issue and successfully fixed it? Or does someone know how to fix it?

 

Thanks!

 

Paul

0 Kudos
5 Replies
p.lerolland
Contributor
Contributor
4,355 Views
Registered: ‎02-24-2016

Hi,

I am still struggling with this, any ideas?

Best,

Paul
0 Kudos
p.lerolland
Contributor
Contributor
3,430 Views
Registered: ‎02-24-2016

Hi,

 

I am still trying to figure this out, anyone has any idea?

 

Thanks.

 

Paul

0 Kudos
p.lerolland
Contributor
Contributor
2,665 Views
Registered: ‎02-24-2016

Hi,

 

It's been a while I have not worked on this, I figured a way of doing what I wanted to do with just 511 bytes. But did anyone figured this out by any chance? It's pretty annoying to know that a ZedBoard can't do what a Teensy could do...!

 

Thanks!

 

Paul

0 Kudos
p.lerolland
Contributor
Contributor
2,479 Views
Registered: ‎02-24-2016

Good Afternoon!

 

Does someone have an idea on how to fix it? Is Xilinx considering it a not significant enough issue to be fixed?

 

Thanks!

 

Best,

 

Paul

0 Kudos
emilio_garcia
Visitor
Visitor
2,202 Views
Registered: ‎11-15-2017

I had a similar problem. I was requesting data from my device and I was sending it through the function XUsbPs_EpBufferSend() and at some point I could not send any more data due to the

 

if (XUsbPs_dTDIsActive(Ep->dTDHead)) {
  return XST_USB_NO_DESC_AVAILABLE;
}

in XUsbPs_EpQueueRequest()

 

The problem was that I was running out of dTDs for sending and therefore I could not answer back to any new data requests from the usb host. The reason was that I was sending from my device the data back to the usb host too late and the host kept on requesting new data. I had a lot of debug outputs and those were the reason of my delayed usb transmission.

 

The problem is that when a pending transmission is blocked by another incomming message in the same endpoint, then the dTD is not properly cleared and it is just left as pending. Which obviously will lead to running out of dTDs for sending at some point. At least this was my conclusion after some debugging.

 

This other post had the same issue as me:

https://forums.xilinx.com/xlnx/board/crawl_message?board.id=EMBEDDED&message.id=16485

 

My first solution was to simply add more dTDs to the endpoint, but still the problem was there. For adding more dTDs you only need to increase the numBuf

 

...
device_config.EpCfg[2].In.Type		= XUSBPS_EP_TYPE_BULK;
device_config.EpCfg[2].In.NumBufs	= 16;     // Here increase the number of dTDs
device_config.EpCfg[2].In.MaxPacketSize	= 1024;
...

So after some time I decided to fix this problem. I am niether an usb expert nor a xilinx usb module expert, so I do not know if the code that I added for resetting all the dTDs from an IN endpoint is breaking any rule.

 

I am basically flushing the endpoint and then setting all the active flags of the dTDs to not active.

 

void resetEndpoint(XUsbPs *InstancePtr, u8 EpNum, u8 Direction)
{
  // Timeout counter for avoiding being locked up inside a while loop
  u32 timeoutCounter = 1000;

  u32 Mask = 0x00;
  if (Direction == XUSBPS_EP_DIRECTION_IN)
  {
    // Mask for the IN endpoints, aka transmission ones
    Mask = 0x00010000;
  }
  else
  {
    // Mask for the OUT endpoints, aka reception ones
    Mask = 0x00000001;
  }

  u32 BitMask = Mask << EpNum;

  // First disable all the interrupts, so no one disturbs us while cleaning the dTDs
  XUsbPs_IntrDisable(InstancePtr, XUSBPS_IXR_ALL);
  // Then disable the endpoint
  XUsbPs_EpDisable(InstancePtr, EpNum, Direction);

  do
  {
    // Flush the endpoint
    XUsbPs_EpFlush(InstancePtr, EpNum, Direction);
    // Wait until all bits are zero, meaning that the flush has been executed.
    // Nevertheless, we still do not know if the flush was successful, so far we
    // only know that the usb hardware tried to flush the desired endpoint
    while(XUsbPs_ReadReg(InstancePtr->Config.BaseAddress, XUSBPS_EPFLUSH_OFFSET) &&
          timeoutCounter)
    {
      timeoutCounter--;
    }

    // Guard for avoiding getting blocked in here
    if (timeoutCounter == 0)
    {
      // Jump out of the do - while
      break;
    }
  }
  // Check that the endpoint that we just flushed is not primed, meaning that it
  // was properly flushed. If an endpoint is primed it is going to have the ready
  // flag set in this register
  while((XUsbPs_ReadReg(InstancePtr->Config.BaseAddress, XUSBPS_EPRDY_OFFSET) & BitMask));

  // Do some specifics depending on the endpoint direction
  if (Direction == XUSBPS_EP_DIRECTION_IN)
  {
    // Now set all IN dTs from the wanted endpoint to not active
    XUsbPs_Endpoint *Ep = InstancePtr->DeviceConfig.Ep;
    XUsbPs_EpConfig *EpCfg = InstancePtr->DeviceConfig.EpCfg;
    XUsbPs_EpIn *In  = &Ep[EpNum].In;

    // Get the amount of dTDs from this endpoint
    int NumdTD = EpCfg[EpNum].In.NumBufs;
    int Td;

    for (Td = 0; Td < NumdTD; ++Td)
    {
      // Invalidate the cache so that we get the latest data from memory
      XUsbPs_dTDInvalidateCache(&In->dTDs[Td]);
      // Set the IN descriptor's TERMINATE bits
      XUsbPs_dTDSetTerminate(&In->dTDs[Td]);
      // Clear the Active bits
      XUsbPs_dTDClearActive(&In->dTDs[Td]);
      // Now flush the cache so that out latest modifications go to RAM
      XUsbPs_dTDFlushCache(&In->dTDs[Td]);
    }
  }

  // Now re-enable the interrupt and all the endpoint stuff
  XUsbPs_EpEnable(InstancePtr, EpNum, Direction);
  XUsbPs_EpPrime(InstancePtr, EpNum, Direction);
  XUsbPs_IntrEnable(InstancePtr, XUSBPS_IXR_UR_MASK | // Reset request interrupt
                                 XUSBPS_IXR_UI_MASK); //USB Transaction Complete
}

I also needed to add some extra code to xusbps_endpoint.h for clearing an active flag

 

#define XUsbPs_dTDClearActive(dTDPtr)                       \
  XUsbPs_WritedTD(dTDPtr, XUSBPS_dTDTOKEN,                  \
                  XUsbPs_ReaddTD(dTDPtr, XUSBPS_dTDTOKEN) & \
                                 ~XUSBPS_dTDTOKEN_ACTIVE_MASK)

 

Now everytime when I get a XST_USB_NO_DESC_AVAILABLE after calling XUsbPs_EpBufferSend(), I just reset the endpoint. It works for my application but as I said I am not sure if I am violating a rule. By the way, I also removed all the debug outputs that were delayed my usb transmission

0 Kudos