AnsweredAssumed Answered

USB host K64F  weird "receive" behaviour

Question asked by Bastian Stahl on Feb 12, 2018

Hi,

I was working on my problem with the USB Host CDC Connecting Surf Stick to frdmk64f via USB-Host   and stumbled on some weird behaviour. I'm basically using the CDC Host example from SDK2.2 on KDS 3.2, I did some adjustments so my Surf Stick will be recognised as a Device and an a connection will be established. In Linux I could now talk to the Stick via Terminal. From this I know that the Surf Stick after a initial response ( a single character via Terminal is enough)  from the Host will start sending informations in a loop, until ended by a specific AT-Command. Also the received data and other informations is printed to the debug console.  But I could not see any of this on the Debug Console. Until now:

I was skipping through the Code in Debug and stopped in the USB_HostCdcOpenDataInterface function looking at the pipe Init. After that I let the Code run free and suddenly my Terminal received  around 30 to 40 Status messages from the Surf Stick. In this moment it was even possibly to send a simple command an see a correct response. This is exactly how the Programm should work. But it stops after these few dozen Data Packages and no new Data from the stick is printed to Debug. Other prints to Debug still work fine. A Breakpoint in the receive part  won't fire either.

I did some Testing and I only get this (correct) behaviour when I stop in the Pipe Init for a few seconds. A for loop doesn't help, but a while loop interrupted by a Button Interrupt does the trick. Also preventing the code to execute the receive part will result in a correct behaviour.

( The Receive Part)

if(!Flag_1 )
{
    g_CurrentUsbRecvNode = getNodeFromQueue(&g_EmptySendQueue);
    if (g_CurrentUsbRecvNode)
    {
       g_CurrentUsbRecvNode->next = NULL;
       g_CurrentUsbRecvNode->dataLength = USB_HOST_SEND_RECV_PER_TIME;
       if(USB_HostCdcDataRecv(g_cdc.classHandle, (uint8_t *)&g_CurrentUsbRecvNode->buffer[0],
       g_CurrentUsbRecvNode->dataLength, USB_HostCdcDataInCallback, &g_cdc))
    {
    usb_echo("No Data received\r\n");
}
else
{
    if(*g_CurrentUsbRecvNode->buffer != 0)
    usb_echo("\rData received: %s\r\n",g_CurrentUsbRecvNode->buffer);
}
}
}

Flag_1 is toggled with a Button Interrupt. The rest of the code is the original code from the example. But Still after a few Messages nothing comes through. Blocking again doesn't help reproducing the initial effect. Also all the methods aren't working really reliable. 

Sometimes it's like a stored buffer is printed. Many frames at the same time or a in very short Time. Sometimes after unblocking the receive the data flows constant with a short delay between the frames like on a terminal. 

 

I'm not that familiar with drivers like these and don't completely understand how the receiving works and the reverence is not very conclusive. For me it looks like something is stopping the receive after a certain time or amount of Data.

 

Has anyone an Idea what might help or what causes this behaviour?

Or give me some good reference?

 

Cheers 

 

Bastian

 

Update:

After some trying I got to a point where I got it kind of running. It's highly unstable, but I think I found something. The Problem seems to come from the Buffer struct

 

typedef struct _usb_uart_buffer_struct
{
uint8_t buffer[USB_HOST_SEND_RECV_PER_TIME];
uint32_t dataLength;
struct _usb_uart_buffer_struct *next;
} usb_uart_buffer_struct_t;

and the corresponding Variables 

 

usb_uart_buffer_struct_t g_EmptyBuffer[USB_HOST_CDC_BUFFER_NUM];
usb_uart_buffer_struct_t g_EmptySendBuffer[USB_HOST_CDC_BUFFER_NUM];
usb_uart_buffer_struct_t *g_EmptyQueue;
usb_uart_buffer_struct_t *g_EmptySendQueue;
usb_uart_buffer_struct_t *g_CurrentUartRecvNode;
usb_uart_buffer_struct_t *g_UsbSendQueue;
usb_uart_buffer_struct_t *g_UsbSendNode;
usb_uart_buffer_struct_t *g_CurrentUsbRecvNode;
usb_uart_buffer_struct_t *g_UartSendQueue;
usb_uart_buffer_struct_t *g_UartSendNode;

 

They are used to store the data coming for the USB-Pipes and the Debug Terminal in this example. As you can see they are a sort of List containing the Data in a Buffer, the Number of Bytes in the Buffer and a Pointer to the next List element. 

But at some point the next Element and the current Element is NULL and from this onward I can't receive any more messages. A reset of the Buffers helps but this causes other errors. This is the code I got kind of running.

 

