USB Tx slow for a large block of data

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

USB Tx slow for a large block of data

1,077 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by pra18 on Thu Dec 11 10:04:42 MST 2014
Hi,

I am trying to implement Tx on a USB Virtual COM for the support of physical layer of an application layer protocol in my custom board.

It is a lpc4357 and uses USB1 on it.

I am not having any problem when it comes to transmitting a single byte over the USB or perhaps shorted frames of data.

But the problem occurs when I try to send large block of data of say 177 records . There are delays in between say it transmits 27 records and
then there is a delay for a short while. after that it again transmits another 30 records. It takes some time like this and finally achieves a full transfer

This problem does not exist for short frames however.

Whereas, the Application layer is doing many retries in this period and is not acceptable to wait because the block of data should be sent as fast as possible and
a callback notification goes to the application layer that the transfer was completed.

If this callback is not signalled in time, the application layer does many retries but the low level USB pauses for a while and at its own convinience transmits next block of data

Is the application layer doing retries very fastly before the USB Tx is done ?

Can anyone point out where exactly the problem could be? Can it be that 64 bytes is max. packet length and it sends 64 bytes at once and then during the next EP IN interrupt the handler services the interrupt and then another 64 bytes are being sent using WriteEP call ?

Thanks in advance,

Labels (1)
0 Kudos
Reply
4 Replies

965 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by pra18 on Wed Feb 11 03:37:59 MST 2015
Hi,

Thank you for replying to my problem.
I have tried to explain below what is happening and also code which I use . I sent descriptors earlier.

Case1:
when I use my device in ModBus mode,  this function gets repeatedly called by the protocol to request USB to send a block of data

This is where I am seeing that the problem is

My function to Transmit a block of data is as below.

int SendBlockOfData(const unsigned char *UsbData,unsigned int NrOfBytes, void (*cb)(void))
  {
  int rc = 0;

  /*signal via hook */
  CompleteHook = cb;

  /*make safe copy*/
  (void)memcpy(UsbTxBuff, UsbData, NrOfBytes);

  /*flag Tx */
  UsbTxBusy |= USB_TX_BUSY;
 
  /* enter critical section */
  NVIC_DisableIRQ(LPC_USB_IRQ);
  rc = USBD_API->hw->WriteEP(UsbdHandle, USB_CDC_IN_EP,(uint8_t *) UsbTxBuff, NrOfBytes);
  /* enter critical section */
  NVIC_EnableIRQ(LPC_USB_IRQ);
 
  return rc; 
  }


In this function argument, There is a callback TxHook which is used to notify higher protocol layer that physical layer USB Tx is complete.

Problem observed:
There are timeouts seen on the Host side when the  PC program  requests large block of data from the device.

For Data with small frames there is no problem. no delay and response is quick.

for data having larger frame size while sending  blocks of data, the timeout occurs  on the Host PC Program with WBVAL(64) in descriptors while with WBVAL(1C)
it works correctly and no timeouts, though very rare.


Case2 : ASCII mode

when I use the device in ASCII mode this function gets called


int SendDataUSB(unsigned char Data)
  {
  /* not transmitting a block of data in which case assign this hook to NULL*/
  CompleteHook = NULL;
 
  /* write Tx */
  if((UsbWrite(&Data,1))== 1)       
    return (int)Data;
 
  return (-1);
  }

I dont see any problem in ASCII mode even with WBVAL(64) or if I change it to WBVAL(64). Everything works fine.
I feel it does not affect ASCII mode of transmission.


Below are my IN and OUT Handlers

