wdm设备驱动程序开发pdf_灵动微课堂(第106讲) | MM32 USB功能学习笔记 —— WinUSB设备...

本文介绍了如何利用MM32 MCU的WinUSB功能在Win10系统上实现免驱设备,讲解了WinUSB设备的概念、Windows系统对WinUSB的支持,以及如何通过修改设备描述符实现WCID支持。通过示例代码展示了MM32 MCU WinUSB的初始化和数据传输,并提供了USB调试工具的使用方法,验证了数据通信的正常性。
摘要由CSDN通过智能技术生成

万事大吉 年年有余

在上一节我们介绍了 MM32 MCU 的 HID 功能,对于HID 来说,虽然免驱,但是速度相对慢,有没有更好的选择呢?当然有,那就是WinUSB ,速度更快,对于现在的 PC 来说,基本上都是  Win10 ,WinUSB 在 Win10 免驱,此节我们就介绍如何使用 MM32 MCU的 WinUSB 功能。

WinUSB 设备是一种通用串行总线 (USB) 设备,其固件定义了某些 Microsoft 操作系统 (OS) 特征描述符,这些描述符将兼容 ID 报告为 "WINUSB"。

WinUSB 设备的用途是让 Windows 将 Winusb.sys 作为设备的功能驱动程序载入,而无需自定义 INF 文件。对于 WinUSB 设备,你无须为设备分发 INF 文件,对最终用户而言,这大大简化了驱动程序安装过程。相反,如果你需要提供自定义 INF,则不应将设备定义为 WinUSB 设备和在 INF 中指定设备的硬件 ID。

通常USB自定义设备都需要用户自己开发驱动,为了免去USB驱动开发,减少用户开发时间,微软花了不少心思,在Win8 或更高版本的Windows 系统中,集成了WinUSB 的WCID设备,从而WinUSB 作为微软提供的一个USB设备的通用驱动程序提供给用户,通过使用这个驱动,用户不再需要编写内核层的驱动程序就能够访问到USB设备。WCID是USB驱动一种新的匹配机制,在2012年左右引入的,通常USB设备都是通过VID和PID来进行匹配的,然而使用了WCID之后,USB设备不再通过VID和PID来匹配驱动,而是通过一个叫做兼容ID(Windows Compatible ID)来匹配,这样用户就不用为每一个VID和PID不同的设备编写INF文件了。当然我们要注意到,这里所说的免驱动包含两层含义:一层是用户不需要编写驱动程序,系统自带了驱动程序,只需写一个INF文件,比如USB串口;另一层则是不需要编写INF文件,系统会根据设备类型来安装驱动,这需要操作系统的支持。对于WinUSB设备来说,在Win8之前不用编写驱动程序,但是需要编写INF文件,匹配设备。在Win8之后,如果设备支持WCID,连INF也不用编写。

 

0b0d0823db84a0bd3a7c8cdd713bda97.png

图1  WinUSB配置

下面将介绍如何在设备中增加对WCID的支持,让在能在Win8之后的系统上实在真正免驱即插即用。

首先我们得要有一个能够使用起来的自定义设备,在这个设备的设备描述符中,USB版本号设置为2.00,在这个设备的基础之上进行如下的修改:

修改一:响应ID为0xEE的字符描述符请求,字符描述的内容为:

{

0x12,                                       /* bLength */

USB_STRING_DESCRIPTOR_TYPE,          /* bDescriptorType */

'M', 0x00,                                    /* wcChar0 */

'S', 0x00,                                    /* wcChar1 */

'F', 0x00,                                    /* wcChar2 */

'T', 0x00,                                    /* wcChar3 */

'1', 0x00,                                    /* wcChar4 */

'0', 0x00,                                    /* wcChar5 */

'0', 0x00,                                    /* wcChar6 */

0x17,                                       /* bVendorCode */

0x00,                                       /* bReserved */

}

修改一:是为了让我们的自定设备被识别为WCID设备。

修改二:响应请求号为0x17并且index为4的厂商自定义请求,返回内容为:

{

0x28, 0x00, 0x00, 0x00,                       /* dwLength */

0x00, 0x01,                                  /* bcdVersion */

0x04, 0x00,                                  /* wIndex */

0x01,                                        /* bCount */

0,0,0,0,0,0,0,                                 /* Reserved */

/* WCID Function  */

0x00,                                        /* bFirstInterfaceNumber */

0x01,                                        /* bReserved */

/* CID */

'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00, 

/* sub CID */

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 

0,0,0,0,0,0,                                  /* Reserved */

}

