USB <Virtual_com demo> output queue full problem

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

USB <Virtual_com demo> output queue full problem

Jump to solution
1,633 Views
MarkP_
Contributor V

Hi,

Tested virtual com in TWR-K60N512 with TeraTerm (v4.75) running in Win7. MQX 4.0.2 and CW10.4 are used.
Character send and echo is OK when pressed by keyboard.
But when sending a testfile (35kb) the output queue became full and characters are not echoed any more.

The following if-test is always false in usb_cdc.c:
uint_8 USB_Class_CDC_Send_Data()
  if(((uint_8)(producer - consumer)) != (uint_8)(CDC_MAX_QUEUE_ELEMS))

Meaning that data is not sent anymore althought there is data in queue.


Increased CDC_MAX_QUEUE_ELEMS from 16 to 128, didn't help.

Does this kind of file send work in your build/environment? And after file send character echo works OK?
Or is the problem in USB stack?

Do you know if the <Freescale USB Stack v4.1.1> works better?

Transmit delay in TeraTerm may help, but that delay cannot be implemented into our Application from where

the data communication is handled. Purpose is to run 921600 baud full duplex.
 
Following projects are used:
C:\Freescale\Freescale_MQX_4_0\usb\device\examples\cdc\virtual_com\cw10\cdc_vcom_twrk60n512
C:\Freescale\Freescale_MQX_4_0\usb\device\build\cw10\usbd_twrk60n512

~Mark

Labels (1)
0 Kudos
Reply
1 Solution
971 Views
MarkP_
Contributor V

The problem is that receiver is activated too urgently.

Fixes:

1) Comment USB_Class_CDC_Recv_Data call away:

   g_recv_size = index;

   /* Schedule buffer for next receive event */

// USB_Class_CDC_Recv_Data(handle, DIC_BULK_OUT_ENDPOINT, g_curr_recv_buf, DIC_BULK_OUT_ENDP_PACKET_SIZE);

2) Add USB_Class_CDC_Recv_Data call here. Also tested a functionality when char echo skipped.

void Virtual_Com_App(void)

...

if(g_send_size)
{
  uint_8 error;
  uint_8 size = g_send_size;
  g_send_size = 0;

  if (g_curr_send_buf[0] == 'z' || g_curr_send_buf[0] == 'x')
  {

    error = USB_Class_CDC_Send_Data(g_app_handle, DIC_BULK_IN_ENDPOINT,g_curr_send_buf, size);
    if (!error && !(size % DIC_BULK_IN_ENDP_PACKET_SIZE))
{
   /* If the last packet is the size of endpoint, then send also zero-ended packet,
   ** meaning that we want to inform the host that we do not have any additional
   ** data, so it can flush the output.
   */
   error = USB_Class_CDC_Send_Data(g_app_handle, DIC_BULK_IN_ENDPOINT, NULL, 0);
    }
    if(error != USB_OK)
    {
    /* Failure to send Data Handling code here */
    }
  }
  /* Receive data handled. Schedule buffer for next receive event */
  error = USB_Class_CDC_Recv_Data(g_app_handle, DIC_BULK_OUT_ENDPOINT, g_curr_recv_buf, DIC_BULK_OUT_ENDP_PACKET_SIZE);
  if(error != USB_OK)
  {
    /* Failure to send Data Handling code here */
  }
}

~Mark

View solution in original post

0 Kudos
Reply
2 Replies
972 Views
MarkP_
Contributor V

The problem is that receiver is activated too urgently.

Fixes:

1) Comment USB_Class_CDC_Recv_Data call away:

   g_recv_size = index;

   /* Schedule buffer for next receive event */

// USB_Class_CDC_Recv_Data(handle, DIC_BULK_OUT_ENDPOINT, g_curr_recv_buf, DIC_BULK_OUT_ENDP_PACKET_SIZE);

2) Add USB_Class_CDC_Recv_Data call here. Also tested a functionality when char echo skipped.

void Virtual_Com_App(void)

...

