cp.*_*ngr 8 usb cdc stm32 winusb
这是我上一个问题的后续,需要为 USB 外围设备编写驱动程序吗?
我正在使用 STM32 微控制器(裸机/无操作系统)设计 USB 外围设备。该设备偶尔会连接到 Windows PC,并在每个方向传输几 KB 的数据。将有一个定制的 PC 应用程序来控制数据传输,使用专有协议(即 USB 有效负载)。
PC 将始终是主机(启动器)——它将发送命令,设备将发出响应,在单个命令或响应中的任一方向最多有几百字节的数据。我想我会想使用 USB 批量传输模式。
据我了解,一种选择是我可以使用 USB 通信设备类 (CDC)。在设备端,我可以使用来自 ST 的示例代码用于 USB CDC,例如来自STM32Cube。在 PC 端,设备将显示为虚拟 COM 端口 (VCP)。然后在软件中,我基本上有一个原始的双向流,在此之上我必须定义我的消息格式、命令等。
我在思考这到底是什么以及如何使用它时遇到了麻烦。
WinUSB 与 USB 设备类的关系是什么?它似乎充当“通用”USB 类,但我找不到任何说明它的文档。
WinUSB 是否提供任何内置的消息分隔符?例如,WinUsb_WritePipe是否将缓冲区的内容作为原子单元发送到设备?或者我只是获得像 VCP/UART 这样的原始流?
如何在设备上实现 WinUSB?有可用的示例代码吗?(最好是 STM32。)
WinUSB 由两部分组成:
在应用程序中使用 WinUSB API:
对于更高级的解决方案 - 使用函数:
出于调试目的您可能需要: winusbtrace_tool https://blogs.msdn.microsoft.com/usbcoreblog/2010/02/05/how-to-generate-and-view-a-winusb-debug-trace-log/;Wireshark https://www.wireshark.org带有 USBPcap 插件。
其他示例:http : //searchingforbit.blogspot.com/2012/04/winusb-communication-with-stm32-part-1.html。示例模板随 Visual Studio 一起提供。
您还需要具备编写 .inf 文件的知识。
另一种与 USB 通信的简单方法 - libusb-win32 https://sourceforge.net/projects/libusb-win32/
我的简单示例控制台应用程序向设备发送小(保持活动)数据块:
#include "stdafx.h"
#include <SetupAPI.h>
#include <Hidsdi.h>
#include <devguid.h>
#include <winusb.h>
#include <usb.h>
#pragma comment(lib, "hid.lib")
#pragma comment(lib, "setupapi.lib")
#pragma comment(lib, "winusb.lib")
#include <iUString.h>
iString<char> DevicePath;
bool WinusbHandle_Open=false;
bool DeviceHandle_Open = false;
WINUSB_INTERFACE_HANDLE WinusbHandle;
HANDLE DeviceHandle;
UCHAR usb_out_buffer[64];
DEFINE_GUID(GUID_DEVCLASS_WINUSB, 0x88bae032L, 0x5a81, 0x49f0, 0xbc, 0x3d, 0xa4, 0xff, 0x13, 0x82, 0x16, 0xd6);
DEFINE_GUID(GUID_DEVCLASS_STL, 0xf177724dL, 0x74d3, 0x430e, 0x86, 0xb5, 0xf0, 0x36, 0x89, 0x10, 0xeb, 0x23);
GUID winusb_guid;
GUID stl_guid;
bool connectusb();
void disconnectusb();
int main()
{
DWORD n;
DWORD numEvents;
HANDLE rHnd;
WinusbHandle_Open = false;
DeviceHandle_Open = false;
winusb_guid = GUID_DEVCLASS_WINUSB;
stl_guid = GUID_DEVCLASS_STL;
usb_out_buffer[0] = 0;
usb_out_buffer[1] = 1;
usb_out_buffer[2] = 2;
usb_out_buffer[3] = 3;
ULONG bytesWritten;
ULONG timeout;
timeout = 100;
rHnd = GetStdHandle(STD_INPUT_HANDLE);
WinUsb_SetPipePolicy(WinusbHandle, 0x01, PIPE_TRANSFER_TIMEOUT, sizeof(ULONG), &timeout);
timeout = TRUE;
WinUsb_SetPipePolicy(WinusbHandle, 0x01, AUTO_CLEAR_STALL, sizeof(ULONG), &timeout);
timeout = TRUE;
WinUsb_SetPipePolicy(WinusbHandle, 0x01, RAW_IO, sizeof(ULONG), &timeout);//Bypasses queuing and error handling to boost performance for multiple read requests.
while (true)
{
if ((!WinusbHandle_Open) || (!WinusbHandle_Open)) { if (!connectusb())Sleep(2000); }
if ((!WinusbHandle_Open) || (!WinusbHandle_Open))continue;
bytesWritten = 0;
if (!WinUsb_WritePipe(WinusbHandle, 0x01, &usb_out_buffer[0], 2, &bytesWritten, NULL))
{
n = GetLastError();
disconnectusb();
}
Sleep(2000);
}
disconnectusb();
return 0;
}
bool connectusb()
{
BOOL bResult = FALSE;
HDEVINFO deviceInfo;
SP_DEVICE_INTERFACE_DATA interfaceData;
PSP_DEVICE_INTERFACE_DETAIL_DATA detailData = NULL;
DWORD n;
SP_DEVINFO_DATA devinfo;
BYTE devdetailbuffer[4096];
bool found;
deviceInfo = SetupDiGetClassDevs(&stl_guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (deviceInfo == INVALID_HANDLE_VALUE) { return false; }
found = false;
for (n = 0;; n++)
{
interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
if (!SetupDiEnumDeviceInterfaces(deviceInfo, NULL, &stl_guid, n, &interfaceData))
{
n = GetLastError();
break;
}
detailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)devdetailbuffer;
detailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
devinfo.cbSize = sizeof(devinfo);
if (!SetupDiGetDeviceInterfaceDetail(deviceInfo, &interfaceData, detailData, sizeof(devdetailbuffer), NULL, &devinfo)) { printf("SetupDiGetDeviceInterfaceDetail: %u\n", GetLastError()); break; }
if (IsEqualGUID(devinfo.ClassGuid, winusb_guid))
{
if ((-1 != iStrPos(detailData->DevicePath, "VID_0483")) || (-1 != iStrPos(detailData->DevicePath, "vid_0483")))
{
if ((-1 != iStrPos(detailData->DevicePath, "PID_576B")) || (-1 != iStrPos(detailData->DevicePath, "pid_576b")))
{
DevicePath = detailData->DevicePath;
found = true;
break;
}
}
}
}
SetupDiDestroyDeviceInfoList(deviceInfo);
if (!found)return false;
DeviceHandle = CreateFile(DevicePath.Buffer() ,
GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL);
if (INVALID_HANDLE_VALUE == DeviceHandle) {
n = GetLastError();
}
if (INVALID_HANDLE_VALUE == DeviceHandle) return false;
DeviceHandle_Open = true;
if (!WinUsb_Initialize(DeviceHandle, &WinusbHandle))
{
n = GetLastError();
CloseHandle(DeviceHandle); DeviceHandle_Open = false;
return false;
}
WinusbHandle_Open = true;
return true;
}
void disconnectusb()
{
if (WinusbHandle_Open) { WinUsb_Free(WinusbHandle); WinusbHandle_Open = false; }
if (DeviceHandle_Open) { CloseHandle(DeviceHandle); DeviceHandle_Open = false; }
}
Run Code Online (Sandbox Code Playgroud)
WinUSB_WritePipe
将数据作为单个 USB传输发送。一次转会在 USB 规范中有特定的定义。您可以判断传输何时结束,因为您会在传输结束时收到一个短数据包。短数据包是小于端点的最大数据包大小的数据包,它可能是零长度的。不过,您应该仔细检查这是否确实如此;尝试发送一个最大数据包大小倍数的传输,并确保 Windows 在其末尾发送一个零长度数据包。顺便说一下,您应该考虑在端点 0 上将数据作为控制传输或一系列控制传输发送。控制传输具有请求和对请求的响应的内置概念。尽管名称如此,但控制传输可用于传输大量数据;它们通常用于 USB 引导加载程序(请参阅 DFU 类)。使用控制传输而不是非零端点的另一个优点是您不必添加额外的端点描述符并在固件中初始化端点。您的 USB 堆栈应该具有处理自定义控制传输的机制,并且您应该能够仅通过编写一些回调函数来进行自定义控制传输。 归档时间: |
|
查看次数: |
11470 次 |
最近记录: |