修改二是为了向 Windows 系统上报我们 USB 设备的 WCID 值,因为我们需要的是 WinUSB 的驱动程序,所以我们上报的内容信息就是 WinUSB 驱动的 WCID : “WINUSB” 。在修改上述内容完成后,将 MM32 MCU 的 USB 插入电脑,会发现设备能够自动安装上 WinUSB 驱动程序,然后显示如下所示:

a34fee2f65ad5bfc94b4c3f7abba1845.png

图2  WinUSB驱动程序

本次我们采用MM32L373 miniboard作为测试开发板。为了方便大家使用MM32 MCU的WinUSB功能,我们已经封装好全部代码,用户不需要自己配置以上的那些描述符等参数,只需要了解MM32 MCU WinUSB的VID和PID以及如何处理WinUSB的数据接收和发送即可。

对于MM32 MCU的WinUSB功能来说,在使用WinUSB功能之前先调用USB初始化函数来初始化USB协议栈。

int main(void)

{

// USB Device Initialization and connect

usbd_init();

usbd_connect(__TRUE);

while (!usbd_configured())   // Wait for USB Device to configure

{

}

while (1)

{      

}

}

然后就是 WinUSB 数据收发处理函数, USB 数据处理函数如下 :

static U8 *ptrDataIn;

static U16 DataInReceLen;

static Bulk_queue Bulk_Cmd_queue;

static volatile uint8_t  USB_ResponseIdle;

void usbd_bulk_init(void)

{

ptrDataIn = USBD_Bulk_BulkOutBuf;

DataInReceLen = 0;

Bulk_queue_init(&Bulk_Cmd_queue);

USB_ResponseIdle = 1;

}

/*

 *  USB Device Bulk In Endpoint Event Callback

 *    Parameters:      event: not used (just for compatibility)

 *    Return Value:    None

 */

void USBD_BULK_EP_BULKIN_Event(U32 event)

{

uint8_t * sbuf = 0;

int slen;

if(Bulk_queue_get_send_buf(&Bulk_Cmd_queue, &sbuf, &slen)){

USBD_WriteEP(usbd_bulk_ep_bulkin | 0x80, sbuf, slen);

} else {

USB_ResponseIdle = 1;

}

}

/*

 *  USB Device Bulk Out Endpoint Event Callback

 *    Parameters:      event: not used (just for compatibility)

 *    Return Value:    None

*/

void USBD_BULK_EP_BULKOUT_Event(U32 event)

