首页 > 其他分享 >移植DAPLink (一) USB部分

移植DAPLink (一) USB部分

时间:2022-09-24 20:56:29浏览次数:87  
标签:DAPLink USB USBD 描述符 端点 移植 usb

DAPLink是ARM推出的一款调试器方案,支持SWD接口的Cortex-M系列MCU,或JTAG接口的Cortex-A系列MPU,软件代码使用Apache2.0许可,因此可以自由地用在个人和商业项目上。
CMSIS-DAP项目主页:
https://www.keil.com/pack/doc/CMSIS/DAP/html/index.html
CMSIS-DAP Github主页:
https://github.com/ARMmbed/DAPLink

DAPLinkv1和v2区别

由于DAPLink目前支持的功能很多也比较复杂,比如使用USB-CDC虚拟串口,USB-MSC虚拟U盘,USB Audio Streaming音频输入/输出实现的ADC/DAC功能等,这里只说明调试器部分的区别。
DAPLinkv1调试器使用的是HID驱动,在win8.1/win10下可以做到免安装驱动程序,使用UsbTreeView软件可以查看到用于调试器的端点描述符和端点信息,下图中可以看到使用两个分别为IN/OUT方向的中断(interrupt)端点来完成数据传输,轮循时间间隔设置为1ms,由于这是个USB全速设备(12Mbps),最大包长是64字节。
image
在usb全速设备中,中断端点在每个微帧只能安排一次传输事务(高速设备可以放3个中断传输事务,见下图),
image
由于上面配置的轮询间隔是1ms,最大包长是64字节,减去协议开销13字节,因此每1ms能携带51字节用户数据,那么中断传输的带宽 = 51 * 1000 / 1024 = 49.804KB/s,因此USB中断端点(HID模式)拿来做数据传输带宽还是比较低的。
image

在DAPLinkv2中,调试器部分使用了winusb驱动,设备端在USB描述符中报告自身支持winusb特性,并且提供上层应用程序访问的GUID,连接 WinUSB设备时,win8.1/win10主机系统会读取设备信息并自动加载Winusb.sys。
有了winusb驱动,就可以直接读写USB设备的端点了,它的功能实际上和libusb类似,不过libusb是将驱动上半部提供给用户空间完成的。那么在winusb驱动下,就可以不局限于中断端点,转而使用高速的批量传输(bulk)端点完成数据交互了。使用UsbTreeView查看DAPLinkv2设备的设备描述符和端点信息,相比与HID模式,WINUSB模式使用两个方向的批量传输端点替代了中断传输端点。
image
在一个微帧时间内,不会限制批量传输事务的传输数,总是利用剩余带宽安排传输,因此在全速设备中,批量传输每个包最大为64字节,一个微帧内,最大传输数是19个批量事务,因此批量传输的带宽 = (64 - 13) * 19 * 1000 / 1024 = 946.289KB/s,比起全速设备的中断传输,速度有了很大的提升。
image

如果设备端芯片换成CH568这种支持高速USB(480Mbps)的MCU(也可以是F1C100S,AM1808,AM335X这类MPU),那么速度会更快一些,不过最终的编程速度还受到目标板Flash擦写速度的限制;如果是调试阶段直接载入RAM执行,那么选择支持高速USB的设备就可以提高开发效率了。

USB描述符和枚举过程

本项目主要移植CMSIS-DAPv2 WinUSB部分,选用的MCU型号为GD32F303RC,Cortex-M4F核心,256KB FLASH + 48KB SRAM,带全速USB@12Mbps。

关于usb2.0具体的枚举过程,可以查看usb中文网的相关资料,
USB设备的枚举过程分析
Windows和Linux不同主机下USB设备枚举过程中的差别
这里主要针对枚举过程中,设备端需要返回的描述符进行适配,下面给出实际调试过程中的USB枚举过程:
image
USB描述符的配置主要参考DAPLink项目DAPLink-main\source\usb文件夹的以下文件:
usb_def.h,usb_lib.c,usbd_desc.h,usb_winusb.h
其中重点是usb_lib.c,包含了DAPLink所有的usb描述符配置信息。
推荐使用集成开发环境阅读usb_lib.c,并且需要先定义宏:
__USB_CONFIG__,USBD_ENABLE 1,USBD_WINUSB_ENABLE 1,USBD_BULK_ENABLE 1,USBD_BOS_ENABLE 1
虽然usb_lib.c内容很多,但这样借助集成开发环境的宏高亮功能,也能看的比较清楚了,下面是Eclipse的示例。
image

USB设备描述符:唯一需要注意的是bcdUSB需要填0x02100x0201,这样在windows下主机才会发起请求二进制设备对象存储描述符(BOS Descriptor),填0x0200,0x0110我测试下来不行。
不过通过0xEE返回MSFT100倒是可以制作自己的USB应用程序,而无需借助libusb驱动。
使用微软系统描述符1.0制作免驱动自定义USB设备

/* USB standard device descriptor */
#define USBD_BOS_ENABLE
#define USBD_EP0_MAX_SIZE 64
#define USB_CLASS_MISC 0xEF
#define USBD_VID    0xC251U
#define USBD_PID    0xF000U

