首页 程序笔记 STM32CubeMx生成的USB CDC代码修改为WINUSB设备

STM32CubeMx生成的USB CDC代码修改为WINUSB设备

前言

WINUSB在Windows中是可以免驱的,那HID也是免驱的,用HID不是一样吗?不一样! HID采用中断传输,传输速度上不去,如果是使用的是USB2.0 FULL speed,那速度更低,可能很多场合都满足不了了。但是WINUSB就不一样了,winusb可以采用批量传输,数据吞吐量大大提高。(HID理论速度:10001964Byte/s, 1ms传输1次, 1次传输19个DAT事务, 1个DAT事务最大64B,好像也不慢了),下面就介绍一下STM32如何在CDC设备的基础上修改为WINUSB设备。

关于如何对WINUSB进行DEBUG

请注意,Windows仅查询OS字符串描述符一次,在开发过程中会造成麻烦。OS描述符存储在注册表中
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\UsbFlags\VVVVPPPPRRRR
(VVVV - VID; PPPP - PID; RRRR - 版本号)
请删除你USB设备对应的注册表项,然后使用USBDeview卸载设备,以便始终获得新的设备插入行为。

Src/usbd_desc.c

第128行,USBD_SUPPORT_USER_STRING_DESC后添加

#if (USBD_SUPPORT_WINUSB==1)
uint8_t *USBD_WinUSBOSStrDescriptor(uint16_t *length);
uint8_t *USBD_WinUSBOSFeatureDescriptor(uint16_t *length);
uint8_t *USBD_WinUSBOSPropertyDescriptor(uint16_t *length);
#endif // (USBD_SUPPORT_WINUSB==1)

USBD_DescriptorsTypeDef FS_Desc中,最后的地方添加

#if (USBD_SUPPORT_WINUSB == 1) 
, USBD_WinUSBOSFeatureDescriptor
, USBD_WinUSBOSPropertyDescriptor
#endif // (USBD_SUPPORT_WINUSB==1)

/* USB_DeviceDescriptor */后添加

#define USB_LEN_OS_FEATURE_DESC 0x28
#if defined ( __ICCARM__ ) /* IAR Compiler */
  #pragma data_alignment=4
#endif /* defined ( __ICCARM__ ) */

__ALIGN_BEGIN uint8_t USBD_WINUSB_OSFeatureDesc[USB_LEN_OS_FEATURE_DESC] __ALIGN_END =
{
   0x28, 0, 0, 0, // length
   0, 1,          // bcd version 1.0
   4, 0,          // windex: extended compat ID descritor
   1,             // no of function
   0, 0, 0, 0, 0, 0, 0, // reserve 7 bytes
// function
   0,             // interface no
   0,             // reserved
   W, I, N, U, S, B, 0, 0, //  first ID
     0,   0,   0,   0,   0,   0, 0, 0,  // second ID
     0,   0,   0,   0,   0,   0 // reserved 6 bytes      
};
#define USB_LEN_OS_PROPERTY_DESC 0x8E
#if defined ( __ICCARM__ ) /* IAR Compiler */
  #pragma data_alignment=4
#endif /* defined ( __ICCARM__ ) */
__ALIGN_BEGIN uint8_t USBD_WINUSB_OSPropertyDesc[USB_LEN_OS_PROPERTY_DESC] __ALIGN_END =
{
      0x8E, 0, 0, 0,  // length 246 byte
      0x00, 0x01,   // BCD version 1.0
      0x05, 0x00,   // Extended Property Descriptor Index(5)
      0x01, 0x00,   // number of section (1)
//; property section        
      0x84, 0x00, 0x00, 0x00,   // size of property section
      0x1, 0, 0, 0,   //; property data type (1)
      0x28, 0,        //; property name length (42)
      D, 0,
      e, 0,
      v, 0,
      i, 0,
      c, 0,
      e, 0,
      I, 0,
      n, 0,
      t, 0,
      e, 0,
      r, 0,
      f, 0,
      a, 0,
      c, 0,
      e, 0,
      G, 0,
      U, 0,
      I, 0,
      D, 0,
      0, 0,
      // D6805E56-0447-4049-9848-46D6B2AC5D28
      0x4E, 0, 0, 0,  // ; property data length
      {, 0,
      1, 0,
      3, 0,
      E, 0,
      B, 0,
      3, 0,
      6, 0,
      0, 0,
      B, 0,
      -, 0,
      B, 0,
      C, 0,
      1, 0,
      E, 0,
      -, 0,
      4, 0,
      6, 0,
      C, 0,
      B, 0,
      -, 0,
      A, 0,
      C, 0,
      8, 0,
      B, 0,
      -, 0,
      E, 0,
      F, 0,
      3, 0,
      D, 0,
      A, 0,
      4, 0,
      7, 0,
      B, 0,
      4, 0,
      0, 0,
      6, 0,
      2, 0,
      }, 0,
      0, 0,
      
};

