请选择 进入手机版 | 继续访问电脑版
查看: 175|回复: 2

[原创] Kinetis/LPC MCU实现WinUSB免驱设备

[复制链接]

该用户从未签到

13

主题

40

帖子

0

金豆

中级会员

Rank: 3Rank: 3

积分
304
最后登录
2021-1-8
发表于 2020-10-30 22:42:56 | 显示全部楼层 |阅读模式
本帖最后由 lszisgood 于 2020-10-31 10:56 编辑

Kinetis/LPC MCU实现WinUSB免驱设备

在Windows操作系统下,除了USB HID设备,其他类型的USB设备需要安装内核驱动程序。但USB HID设备Interrupt Type中断传输端点速度慢。如果使用Bulk Type批量传输端点时需要自己开发USB内核驱动,并申请Windows 驱动程序签名,开发难度非常大。
为了简化USB设备开发,微软开发了WinUSB,可以将Winusb.sys作为设备功能驱动程序安装,并提供WinUSB API供应用程序访问设备。支持WinUSB的设备,在Win8之前不用编写内核驱动程序,只需要编写inf文件,匹配设备。在Win8之后,如果USB设备支持WCID((Windows Compatible ID),则不需要inf文件,实现完全免驱动。
下面将介绍如何在MCUXpresso SDK USB Stack基础上实现WinUSB功能,让Kinetis/LPC/I.MX RT MCU在Windows上实现免驱即插即用。
要符合WinUSB的要求, 需要修改MCUXpressoSDK USB Stack,满足以下 3 项:

1. 响应字符串描述符请求,返回索引 0xEE的 OS 字符串描述符
#define bMS_VendorCode             ( 0xA0 )
//"MSFT100" : index : 0xEE : langId : 0x0000
uint8_tOS_StringDescritpor[ ] =
{0x12, 0x03, 'M', 0, 'S', 0, 'F', 0, 'T', 0, '1', 0, '0', 0, '0', 0,  bMS_VendorCode, 0 };

处理 USB 字符串描述符请求时, 当字符串索引wIndex==0xEE时, 返回OS_StringDescritpor响应字符串描述符。返回这个描述符后,USB设备被识别为WCID设备。
请注意,Windows只会在USB设备第一次连接后发送获取OS字符串描述符的请求,索引为0xEE 。OS描述符存储在注册表中HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\UsbFlags\VVVVPPPPRRRR(VVVV- VID; PPPP - PID; RRRR - 版本号)。在开发过程中如果无法正确识别为WCID设备,请删除USB设备对应的注册表项,然后在设备管理器中卸载USB设备,以便始终获得新的设备插入行为。

2. 响应VendorRequest厂商自带定义请求,bRequest请求号为OS字符描述符定义的bMS_VendorCode值(本例程为0xA0)。如果bRequest== 0xA0 && wIndex == 0x04,返回WCID扩展兼容特征描述符:“WINUSB”。
//"WINUSB\0\0" : wIndex : 0x0004
uint8_tWINUSB_ExtendedCompatId_Descritpor[ ] =
{
  0x28,0x00, 0x00, 0x00,                         // dwLength
  0x00,0x01,                                    // bcdVersion
  0x04,0x00,                                    // wIndex
  0x01,                                         // bCount
  0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00,       // Reserved[7]
  0x00,                                         //bFirstInterfaceNumber
  0x01,                                         // RESERVED ( 0x01 )
  'W','I', 'N', 'U', 'S', 'B', 0x00, 0x00,       //compactiableID[8]
  0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // subCompactiableID[8]
  0x00,0x00, 0x00, 0x00, 0x00, 0x00             // Reserved[6]
};
3. 响应VendorRequest厂商自带定义请求,bRequest请求号为OS字符描述符定义的bMS_VendorCode值(本例程为0xA0)。如果bRequest== 0xA0 && wIndex == 0x05,返回设备接口 GUID描述符:WINUSB_ExtendedProperty_InterfaceGUID_Descritpor。该描述符用于区分不同的WinUSB设备。
//L"DeviceInterfaceGUID" : wIndex = 0x0005
// L"{1D4B2365-4749-48EA-B38A-7C6FDDDD7E26}"
//
uint8_tWINUSB_ExtendedProperty_InterfaceGUID_Descritpor[ ] =
{  
///////////////////////////////////////
  /// WCID property descriptor
  ///////////////////////////////////////
  0x8e, 0x00, 0x00, 0x00,                           /* dwLength */
  0x00, 0x01,                                        /* bcdVersion */
  0x05, 0x00,                                        /* wIndex */
  0x01, 0x00,                                        /* wCount */
  ///////////////////////////////////////
  /// registry propter descriptor
  ///////////////////////////////////////
  0x84, 0x00, 0x00, 0x00,                           /* dwSize */
  0x01, 0x00, 0x00, 0x00,                           /*dwPropertyDataType */
  0x28, 0x00,                                        /* wPropertyNameLength */
  /* DeviceInterfaceGUID */
  'D', 0x00, 'e', 0x00, 'v', 0x00, 'i',0x00,       /* wcName_20 */
  'c', 0x00, 'e', 0x00, 'I', 0x00, 'n',0x00,       /* wcName_20 */
  't', 0x00, 'e', 0x00, 'r', 0x00, 'f',0x00,       /* wcName_20 */
  'a', 0x00, 'c', 0x00, 'e', 0x00, 'G',0x00,       /* wcName_20 */
  'U', 0x00, 'I', 0x00, 'D', 0x00, 0x00,0x00,      /* wcName_20 */
   0x4e, 0x00,0x00, 0x00,                            /* dwPropertyDataLength */
   /* {7D9ADCFC-E570-4B38-BF4E-8F81F68964E0}*/
  '{', 0x00, '7', 0x00, 'D', 0x00,'9', 0x00,       /* wcData_39 */
  'A', 0x00, 'D', 0x00, 'C', 0x00,'F', 0x00,       /* wcData_39 */
  'C', 0x00, '-',0x00, 'E', 0x00, '5', 0x00,       /*wcData_39 */
  '7', 0x00, '0', 0x00, '-', 0x00, '4',0x00,       /* wcData_39 */
  'B', 0x00, '3', 0x00, '8', 0x00, '-',0x00,       /* wcData_39 */
  'B', 0x00, 'F', 0x00, '4', 0x00, 'E', 0x00,       /* wcData_39 */
  '-', 0x00, '8', 0x00, 'F', 0x00, '8',0x00,       /* wcData_39 */
  '1', 0x00, 'F', 0x00, '6', 0x00, '8',0x00,       /* wcData_39 */
  '9', 0x00, '6', 0x00, '4', 0x00, 'E',0x00,       /* wcData_39 */
  '0', 0x00, '}', 0x00, 0x00, 0x00,                  /* wcData_39 */
4. 修改MCUXpressoSDK USB例程,支持WinUSB。
NXP的MCUXpresso SDK USB例程 dev_printer_virtual_plain_text_bm原本是一个打印机例程,包含二个Bulk批量传输端点。可以在这个例程基础之上快速修改支持WinUSB功能。

  修改下面宏定义,将打印机设备宏定义修改用户自定义协议WinUSB设备。
#defineUSB_DEVICE_DEMO_BCD_VERSION (0x0200U)

#defineUSB_DEVICE_STRING_COUNT (4U)

#defineUSB_PRINTER_CLASS    (0xFFU)
#defineUSB_PRINTER_SUBCLASS (0xFFU)
#defineUSB_PRINTER_PROTOCOL (0x00U)

#defineUSB_DEVICE_CONFIG_PRINTER_CLASS_CODE (0xFFU)
在USB协议栈描述请求中增加VendorRequest厂商自带定义请求处理代码:
/* Getdevice string descriptor request */
usb_status_tUSB_DeviceGetStringDescriptor(usb_device_handle handle,
                                      usb_device_get_string_descriptor_struct_t*stringDescriptor)
{
    uint8_t languageIndex = 0U;
    uint8_t stringIndex   = USB_DEVICE_STRING_COUNT;

    if (stringDescriptor->stringIndex == 0U)
    {
        stringDescriptor->buffer = (uint8_t*)g_UsbDeviceLanguageList.languageString;
        stringDescriptor->length =g_UsbDeviceLanguageList.stringLength;
    }else if(stringDescriptor->stringIndex == 0xEE) // OSString
    {
        stringDescriptor->buffer = (uint8_t*)OS_StringDescritpor;
        stringDescriptor->length =OS_StringDescritpor[0];
    }else
    {
       …………………………………………
       …………………………………………
    }
    return kStatus_USB_Success;
}

staticusb_status_t USB_DeviceCallback(usb_device_handle handle, uint32_t event, void*param)
{
…………………………………………
    switch (event)
    {
…………………………………………
…………………………………………
        case kUSB_DeviceEventVendorRequest:
            if (param)
            {
                status =USB_HandleVendorRequest(handle, event, param);
            }
           break;
        default:
            break;
    }
    return status;
}

usb_status_tUSB_HandleVendorRequest(usb_device_handle handle, uint32_t event, void *param)
{
    usb_status_t error = kStatus_USB_Success;
    uint8_t* pFlash;

    /* Handle the vendor specific request. */
    usb_device_control_request_struct_t*controlRequest = (usb_device_control_request_struct_t *)param;

    if (controlRequest->setup->bRequest== WCID_VENDOR_CODE)
    {
       switch(controlRequest->setup->wIndex)
        {
        case 4:
            controlRequest->buffer =(uint8_t*)WINUSB_ExtendedCompatId_Descritpor;
            controlRequest->length =USB_LEN_OS_FEATURE_DESC;
            break;
        case 5:
            controlRequest->buffer =(uint8_t*)WINUSB_ExtendedProperty_InterfaceGUID_Descritpor;
            controlRequest->length =USB_LEN_OS_PROPERTY_DESC;
            break;
        default:
            error = kStatus_USB_InvalidRequest;
            break;
        }
    }
    return error;
}


正确响应上述三个描述符请求后,就可以成功枚举为WinUSB设备。在Windows设备管理器中可以看到WinUSB设备工作正常:
5. WinUSB配套测试上位机软件。
微软官方提供了PC测操作WinUSB设备的示例代码。与之前通过VID/PID打开USB设备句柄不一样,上位机程序通过设备GUID参数获取WinUSB设备句柄。需要与嵌入式设备的描述符中的GUID保持一致。
调用 SetupDiGetClassDevs 获取设备信息集的句柄;调用SetupDiEnumDeviceInterfaces 枚举设备信息并获取有关设备接口的信息;调用WinUsb_Initialize创建的文件句柄。WinUsb_ReadPipe 从设备的批量输入端点读取数据。调用 WinUsb_WritePipe 通过批量输出端点将数据写入设备。最后WinUsb_Free释放由 WinUsb_Initialize 获得的WinUSB 接口句柄。
KEIL uVision5 安装目录自带了WinUSB上位机测试工具,支持中断传输,批量传输和控制传输。提供了Visual Studio VC++源代码工程,用户可以在此基础上实现自己的上位机软件。可参考KEIL网页(https://www.keil.com/pack/doc/mw/USB/html/dev_cc_tutorial.html)了解更多细节。The example can be tested on a Windows PC using theWinUSB_Test.exe utility provided with MDK Middleware. The program runsstand-alone without installation. Simply run"install_dir\ARM\PACK\Keil\MDK-Middleware\x.y.z\Utilities\WinUSB_Test\Release\WinUSB_Test.exe"application (where x >= 7, y >= 5, z >= 0):


Kinetis LPC MCU实现WinUSB免驱设备.pdf

420.21 KB, 下载次数: 14, 下载积分: 威望 1

Kinetis/LPC MCU实现WinUSB免驱设备

FRDM_K64_WinUSB.rar

1.4 MB, 下载次数: 20, 下载积分: 威望 1

FRDM_K64 WinUSB测试代码

WinUSB_Test.rar

1.33 MB, 下载次数: 13, 下载积分: 威望 1

WinUSB上位机测试工具

回复

使用道具 举报

  • TA的每日心情
    擦汗
    2016-12-2 08:40
  • 签到天数: 3 天

    [LV.2]偶尔看看I

    60

    主题

    541

    帖子

    7

    金豆

    金牌会员

    Rank: 6Rank: 6

    积分
    2009
    最后登录
    2021-1-26
    发表于 2020-10-31 12:16:22 | 显示全部楼层
    厉害了
    回复

    使用道具 举报

  • TA的每日心情
    开心
    11 小时前
  • 签到天数: 465 天

    [LV.9]以坛为家II

    38

    主题

    1197

    帖子

    12

    金豆

    版主

    Rank: 7Rank: 7Rank: 7

    积分
    2649
    最后登录
    2021-1-26
    发表于 2020-10-31 12:59:25 | 显示全部楼层
    学习了。
    一直想了解这方面的知识。
    今天天气不错!签到!
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    关闭

    站长推荐上一条 /2 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2021-1-26 20:34 , Processed in 0.082590 second(s), 18 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2020, Tencent Cloud.

    快速回复 返回顶部 返回列表