USB <Virtual_com demo> output queue full problem

取消
显示结果 
显示  仅  | 搜索替代 
您的意思是: 
已解决

USB <Virtual_com demo> output queue full problem

跳至解决方案
1,348 次查看
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

标签 (1)
0 项奖励
1 解答
686 次查看
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 项奖励
2 回复数
687 次查看
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 项奖励
686 次查看
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 项奖励