我正在做一个项目,通过 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 必须首先将他连接为大容量存储,因为默认情况下它枚举为包含 Windows 驱动程序的 MSD。所以我将它作为 MSD 设备连接并发送“ModeSwitch”命令。Linux 用户将熟悉此过程。然后,Stick 会自行断开连接,并将被枚举为供应商特定设备(类:0xFF)。不幸的是,它不是 CDC 设备。好久不见,就像在 Linux 中一样,我现在可以通过终端(例如 MiniCom)发送 AT 命令。现在我的代码加载了它运行的 CDC-Component,就像从这一点开始的 CDC-Host 示例一样。我收到一些错误:
中断管道建立失败
线路状态为“ok”,但所有值均为零。
代码 10 的数据传输错误
从此时起,该示例本身并没有做任何可见的事情。经过一番尝试,我达到了可以运行的程度。它非常不稳定,但我想我找到了一些东西。问题似乎来自 Buffer 结构
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 管道和调试终端的数据。如您所见,它们是一种列表,包含缓冲区中的数据、缓冲区中的字节数和指向下一个列表元素的指针。
但是在某些时候下一个元素和当前元素是 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"
我认为这来自一些在重新初始化时触发的中断,或者因为一些标志没有被重置并且代码认为它仍然必须发送数据。
但是我在 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 函数中,似乎缺少传输标头。这个错误确实经常出现,但是当我“静音”它时,它运行得很好。这些消息的数量与计数器 NoReceivCounter 和 host_cdc.h 中的 Makro 成正比
/*! @brief buffer number used to data transfer */
#define USB_HOST_CDC_BUFFER_NUM 10U
我对USB不是很熟悉,接触Controllers才半年。所以任何信息都可以提供帮助。
现在我想知道为什么我必须重置缓冲区以及如何在不导致错误的情况下进行重置。
数据究竟是如何收到的?它是如何进入缓冲区的?我在代码中找不到任何相关内容。
我有一种感觉,让它运行起来并不难,感觉可能只是某些设置错误,现在我尝试治愈症状,但疾病应该是显而易见的。
这是我的第一篇文章,所以如果我错过了一些重要的信息,我很乐意提供给他们。
干杯
巴斯蒂安