if(g_send_size)
{
  uint_8 error;
  uint_8 size = g_send_size;
  g_send_size = 0;

  if (g_curr_send_buf[0] == 'z' || g_curr_send_buf[0] == 'x')
  {

    error = USB_Class_CDC_Send_Data(g_app_handle, DIC_BULK_IN_ENDPOINT,g_curr_send_buf, size);
    if (!error && !(size % DIC_BULK_IN_ENDP_PACKET_SIZE))
{
   /* If the last packet is the size of endpoint, then send also zero-ended packet,
   ** meaning that we want to inform the host that we do not have any additional
   ** data, so it can flush the output.
   */
   error = USB_Class_CDC_Send_Data(g_app_handle, DIC_BULK_IN_ENDPOINT, NULL, 0);
    }
    if(error != USB_OK)
    {
    /* Failure to send Data Handling code here */
    }
  }
  /* Receive data handled. Schedule buffer for next receive event */
  error = USB_Class_CDC_Recv_Data(g_app_handle, DIC_BULK_OUT_ENDPOINT, g_curr_recv_buf, DIC_BULK_OUT_ENDP_PACKET_SIZE);
  if(error != USB_OK)
  {
    /* Failure to send Data Handling code here */
  }
}

~Mark

0 Kudos
Reply
971 Views
ianridge
Contributor I

Hi Mark,

Your problem may be caused by a logical bug in the MQX USB device stack (in version <= 4.0.2).

Bug description:

The 'USB_Class_CDC_Send_Data' function in usb_cdc.c uses a variable (uint_8 consumer) to store a local copy of a value changed by the USB completion interrupt (in USB_Service_Cdc_Notif). If this interrupt occurs between the variable being assigned near the start of USB_Class_CDC_Send_Data, and the variable being tested near the end of the function, it will result in the test failing to detect that it is necessary to start sending. Instead it incorrectly assumes there is other packet in the process of being sent. As the next item is only sent from the queue when the previous item completes, nothing is ever sent again and the queue fills up on subsequent calls. This is most likely to happen if 'USB_Class_CDC_Send_Data'  is called 2 or more times in quick succession (or in a loop).

Fix:

Modify MQX so it doesn't take a local copy of bin_consumer in the 'USB_Class_CDC_Send_Data' function. Directly test the value changed by the interrupt instead. bin_producer does not suffer the same problem as it is tested but not modified in the interrupt.

Alternatively you could try disabling interrupts before calling USB_Class_CDC_Send_Data, and re-enabling afterwards.

Index: usb_cdc.c

===================================================================

--- usb_cdc.c (revision 21)

+++ usb_cdc.c (revision 22)

@@ -628,7 +628,7 @@

{

     #if IMPLEMENT_QUEUING

         uint_8 index;

-        uint_8 producer, consumer;

+        uint_8 producer;

//        USB_ENDPOINTS *usb_ep_data;

     #endif   

        

@@ -646,12 +646,12 @@

         index = USB_Map_Ep_To_Struct_Index(cdc_obj_ptr, ep_num);

                

         producer = cdc_obj_ptr->ep[index].bin_producer;

-        consumer = cdc_obj_ptr->ep[index].bin_consumer;

+   //     consumer = cdc_obj_ptr->ep[index].bin_consumer;

                                

-        if(((uint_8)(producer - consumer)) != (uint_8)(CDC_MAX_QUEUE_ELEMS)) 

+        if(((uint_8)(producer - cdc_obj_ptr->ep[index].bin_consumer)) != (uint_8)(CDC_MAX_QUEUE_ELEMS)) 

         {   /* the bin is not full*/       

             uint_8 queue_num = (uint_8)(producer % CDC_MAX_QUEUE_ELEMS);

-           

+          

             /* put all send request parameters in the endpoint data structure*/

             cdc_obj_ptr->ep[index].queue[queue_num].channel = ep_num;

             cdc_obj_ptr->ep[index].queue[queue_num].app_data.data_ptr = app_buff;

@@ -658,10 +658,11 @@

             cdc_obj_ptr->ep[index].queue[queue_num].app_data.data_size = size;

             cdc_obj_ptr->ep[index].queue[queue_num].handle =

             cdc_obj_ptr->controller_handle;        

+        

             /* increment producer bin by 1*/      

             cdc_obj_ptr->ep[index].bin_producer = ++producer;

-

-            if((uint_8)(producer - consumer) == (uint_8)1)        

+           

+            if((uint_8)(producer - cdc_obj_ptr->ep[index].bin_consumer) == (uint_8)1)        

             {         

     #endif     

                 status = USB_Class_Send_Data(cdc_obj_ptr->class_handle,

Hope this fixes your problem.

Ian

0 Kudos
Reply