const usb_desc_dev dap_dev_desc = {
    .header = {
        .bLength           = USB_DEV_DESC_LEN, 
        .bDescriptorType   = USB_DESCTYPE_DEV
    },

#if (USBD_BOS_ENABLE)
    // 通过二进制设备对象存储描述符(BOS Descriptor)向主机报告支持winusb
    .bcdUSB                = 0x0210U,
#else
    // 通过 操作系统字符串描述符->扩展兼容ID描述符->扩展属性描述符 向主机报告支持winusb
    // 暂未调试通过,windows未请求wIndex为5的主机扩展属性(Extend Properties),无法报告Keil-MDK使用DAPLink系统接口的GUID
    .bcdUSB                = 0x0200U,
#endif
    .bDeviceClass          = USB_CLASS_MISC,
    .bDeviceSubClass       = 0x02u,
    .bDeviceProtocol       = 0x01U,
    .bMaxPacketSize0       = USBD_EP0_MAX_SIZE,
    .idVendor              = USBD_VID,
    .idProduct             = USBD_PID,
    .bcdDevice             = 0x0110U,
    .iManufacturer         = STR_IDX_MFC,  // 1 厂商字符串位置 
    .iProduct              = STR_IDX_PRODUCT, // 2 产品字符串位置
    .iSerialNumber         = STR_IDX_SERIAL, // 3 序列号字符串位置
    .bNumberConfigurations = USBD_CFG_MAX_NUM // 1 配置描述符的数量
};

配置描述符:需要注意的是Bulk OUT端点在前,Bulk IN端点在后。
image

/* USB device configuration descriptor */
const usb_desc_config_set dap_config_desc = {
    .config = {
        .header = {
            .bLength         = USB_CFG_DESC_LEN,
            .bDescriptorType = USB_DESCTYPE_CONFIG
        },
        // no vcom
        .wTotalLength        = (USB_CFG_DESC_LEN + USB_ITF_DESC_LEN + 2 * USB_EP_DESC_LEN),
        .bNumInterfaces      = 0x01U,
        .bConfigurationValue = 0x01U,
        .iConfiguration      = 0x00U,
        // bus powered, no remote wakeup
        .bmAttributes        = (USB_CONFIG_BUS_POWERED),
        // 500mA
        .bMaxPower           = 0xFAu
    },

    // descriptor: winusb
    .dap_itf = {
        .header = {
            .bLength         = USB_ITF_DESC_LEN,
            .bDescriptorType = USB_DESCTYPE_ITF
        },
        .bInterfaceNumber    = 0x00U,
        .bAlternateSetting   = 0x00U,
        .bNumEndpoints       = 0x02U,
        .bInterfaceClass     = USB_CLASS_VEND_SPECIFIC,
        .bInterfaceSubClass  = 0x00,
        .bInterfaceProtocol  = 0x00,
        // The string index for this interface.
        .iInterface          = 0x04
    },

    // CMSIS-DAP v2 WinUSB 要求第一个端点是 Bulk OUT,第二个端点是 Bulk IN
    .dap_winusb_epout = {
        .header = {
            .bLength         = USB_EP_DESC_LEN,
            .bDescriptorType = USB_DESCTYPE_EP
        },
        .bEndpointAddress    = WINUSB_OUT_EP,
        .bmAttributes        = USB_EP_ATTR_BULK,
        .wMaxPacketSize      = WINUSB_PACKET_SIZE,
        // bInterval: ignore for Bulk transfer
        .bInterval           = 0x00U
    },

    .dap_winusb_epin = {
        .header = {
            .bLength         = USB_EP_DESC_LEN,
            .bDescriptorType = USB_DESCTYPE_EP
        },
        .bEndpointAddress    = WINUSB_IN_EP,
        .bmAttributes        = USB_EP_ATTR_BULK,
        .wMaxPacketSize      = WINUSB_PACKET_SIZE,
        // bInterval: ignore for Bulk transfer
        .bInterval           = 0x00U
    }
};

产品字符串:必须包含CMSIS-DAP字符串
image

/* USB product string */
static const usb_desc_str product_string = {
    .header = {
         .bLength         = USB_STRING_LEN(14U),
         .bDescriptorType = USB_DESCTYPE_STR,
     },
     .unicode_string = {'C', 'M', 'S', 'I', 'S', '-', 'D', 'A', 'P', ' ','v','2','.','1'}
};

接口字符串:对于组合设备(DAPLink + USBCDC虚拟串口),必须包含CMSIS-DAP字符串

static const usb_desc_str dap_itf_string = {
    .header = {
         .bLength         = USB_STRING_LEN(17U),
         .bDescriptorType = USB_DESCTYPE_STR,
     },
    .unicode_string = {'C', 'M', 'S', 'I', 'S', '-', 'D', 'A', 'P',' ','v','2','.','1','-', 'G','D'}
};

其它的字符串信息,按照usb_lib.c的作为模板,可以自行编写。
经过这样操作,USB设备就可以被主机成功枚举,由于我使用的是win10LTSC版本的系统,不能自动安装winusb驱动,因此出现代码28表示驱动探测失败。
image

设备管理器也是感叹号

对于这种现象,只需要手动安装inf驱动描述文件就行,先关闭win10驱动签名验证,再到DAPLink网站下载inf文件,
USB Driver and *.inf file
直接复制即可,新建个记事本,粘贴,需要修改inf文件内的VID PID和USB设备一致,最后另存为.inf文件,并放入单独的文件夹。
image
然后到设备管理器里,手动安装驱动。





最后USB就调通了。

在keil-MDK也能识别到CMSIS DAPlink工具,只是由于当前还未移植DAPLink SWD接口IO操作部分,显示SWD/JTAG通信失败。

标签:DAPLink,USB,USBD,描述符,端点,移植,usb
From: https://www.cnblogs.com/yanye0xff/p/16710614.html

相关文章