这是我上一个问题的后续,需要为USB外围设备编写驱动程序吗?。
背景
我正在设计一个使用STM32微控制器(裸金属/无操作系统)的USB外围设备。该设备偶尔会连接到Windows,并在每个方向传输几KB的数据。将有一个自定义PC应用程序来控制数据传输,使用专有协议(即USB有效载荷)。
PC将永远是主(启动器)-它将发送命令,设备将发出响应,多达几百字节的数据在一个单一的命令或响应中向任意方向移动。我想我会想要使用USB批量传输模式。
选项1- USB CDC
据我所知,一个选择是我可以使用USB通信设备类(CDC)。在设备端,我可以为USB使用ST的示例代码,例如来自STM32Cube的示例代码。在PC端,该设备将呈现为虚拟COM端口(VCP)。然后,在软件中,我基本上有一个原始的双向流,在这个流之上,我必须定义我的消息格式、命令等等。
备选方案2- WinUSB
我很难想清楚这到底是什么,以及如何处理它。
选择
发布于 2016-08-12 04:11:50
WinUSB_WritePipe
以单一的USB传输方式发送数据。在USB规范中,传输具有特定的定义。您可以知道传输何时结束,因为您将在传输结束时得到一个短数据包。短数据包是小于端点的最大数据包大小的数据包,它可能是零长度。但是,您应该再次检查这是否是真的;尝试发送一个最大数据包大小倍数的传输,并确保Windows在该传输结束时发送一个零长度数据包。顺便说一句,您应该考虑在端点0上将数据作为控件传输或一系列控件传输发送。控制权转移有一个内置的请求概念和对请求的响应。尽管名称,控制传输可以用来传输大量的数据;它们通常在USB引导程序中使用(参见DFU类)。使用控制传输而不是非零端点的另一个优点是,您不必在固件中添加额外的端点描述符并初始化端点。您的USB堆栈应该有处理自定义控制传输的机器,并且您应该能够通过编写一些回调函数来进行自定义控制传输。发布于 2018-02-18 00:45:07
WinUSB由两部分组成:
要在应用程序中使用WinUSB API,请执行以下操作:
对于更高级的解决方案--使用函数:
出于调试目的,您可能需要: winusbtrace_tool https://blogs.msdn.microsoft.com/usbcoreblog/2010/02/05/how-to-generate-and-view-a-winusb-debug-trace-log/;带有USBPcap插件的Wireshark https://www.wireshark.org。
其他例子:http://searchingforbit.blogspot.com/2012/04/winusb-communication-with-stm32-part-1.html。示例模板随Visual一起提供。
您还需要掌握编写.inf文件的知识。
另一种与USB - libusb-win32 32 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; }
}
发布于 2018-05-24 13:45:16
我还必须做您完全相同的要求: PC <==> STM
微软有很多关于WinUSB的文档。这是我看到的回答你问题的东西..。
自定义USB设备示例
https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomUsbDeviceAccess
开发用于USB设备的Windows应用程序-- C#和VB
用于USB设备的Windows桌面应用程序
如何使用WinUSB函数访问USB设备
为USB主机控制器开发Windows驱动程序
Windows.Devices.Usb Windows.Devices.Usb命名空间
https://learn.microsoft.com/en-us/uwp/api/windows.devices.usb
https://stackoverflow.com/questions/38906880
复制相似问题