我正在开展一个项目,通过USB将Hauwai E3531i-2 Surf Stick连接到frdmk64F板(来自NXP的Cortex M4的开发板),我遇到了CDC主机堆栈的困难。我的目标是通过USB端口发送像终端工具这样的AT命令。出于测试目的,并且因为在示例中,所有数据都被流式传输到我的计算机上的终端(Putty / Terra Term / HTerm)。我也从哪里发送数据。
我正在使用Kinetis Design Studio(KDS)3.2和Kinetis Software Develpment Kid(KSDK)2.2并获得USB-Host BM示例CDC和MSD运行并修改它们以达到我的目的。我重写了枚举过程,因此我可以自动区分不同的类,并相应地执行Init和Task。
使用此Stick时,首先需要将其连接为Mass Storage,因为默认情况下它会枚举为包含Windows驱动程序的MSD。所以我将它作为MSD设备连接并发送“ModeSwitch”命令。 Linux用户将熟悉此过程。然后Stick断开连接并将枚举为供应商特定设备(类:0xFF)。不幸的是,不作为CDC设备。这么好,就像在Linux中那样我现在可以通过终端发送AT命令,例如MINICOM。现在,我的代码加载了它运行的CDC-Component,就像此时的CDC-Host示例一样。我收到了一些错误:
中断管道无法建立
线路状态为“ok”,但所有值均为零。
代码为10的数据传输错误
从这一点开始,这个例子本身并没有做任何可见的事情。经过一番尝试,我得到了一个让我有点跑步的地步。它非常不稳定,但我想我找到了一些东西。问题似乎来自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;
和相应的变量
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;
在本例中,它们用于存储USB管道和调试终端的数据。如您所见,它们是一种List,包含缓冲区中的数据,缓冲区中的字节数和指向下一个List元素的指针。
但是在某些时候,下一个元素和当前元素是NULL,从这一点开始我不能再收到任何消息了。重置缓冲区会有所帮助,但这会导致其他错误。这是我运行的代码。
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;
它基本上来自示例中的host_cdc.c文件。我在第22行到第39行之间添加了一些if条件和重置部分并且休息了。这会导致在收到特定数量的NULL后重新初始化缓冲区。据我所知,文本g_EmptySendQueue包含我通过USB从Stick获得的数据,但我基本上不知道它是如何进入这个缓冲区的。
有了这个,我得到代码运行,直到我收到断言错误:
ASSERT ERROR " xfer->dataSize ": file "../drivers/fsl_uart.c" Line "715" function name "UART_TransferSendNonBlocking"
我认为这是因为在重新初始化时发生了一些中断,或者因为某些Flags没有重置而且Code认为它仍然必须发送数据。
但是我在usb_host_cdc.c中的USB_HostCdcDataRecv中失败了
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;
}
在USB_HostMallocTransfer功能中,传输标题似乎丢失了。这个错误真的经常发生,但是当我“静音”它时,它运行得非常好。这些消息的数量可以通过host_cdc.h中的Counter NoReceivCounter和Makro进行扩展。
/*! @brief buffer number used to data transfer */
#define USB_HOST_CDC_BUFFER_NUM 10U
我对USB不是很熟悉,并且半年来一直与控制器合作。所以任何信息都可以提供帮助。
现在我想知道为什么我必须重置缓冲区以及如何在不造成错误的情况下执行此操作。
收到的数据究竟如何?如何进入缓冲区?我在代码中找不到任何相关内容。
我觉得让这种情况变得困难并不是很难,感觉可能只是一些设置是错误的,现在我尝试治愈症状,但疾病应该是明显的。
这是我的第一篇文章,所以如果我错过了一些重要的信息,我很乐意为他们提供。
干杯
的Bastian