AnsweredAssumed Answered

Creating flow control in VCP-derived code

Question asked by achterop.sietse on Mar 28, 2014
Latest reply on Feb 16, 2017 by achterop.sietse
Dear list,

  I use the USB-VCP example, from STM32_USB-Host-Device_Lib_V2.1.0, for my application, but am running
into some trouble when trying to get the proper flowcontrol for my application.

I removed the usart code and separated input and output in the example.
There now only is a background process that uses VCP to communicate with a PC.
My background sends data to the USB IN endpoint using VCP_DataTx, and reads data
from the USB OUT endpoint via a simple fifo filled by VCP_DataRx.
See the code below for that.

But VCP_DataRx stalls if the fifo is full, and the background process does not make process anymore,
effectively creating a deadlock. I assume that VCP_DataRx is called from an interrupt routine.

I am trying to figure a way to solve this problem, but still using the VCP code as unchanged as possible.
Is there a way to trigger flow control ("XOFF") in the USB OUT endpoint in another way than stalling VCP_DataRx?

If so, then I could call that code from VCP_DataRx when there still is enough room in the fifo.
  (enough meaning, enough to make the current (and maybe the next) call to VCP_DataRx finish..
   This of course depends upon the maximum size of the parameter Len)
Then the background could to its work until the fifo is allmost empty and then start the USB OUT endpoint again ("XON").

Is this something that makes sense? Some trickery in one of the USB interrupt routines?
Or is there another approach possible?

  Thanks in advance,
      Sietse

PS. I could start using a RTOS, and than make both the usb interrupts and the background process into RTOS processes,
      but I would like to avoid that complexity.

static uint16_t VCP_DataRx (uint8_t* Buf, uint32_t Len)
{
  int i = Len; int j;
  while (i > fifo_free(&recfifo));     /* Wait busy, and deadlock!  */
 
  j = 0;
  while (j<i)
    fifo_put(&recfifo,Buf[j]); j++;
  return USBD_OK;
}

For completeness I also include the background function that I use.

// Used in background. non-blocking
int rtIOStreamRecv(
           int      streamID,
           void   * dst,
           size_t   size,
           size_t * sizeRecvd) {
  int i; uint8_t c; uint32_t j;
   
  if (size == 0) {
    return 0;
  }
  else
    if ((i=fifo_avail(&recfifo))) {
      if (i > size) i = size;
      for ( j=0; j<i; j++) {
    if (fifo_get(&recfifo,&c))  {
      ((char *)dst)[j] = c;
    }
      }
      return i;
  } else
      return 0;
}

Outcomes