在文件末尾添加

#if (USBD_SUPPORT_WINUSB==1)
const uint8_t USBD_OS_STRING[8] = { 
   M,
   S,
   F,
   T,
   1,
   0,
   0,
   USB_REQ_MS_VENDOR_CODE, 
}; 
uint8_t *USBD_WinUSBOSStrDescriptor(uint16_t *length)
{
   USBD_GetString((uint8_t *)USBD_OS_STRING, USBD_StrDesc, length);
   return USBD_StrDesc;
}
uint8_t *USBD_WinUSBOSFeatureDescriptor(uint16_t *length)
{
  *length = USB_LEN_OS_FEATURE_DESC;
  return USBD_WINUSB_OSFeatureDesc;
}
uint8_t *USBD_WinUSBOSPropertyDescriptor(uint16_t *length)
{
  *length = USB_LEN_OS_PROPERTY_DESC;
   return USBD_WINUSB_OSPropertyDesc;
}
#endif // (USBD_SUPPORT_WINUSB==1)

Inc/usbd_conf.h

在文件中添加

#define USBD_SUPPORT_WINUSB       1

Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ctlreq.c

static uint8_t USBD_GetLen(uint8_t *buf);后添加

#if (USBD_SUPPORT_WINUSB==1)
static void USBD_WinUSBGetDescriptor(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
#endif // (USBD_SUPPORT_WINUSB==1)

USBD_StdDevReq函数中,case USB_REQ_CLEAR_FEATURE:分支后面添加

#if (USBD_SUPPORT_WINUSB==1)
  case USB_REQ_MS_VENDOR_CODE:
    USBD_WinUSBGetDescriptor( pdev, req ); 
    break;
#endif // (USBD_SUPPORT_WINUSB==1)

USBD_StdItfReq函数中,switch的default分支中添加

#if (USBD_SUPPORT_WINUSB==1)
    if ( req-bmRequest == 0xC1 ) {
       USBD_WinUSBGetDescriptor( pdev, req ); 
       break;
    }
#endif // (USBD_SUPPORT_WINUSB==1)

USBD_GetDescriptor函数中,第一个switch的case USB_DESC_TYPE_STRING:分支中的USBD_IDX_INTERFACE_STR子分支后添加

#if (USBD_SUPPORT_WINUSB==1)
    case 0xEE: // OS String 
      pbuf = (uint8_t *) pdev-pClass-GetWinUSBOSDescriptor(len);
      break;
#endif // (USBD_SUPPORT_WINUSB==1)

在该文件最后添加

#if (USBD_SUPPORT_WINUSB==1)
static void USBD_WinUSBGetDescriptor(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
{
  uint16_t len;
  uint8_t *pbuf;
  
  switch (req-wIndex)
  { 
  case 0x04: // compat ID
    pbuf = pdev-pDesc-GetWinUSBOSFeatureDescriptor(len);
    break;
  case 0x05:
    pbuf = pdev-pDesc-GetWinUSBOSPropertyDescriptor(len);
    break;
     
  default: 
     USBD_CtlError(pdev , req);
    return;
  }
  if((len != 0) (req-wLength != 0))
  {
    
    len = MIN(len , req-wLength);
    
    USBD_CtlSendData (pdev, 
                      pbuf,
                      len);
  }
  
   
}   

#endif // (USBD_SUPPORT_WINUSB==1)

Middlewares/ST/STM32_USB_Device_Library/Core/Inc/usbd_def.h

#define USB_REQ_SYNCH_FRAME后添加

// WinUSB MS Vendor Code
#define  USB_REQ_MS_VENDOR_CODE                         0xA0

typedef struct _Device_cb USBD_ClassTypeDef中,末尾添加

#if (USBD_SUPPORT_WINUSB == 1) 
  uint8_t  *(*GetWinUSBOSDescriptor)(uint16_t *length); 
#endif

typedef struct USBD_DescriptorsTypeDef中,末尾添加

#if (USBD_SUPPORT_WINUSB==1)

   uint8_t *(*GetWinUSBOSFeatureDescriptor)(uint16_t *length);
   uint8_t *(*GetWinUSBOSPropertyDescriptor)(uint16_t *length);
#endif

Middlewares/ST/STM32_USB_Device_Library/CDC/inc/usbd_cdc.c

static uint8_t USBD_CDC_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum);后添加

#if (USBD_SUPPORT_WINUSB==1)
uint8_t* USBD_WinUSBOSStrDescriptor(uint16_t *length);
#endif //(USBD_SUPPORT_WINUSB==1)

USBD_ClassTypeDef USBD_CDC中,末尾添加

#if (USBD_SUPPORT_WINUSB==1)   
  USBD_WinUSBOSStrDescriptor
#endif // (USBD_SUPPORT_WINUSB==1)

本文参考自:https://0w0.pw/417.html

2

站心网

前言 WINUSB在Windows中是可以免驱的,那HID也是免驱的,用HID不是一样吗?不一样! HID采用中断传输,传输..

为您推荐

代码照进现实:对公司管理策略的技术性解构

上学的时候觉得计算机专业的一些理论晦涩难懂,跟现实世界的关联太少,每当遇到一些精妙的设计时都会发出一种感叹:究竟是什么脑袋才能想出这么有意思的东西。一晃工作十年,阅历渐丰,隐约发现其实社会中的一些现象..

编写优秀 CSS 代码的 8 个策略

编写基本的CSS和HTML是我们作为Web开发人员学习的首要事情之一。然而,我遇到的很多应用程序显然没有人花时间真正考虑前端开发的长久性和可维护性。我认为这主要是因为许多开发人员对组织CSS / HTML和JavaScript的策..

天天写业务代码,如何成为技术大牛?

不管是开发、测试、运维,每个技术人员心理多多少少都有一个成为技术大牛的梦,毕竟"梦想总是要有的,万一实现了呢"!正是对技术梦的追求,促使我们不断地努力和提升自己。然而"梦想是美好的,现实却是残酷的",很多..

记我经历的一次公司破产经历,一行代码害死一家公司

前言这是一篇亲身经历的真实记录,事情发生在2010年。狗血剧情一再上演,使我的程序员生涯变得跌宕起伏,也从中学到了很多。在写这篇文章之前,我还专门去查了这家公司的资料。有如下事实:1.官网已经打不开了。2.天..

如何处理前任程序员留下的代码

作为软件工程师不可避免会遇到的一个场景是:我们在改变或添加一个功能到不是我们创建的、我们不熟悉的、与我们负责的系统部分无关的代码中时,会遇到麻烦。虽然这可能会是一个繁琐而艰巨的任务,但是由于使用其他开..

对码农而言什么样的代码才能叫做好代码?

好的代码,就像是好的笑话——无需解释就能让别人明白。如果你的代码能够做到不解自明,在大多数时候,你根本无需为其配备说明文档。好的代码,就像是一辆配备了优秀音响和杯架的汽车,这辆车在行驶到最高速度的时候..

当一个程序员写不出代码了,该怎么办?

你已经对着电脑n个小时了。不知道该写什么代码,或者一种摔键盘的冲动正在你的胸中酝酿。咖啡一杯接着一杯。不敢再喝了,因为搞不好要有副作用了,心跳加速,身体不由自主地颤抖,出冷汗,但还是无法产出任何代码。..

MySQL查看、修改字符集及Collation

前言在使用MySQL的过程中,可能会出现初始设计使用的字符集或Collation不符合当前需求的情况。如使用utf8的表(MySQL中的utf8即utf8mb3)要支持emoji,而utf8mb3不支持emoji(emoji需要4个字节,而utf8mb3最长只支持..

基于Dapper的开源Lambda扩展,且支持分库分表自动生成实体之基础

LnskyDB是基于Dapper的Lambda扩展,支持按时间分库分表,也可以自定义分库分表方法.而且可以T4生成实体类免去手写实体类的烦恼.文档地址:https://liningit.github.io/LnskyDB/开源地址:https://github.com/liningit/Ln..

ASP.NET MVC最常用的设计模式代码示例

ASP.NET MVC 是一个基于分层架构的框架,其核心架构本身已经实现了 MVC 模式(Model-View-Controller)。除了 MVC 模式,开发者在使用 ASP.NET MVC 开发应用时,通常会结合其他设计模式以提高代码的可维护性、可扩展..

js 数组方法 - 修改篇

js数组方法可分为三类:修改、访问、迭代。修改:改变原有数组访问:不改变原有数组,从原有数组中获取数据迭代:对数组的每一项进行处理,返回数据本文主要介绍数组的修改篇一、增加1、push()含义:在数组末尾添加..

ASP.NET 使用Entity Framework (EF) 创建迁移修改SQLite数据库表结构

在 ASP.NET 中,使用 Entity Framework (EF) 创建并连接 SQLite 数据库是一种轻量级、高效的数据库管理方式。以下是详细步骤:安装必要的 NuGet 包安装EntityFrameworkCore.Sqlite包:Install-Package Microsoft.Ent..

10款.NET开发中推荐的代码分析和质量工具

以下是10款.NET开发中常用的代码分析和质量工具列表,以及它们的主要功能和使用场景:1. SonarQube简介:一个流行的开源静态代码分析平台,用于检测代码中的漏洞、错误、技术债务等问题。主要功能:支持代码质量监测..

通过js修改tinymce的编辑器的内容

在网页开发中,TinyMCE是一个流行的富文本编辑器。它允许用户轻松地创建和编辑HTML内容,而无需直接操作代码。然而,有时我们可能需要通过JavaScript来动态修改编辑器中的内容。本文将介绍如何使用JavaScript来修改T..

.NET C# EntityFramework(EF)连接SQLite代码示例

在.NET C#中使用Entity Framework(EF)连接SQLite数据库是一种常见的做法,可以有效地管理和操作数据。以下是一个简单的示例代码,展示了如何使用EF Core连接到SQLite数据库并执行基本的CRUD操作。首先,确保你已经..

微软 .NET 9 正式发布!专为云原生和生成式 AI 应用设计

微软正式发布了 .NET 9,这是一次重大的版本更新。微软在 .NET 9 中带来了一系列新特性和改进,主要聚焦在性能优化、云原生支持、AI集成以及开发者体验的提升。以下是一些重要的更新亮点:性能改进:在 .NET 9 中,..

设计模式之高质量代码

0,什么是高质量代码我觉得回答这个问题,应该从两个方面考虑。从业务角度考虑。首先,在公司开发一款软件,应该是业务在驱动。所以,从这个角度来说,代码第一个应该满足的是业务需求,如果连最基本的业务需求都满..

修改VisualSVN Server地址为ip地址,修改svn服务端地址为ip或者域名地址的方法

svn服务端搭建成功之后,地址太长很麻烦,想搞一个服务器专门做svn服务端,修改svn地址为ip地址无奈网上教程不靠谱,于是自己研究了下1.修改VisualSVN 的地址2修改地址并保存很多人不成功就在这里,点击确认之后复制..

ideogram.ai 人工智能AI图片生成工具网站

Ideogram是一个由前Google Brain员工创立的AI绘画工具,它能够根据文本生成各种风格的图像,尤其擅长准确生成文本内容和抽象图标。Ideogram官网地址:https://ideogram.ai/loginIdeogram是由前Google Brain员工在202..

.NET 9 即将推出的功能Task.WhenEach

.NET 爱好者!我刚刚偶然发现了一个非常酷的新 PR,它被合并到 .NET 运行时存储库中,我想分享一个例子。希望您能为新的 .NET 版本大肆宣传!在即将到来的 .NET 9 版本中,我们预计会有一个名为 .它在这里让您的异步..

发表回复

返回顶部