ErrorCode_t INHandler(USBD_HANDLE_T UsbdHandle, void *Data, uint32_t Event)
  {
   Data = Data ;

   if (Event == USB_EVT_IN)
     {   
   
     /* allow next send */
     UsbTxBusy &= ~USB_TX_BUSY; 
    

     /* call registered hook
     if(CompleteHook != NULL)
       {          
       CompleteHook(); 
       CompleteHook = NULL;
       } 
      
     }
 
  return LPC_OK;
  }

volatile uint16_t BytesCount = 0;

ErrorCode_t OUTHandler(USBD_HANDLE_T UsbdHandle, void *Data, uint32_t Event)
  {
  int i;
 
  (void )&Data;

  switch (Event)
  {
  case USB_EVT_OUT:
  BytesCount = USBD_API->hw->ReadEP(UsbdHandle, USB_CDC_OUT_EP, &RxHelper[0]);
 

  if(LocalBytesCount != 0)
    {
    /* reset to 0 */
    RxBusy = 0;
    }
 

  for(i = 0; i <BytesCount; i++)
    {
    RxRing = RxHelper;
    }

    break;

  case USB_EVT_OUT_NAK:
    if (RxBusy == 0)
      /*  we've not queued the Rx buffer, so handle this NAK event. */
      {
      /* queue free buffer for RX and send DMA request */
      USBD_API->hw->ReadReqEP(UsbdHandle, USB_CDC_OUT_EP, &RxHelper[0], RX_BUFFER);
      /* Flag RX buffer as busy and allow base handler to queue the buffer. */
      RxBusy = 1;
      }
    else
      {
      /* we've already queued the Rx buffer, so ignore this NAK event. */
      return LPC_OK;
      }
     
  break;

  default:
  break;
  }

  return LPC_OK;
  }

Here is my Write  routine

int Write(uint8_t *Buf, uint32_t Len)
  {
  int rc = 0;
  if (UsbTxBusy & USB_TX_CONNECTED) 
    { 

    while(( UsbTxBusy & USB_TX_BUSY) != 0);
    UsbTxBusy |= USB_TX_BUSY;
   
    /* enter critical section */
   
    rc = USBD_API->hw->WriteEP(UsbdHandle, USB_CDC_IN_EP, (uint8_t *)Buf, Len);
    /* exit critical section */
   
    }

  return rc;
  }


Regards,
0 Kudos
Reply

965 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Tsuneo on Tue Feb 10 06:04:42 MST 2015
You wrote "a large block of data" in your post title and body. This description gave us wrong impression that your entire records are passed to the bulk IN in single large buffer. It made us confused.

But in fact, you should pass each record (0x1C bytes or so) to the bulk IN endpoint, one by one. And then, the endpoint size (wMaxPacketSize: MPS) just of the record size makes the transfer speed maximize.

Unfortunately, the USB spec doesn't allow MPS of 0x1C (or 1A,1B,1C,1D 1E, 1F) for full-speed bulk endpoint. Just 8, 16, 32 and 64. The out-of-spec MPS is not guaranteed to work on every PC, even if it would work on your PC.

I believe 32 bytes MPS and padding of each record to 32 bytes would be passable solution.
Also, you need to send ZLP, to terminate the "Transfer" at the end of "large block of records".

Tsuneo
0 Kudos
Reply

965 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by pra18 on Tue Feb 10 03:09:49 MST 2015
Hi,

After changing the WBVAL(64) to WBVAL(0x001C) in  the last lines of ALIGNED(4) uint8_t USB_FsConfigDescriptor[] array ,the response has greatly improved and now there is no delays anymore. The application layer is able to receive all data in time. This problem occured only when the USB served as a physical layer for higher layer protocol ModBus but when the USB request-response were verified in a Hyperterminal program, the response was very good ( even if WBVAL was 64).

What is now the worrying part is is the value WBVAL(1C) or 1D,1E,1F alowed to be used in the /* wMaxPacketSize */ field in the USB_FsConfigDescriptor array?

also would liek to understand when i changed WBVAL(64) to WBVAL(1C) what exactly happened in the USB stack , how did it start working.
Was it the USB  windows Host driver that was not accepcting 64 but it accepted 1C( 1A,1B,1C,1D 1E and 1F also work but not 64,32,16,8)

If this is Ok, then my problem is solved. Ortherwise, please suggest me what to do next.

I have attached my descriptors for your reference.

I am using USB1 on my NXP 4330 custom board.

Thanks,









0 Kudos
Reply

965 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by xianghuiwang on Mon Feb 09 12:22:22 MST 2015
Hi, pra18,
Please check below for performance improvement:
1. configure your endpoint to 512byte for high speed USB.
2. if you are using Bulk transfer, check if your system has other isochronous or interrupt transfer that eat all your host's bandwidth.
You can reference the LPCOpen USB VCOM example for more ideas:
http://www.lpcware.com/content/nxpfile/lpcopen-software-development-platform-lpc43xx-packages
regards,
0 Kudos
Reply