case kRunIdle:
            if (g_AttachFlag)
            {


                      {
                if (!g_UsbSendBusy)
                {
                    if(g_UsbSendQueue)
                      {
               g_UsbSendNode = getNodeFromQueue(&g_UsbSendQueue);
               if (g_UsbSendNode)
               {
                   g_UsbSendBusy = 1;
                   USB_HostCdcDataSend(g_cdc.classHandle, (uint8_t *)&g_UsbSendNode->buffer[0],
                              g_UsbSendNode->dataLength, USB_HostCdcDataOutCallback, &g_cdc);

               }
                      }
                    else
              {
                     if (g_EmptySendQueue)
                       {

                         g_CurrentUsbRecvNode = getNodeFromQueue(&g_EmptySendQueue);
//                   if (g_CurrentUsbRecvNode)
                   {
                           NoReceivCounter = 0;
                    g_CurrentUsbRecvNode->next = NULL;
                    g_CurrentUsbRecvNode->dataLength = USB_HOST_SEND_RECV_PER_TIME;
                    USB_HostCdcDataRecv(g_cdc.classHandle, (uint8_t *)&g_CurrentUsbRecvNode->buffer[0],
                                  g_CurrentUsbRecvNode->dataLength, USB_HostCdcDataInCallback, &g_cdc);

                   }
                       }
               else
                 {
                   NoReceivCounter++;



                 }
              }
                }

                if (!g_UartSendBusy)
                {
                    if(g_UartSendQueue)
                      {
                g_UartSendNode = getNodeFromQueue(&g_UartSendQueue);

                if (g_UartSendNode)
                {
                 g_txfer.buffer = g_UartSendNode->buffer;
                 g_txfer.size = g_UartSendNode->dataLength;
                 g_UartSendBusy = 1;
                 USB_UartSendNonBlocking((USB_UartType *)BOARD_DEBUG_UART_BASEADDR, &g_UartHandle, &g_txfer);
                }
                    }
                }
                g_UartActive++;

                if (g_UartActive > USB_HOST_UART_RECV_TIMEOUT_THRSHOLD)
                {
                    g_UartActive = 0;

                    USB_BmEnterCritical(&usbOsaCurrentSr);
                    if ((g_CurrentUartRecvNode) && (g_CurrentUartRecvNode->dataLength))
                    {
                        insertNodeToQueue(&g_UsbSendQueue, g_CurrentUartRecvNode);
                        g_CurrentUartRecvNode = getNodeFromQueue(&g_EmptyQueue);
                    }
                    USB_BmExitCritical(usbOsaCurrentSr);
                }

            }
            }
         if (NoReceivCounter > 90000 )
         {
            USB_HostCdcInitBuffer();
            NoReceivCounter = 0;
            }
            break;

 It basically comes from the host_cdc.c File in the example. I added some if conditions and the reset part between Line 22 to 39 and bevor the break. This causes the Buffers to be reinitialised after a specific amount of NULL received. As far as I understand the Text the g_EmptySendQueue contains the data I get from the Stick via USB but I have basically no clue how it gets in this Buffer.

With this  I get the code running until I get an assertion error:

 

ASSERT ERROR " xfer->dataSize ": file "../drivers/fsl_uart.c" Line "715" function name "UART_TransferSendNonBlocking"

I think this comes from some Interrupts firing while doing the reinitialisation or because some Flags aren't reset and the Code thinks it still has to send the Data.   

 

But I get failures in USB_HostCdcDataRecv in usb_host_cdc.c

if (USB_HostMallocTransfer(cdcInstance->hostHandle, &transfer) != kStatus_USB_Success)
    {
#ifdef HOST_ECHO
        usb_echo("error to get transfer DataRecv\r\n");
#endif
        return kStatus_USB_Error;
    }

In the USB_HostMallocTransfer function the  Transfer Header seems to be missing. This error comes comes really really often, but when I "mute" it, it runs quite good. The amount of these messages scales witch the Counter NoReceivCounter and the Makro in host_cdc.h

 

/*! @brief buffer number used to data transfer */
#define USB_HOST_CDC_BUFFER_NUM 10U

 

Now I am wondering why do I have to reset the Buffers and how can I do it without causing the errors.

How exactly is the Data received? How does it get inside the Buffers?

And most important could someone give me a comment, who didn't had these kind of Problems? I have the feeling that it can't be this hard to get this running, it feels like maybe just some settings are wrong and now I try cure the symptoms but the sickness should be in plain sight.

Outcomes