{    

U16 bytes_rece;

uint8_t * rbuf;

bytes_rec = USBD_ReadEP(usbd_bulk_ep_bulkout, ptrDataIn, USBD_Bulk_BulkBufSize - DataInReceLen);

ptrDataIn += bytes_rece;

DataInReceLen  += bytes_rece;

if ((DataInReceLen >= USBD_Bulk_BulkBufSize) ||

(bytes_rece

if(Bulk_queue_execute_buf(&Bulk_Cmd_queue,USBD_Bulk_BulkOutBuf, DataInReceLen, &rbuf)) {

//Trigger the BULKIn for the reply

if (USB_ResponseIdle) {

USBD_BULK_EP_BULKIN_Event(0);

USB_ResponseIdle = 0;

}

}

//revert the input pointers

DataInReceLen = 0;

ptrDataIn = USBD_Bulk_BulkOutBuf;

}

}

/*

 *  USB Device Bulk In/Out Endpoint Event Callback

 *    Parameters:      event: USB Device Event

 *                       USBD_EVT_OUT: Output Event

 *                       USBD_EVT_IN:  Input Event

 *    Return Value:    None

*/

void USBD_BULK_EP_BULK_Event(U32 event)

{

if (event & USBD_EVT_OUT) {

USBD_BULK_EP_BULKOUT_Event(0);

}

if (event & USBD_EVT_IN) {

USBD_BULK_EP_BULKIN_Event(0);

}

}

void Bulk_queue_init(Bulk_queue *queue)

{

queue->recv_idx = 0;

queue->send_idx = 0;

queue->free_count = FREE_COUNT_INIT;

queue->send_count = SEND_COUNT_INIT;

}

BOOL Bulk_queue_get_send_buf(Bulk_queue *queue, uint8_t **buf, int *len)

{

if (queue->send_count)

{

queue->send_count--;

*buf = queue->USB_Request[queue->send_idx];

*len = queue->resp_size[queue->send_idx];

queue->send_idx = (queue->send_idx + 1) % Bulk_PACKET_COUNT;

queue->free_count++;

return (__TRUE);

}

return (__FALSE);

}

BOOL Bulk_queue_execute_buf(Bulk_queue *queue, const uint8_t *reqbuf, int len, uint8_t **retbuf)

{

uint32_t rsize;

if (queue->free_count > 0)

{

if (len > Bulk_PACKET_SIZE)

{

len = Bulk_PACKET_SIZE;

}

queue->free_count--;

memcpy(queue->USB_Request[queue->recv_idx], reqbuf, len);

rsize = Bulk_ExecuteCommand(reqbuf, queue->USB_Request[queue->recv_idx]);

queue->resp_size[queue->recv_idx] = rsize & 0xFFFF; //get the response size

*retbuf = queue->USB_Request[queue->recv_idx];

queue->recv_idx = (queue->recv_idx + 1) % Bulk_PACKET_COUNT;

queue->send_count++;

return (__TRUE);

}

return (__FALSE);

}

如上,我们只需要实现修改如下 Bulk_ExecuteCommand 即可处理我们收到的收据,并且填入我们发送数据出去队列即可发送出去。  

为了验证MM32 MCU WinUSB功能,使用如下测试工具测试通信情况。

9718790ad53504f51b0878f284aa1de8.png

图3  USB调试工具

在VID栏填入我们MM32 MCU WinUSB的VID号0x2F81,点击Refresh刷新即可识别,点击OK就可以打开WinUSB。在图上可以看到有输入输出端点,我们MM32 MCU WinUSB采用的的端点EP3来收发数据,填入数据收发如下:

bee7cefef319394291940ac70912d569.png

图4  USB数据通信

发送端填入01 02 03 04 05 06 07 08 09,点击Send发送,接收端收到01 ff数据,测试结果说明我们的MM32 MCU的WinUSB数据通信正常。

  以上就是 MM32 MCU USB 的 WinUSB 功能,下一节我们继续介绍 MM32 MCU USB 的虚拟串口 CDC 功能。 96f6f95f79df526d86f09e9a6cf4d938.png

往期精彩:

MM32 USB功能学习笔记 —— USB HID设备

MM32-LINK使用教程 —— 使用小技巧

MM32-LINK使用教程 —— 远程授权编程

MM32-LINK使用教程 —— 编程规则设置

MM32-LINK使用教程——读写保护操作

MM32-LINK使用教程——编程计数功能

MM32-LINK使用教程 —— 串口功能及硬件连接方式介绍

基于MM32 MCU的shell调试教程(一)

基于MM32 MCU的shell调试教程(二)

基于MM32 MCU的shell调试教程(三)

MM32W无线MCU系列产品应用笔记 —— 数据采集仪器

MM32W无线MCU系列产品应用笔记 —— 数据透传

MM32W无线MCU系列产品应用笔记 —— 蓝牙智能锁方案

MM32W无线MCU系列产品应用笔记 —— 温湿度监测仪方案

MM32W无线MCU系列产品应用笔记 —— 蓝牙自拍杆方案

MM32W无线MCU系列产品应用笔记 —— 智能炫彩遥控灯方案

MM32W无线MCU系列产品应用笔记 —— 自定义AT指令

MM32W无线MCU系列产品应用笔记 —— 自定义服务和特征值

MM32W无线MCU系列产品应用笔记 —— 接口函数调用

MM32W无线MCU系列产品应用笔记 —— 低功耗BLE蓝牙应用

MM32W无线MCU系列产品应用笔记 —— 阻塞式例程

MM32W无线MCU系列产品应用笔记——中断式例程

MM32W无线MCU系列产品应用笔记——蓝牙开发套件介绍

MM32W无线MCU系列产品应用手册——模组与AT指令

MM32SPIN2x 电机专用MCU功能特色——CRC计算单元

MM32SPIN2x 电机专用MCU功能特色——ADC DMA模块配置

MM32SPIN2x 电机专用MCU功能特色 —— I2C功能

MM32SPIN2x 电机专用MCU功能特色 —— SPI功能

MM32SPIN2x 电机专用MCU功能特色 —— 独立看门狗低功耗唤醒

MM32SPIN2x 电机专用MCU功能特色 —— 高集成度产品的电源管理

基于MM32SPIN电机/电源专用芯片的无感方波驱动应用方案——中小功率水泵

基于MM32SPIN电机/电源专用芯片的无传感弦波驱动应用方案——手持式吸尘器

基于MM32SPIN电机/电源专用芯片的有刷电机驱动应用方案——机器人舵机

865bee9d11343412f91e0ccad63a15e6.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值