[应用方案] 修完484跑"linux",秀个基础一些的,跑USB设备

[复制链接]
 楼主| vsfopen 发表于 2019-12-25 15:53 | 显示全部楼层 |阅读模式
本帖最后由 vsfopen 于 2019-12-25 21:47 编辑

实现一个CDC,大部分开发方式下,还需要去研究很多CDC的细节,特别是各种描述符,一有错误,还无法识别。好吧,其实,描述符啥的,从来就不是个事,直接上代码,非官方USB协议栈:

  1. #include "vsf.h"

  2. struct usrapp_const_t {
  3.     struct {
  4.         uint8_t dev_desc[USB_DT_DEVICE_SIZE];
  5.         uint8_t config_desc[USB_DT_CONFIG_SIZE + USB_DESC_CDC_ACM_IAD_LEN];
  6.         uint8_t str_lanid[4];
  7.         uint8_t str_vendor[20];
  8.         uint8_t str_product[26];
  9.         uint8_t str_cdc[14];
  10.         vk_usbd_desc_t std_desc[6];
  11.     } usbd;
  12. };
  13. typedef struct usrapp_const_t usrapp_const_t;

  14. struct usrapp_t {
  15.     struct {
  16.         struct {
  17.             vk_usbd_cdcacm_t param;
  18.         } cdc;

  19.         vk_usbd_ifs_t ifs[USB_CDC_IFS_NUM];
  20.         vk_usbd_cfg_t config[1];
  21.         vk_usbd_dev_t dev;
  22.     } usbd;
  23. };
  24. typedef struct usrapp_t usrapp_t;

  25. static const usrapp_const_t usrapp_const = {
  26.     .usbd                       = {
  27.         .dev_desc               = {
  28.             USB_DESC_DEV_IAD(64, APP_CFG_USBD_VID, APP_CFG_USBD_PID, 1, 2, 0, 1)
  29.         },
  30.         .config_desc            = {
  31.             USB_DESC_CFG(sizeof(usrapp_const.usbd.config_desc), 2 * USRAPP_CFG_CDC_NUM, 1, 0, 0x80, 100)
  32.             USB_DESC_CDC_UART_HS_IAD(0, 4, 2, 1, 1)
  33.         },
  34.         .str_lanid              = {
  35.             USB_DESC_STRING(2, 0x09, 0x04)
  36.         },
  37.         .str_vendor             = {
  38.             USB_DESC_STRING(18,
  39.                 'S', 0, 'i', 0, 'm', 0, 'o', 0, 'n', 0, 'Q', 0, 'i', 0, 'a', 0,
  40.                 'n', 0
  41.             )
  42.         },
  43.         .str_product            = {
  44.             USB_DESC_STRING(24,
  45.                 'V', 0, 'S', 0, 'F', 0, '-', 0, 'M', 0, 'u', 0, 'l', 0, 't', 0,
  46.                 'i', 0, 'C', 0, 'D', 0, 'C', 0
  47.             )
  48.         },
  49.         .str_cdc                = {
  50.             USB_DESC_STRING(12,
  51.                 'V', 0, 'S', 0, 'F', 0, 'C', 0, 'D', 0, 'C', 0
  52.             )
  53.         },
  54.         .std_desc               = {
  55.             VSF_USBD_DESC_DEVICE(0, usrapp_const.usbd.dev_desc, sizeof(usrapp_const.usbd.dev_desc)),
  56.             VSF_USBD_DESC_CONFIG(0, 0, usrapp_const.usbd.config_desc, sizeof(usrapp_const.usbd.config_desc)),
  57.             VSF_USBD_DESC_STRING(0, 0, usrapp_const.usbd.str_lanid, sizeof(usrapp_const.usbd.str_lanid)),
  58.             VSF_USBD_DESC_STRING(0x0409, 1, usrapp_const.usbd.str_vendor, sizeof(usrapp_const.usbd.str_vendor)),
  59.             VSF_USBD_DESC_STRING(0x0409, 2, usrapp_const.usbd.str_product, sizeof(usrapp_const.usbd.str_product)),
  60.             VSF_USBD_DESC_STRING(0x0409, 4, usrapp_const.usbd.str_cdc, sizeof(usrapp_const.usbd.str_cdc)),
  61.         },
  62.     },
  63. };

  64. static usrapp_t usrapp = {
  65.     .usbd                       = {
  66.         .cdc.param              = {
  67.             USB_CDC_ACM_PARAM(2, 1, 1, NULL, NULL, USB_CDC_ACM_115200_8N1)
  68.         },

  69.         USB_CDC_IFS(.ifs, 0, usrapp.usbd.cdc.param)
  70.         USB_CONFIG(.config, 0, &usrapp.usbd.ifs)
  71.         USB_DEVICE(.dev, usrapp.usbd.config, usrapp_const.usbd.std_desc, USB_DC_SPEED_HIGH, &VSF_USB_DC0)
  72.     },
  73. };

  74. void main(void)
  75. {
  76.     vk_usbd_init(&usrapp.usbd.dev);
  77.     vk_usbd_connect(&usrapp.usbd.dev);
  78. }


好吧,我承认,用户需要自己定义字符串描述符。
目前,需要用户了解的信息量还有一些大,我们会继续进一步优化。
目标:没玩过USB的人,通过文档,也可以自己实现USB设备,而不是只能改改demo。
而且,由于我们的USB协议栈的专门设计,用户层代码,甚至连USB的EP初始化都不用考虑,用户层只需要知道要实现什么设备就行,其他的都交给软件,自己只需要在意业务逻辑。
xixi2017 发表于 2019-12-25 19:31 | 显示全部楼层
NIU B。楼主的头文件哪儿的
 楼主| vsfopen 发表于 2019-12-25 21:09 | 显示全部楼层
xixi2017 发表于 2019-12-25 19:31
NIU B。楼主的头文件哪儿的

是我们自己的系统的头文件,虽然目前还没完成最简的用户层封装,不过相比很多USB的demo,已经简化了非常多了。让代码去处理细节,人只需要指定功能(通过各种参数等等)
 楼主| vsfopen 发表于 2019-12-25 21:12 | 显示全部楼层
本帖最后由 vsfopen 于 2019-12-25 21:21 编辑

简单说明一下原理,其实很简单:
这里,USB设备描述符是IAD的方式,所以,后面各种东西,都可以简单的追加。比如,如果要实现一个CDC串口+U盘,就是定义了CDC描述符后,再定义一个MSC描述符就行。而且,定义的方式也是类似的,调用一个宏,提供一些关键参数,其他的细节都不用考虑了。

  1. #define USB_DESC_CDC_ACM_IAD(__IFS_START, __I_FUNC, __INT_IN_EP, __BULK_IN_EP, __BULK_OUT_EP, __BULK_EP_SIZE, __INT_EP_INTERVAL)\
  2.             USB_DESC_IAD((__IFS_START), 2, USB_CLASS_COMM, 0x02, 0x01, (__I_FUNC))\
  3.             USB_DESC_IFS((__IFS_START), 0, 1, USB_CLASS_COMM, 0x02, 0x01, (__I_FUNC))\
  4.                                                 /* Header Functional Descriptor */\
  5.             0x05,                               /* bLength: Endpoint Descriptor size */\
  6.             0x24,                               /* bDescriptorType: CS_INTERFACE */\
  7.             0x00,                               /* bDescriptorSubtype: Header Func Desc */\
  8.             USB_DESC_WORD(0x0110),              /* bcdCDC: spec release number */\
  9.                                                 /* Call Managment Functional Descriptor */\
  10.             0x05,                               /* bFunctionLength */\
  11.             0x24,                               /* bDescriptorType: CS_INTERFACE */\
  12.             0x01,                               /* bDescriptorSubtype: Call Management Func Desc */\
  13.             0x00,                               /* bmCapabilities: D0+D1 */     \
  14.             0x01,                               /* bDataInterface: 1 */         \
  15.                                                 /* ACM Functional Descriptor */ \
  16.             0x04,                               /* bFunctionLength */           \
  17.             0x24,                               /* bDescriptorType: CS_INTERFACE */\
  18.             0x02,                               /* bDescriptorSubtype: Abstract Control Management desc */\
  19.             0x02,                               /* bmCapabilities */\
  20.                                                 /* Union Functional Descriptor */\
  21.             0x05,                               /* bFunctionLength */           \
  22.             0x24,                               /* bDescriptorType: CS_INTERFACE */\
  23.             0x06,                               /* bDescriptorSubtype: Union func desc */\
  24.             (__IFS_START),                      /* bMasterInterface: Communication class interface */\
  25.             1 + (__IFS_START),                  /* bSlaveInterface0: Data Class Interface */\
  26.                                                                                 \
  27.             USB_DESC_EP(USB_DIR_IN | (__INT_IN_EP), USB_ENDPOINT_XFER_INT, 8, __INT_EP_INTERVAL)\
  28.             USB_DESC_IFS((__IFS_START) + 1, 0, 2, USB_CLASS_CDC_DATA, 0x00, 0x00, (__I_FUNC))\
  29.             USB_DESC_EP(USB_DIR_IN | (__BULK_IN_EP), USB_ENDPOINT_XFER_BULK, __BULK_EP_SIZE, 0x00)\
  30.             USB_DESC_EP(USB_DIR_OUT | (__BULK_OUT_EP), USB_ENDPOINT_XFER_BULK, __BULK_EP_SIZE, 0x00)


MSC也有类似的宏,所以,如果定义一个CDC的配置描述符,这样处理就行了:
uint8_t config_desc[USB_DT_CONFIG_SIZE + USB_DESC_CDC_ACM_IAD_LEN] = {
    USB_DESC_CFG(sizeof(usrapp_const.usbd.config_desc), USB_CDC_IFS_NUM, 1, 0, 0x80, 100)
    USB_DESC_CDC_UART_HS_IAD(0, 4, 2, 1, 1)
};

如果要定义一个CDC+U盘,就在后面,跟一个MSC的宏:
uint8_t config_desc[USB_DT_CONFIG_SIZE + USB_DESC_CDC_ACM_IAD_LEN + USB_DESC_MSCBOT_IAD_LEN] = {
    USB_DESC_CFG(sizeof(usrapp_const.usbd.config_desc), USB_CDC_IFS_NUM, 1, 0, 0x80, 100)
    USB_DESC_CDC_UART_HS_IAD(0, 4, 2, 1, 1)
    USB_DESC_MSCBOT_IAD(USB_CDC_IFS_NUM, 5, 3, 3, 512)
};

只要根据手册填入宏的参数(描述符的关键数据,比如端点号等等),其他描述符的细节,就让代码自动生成吧。
21mengnan 发表于 2019-12-26 11:44 | 显示全部楼层
有图有真相吗
 楼主| vsfopen 发表于 2019-12-26 13:32 | 显示全部楼层

CDC需要咋样的截图?
 楼主| vsfopen 发表于 2019-12-26 13:45 | 显示全部楼层
CDC和MSC,用户实际使用的时候,除了一些设置外,只需要关心用户层的接口。

对于CDC,用户层接口就是一个输入流和一个输出流;对于MSC,用户层接口就是一个scsi设备。

  1. #define USB_CDC_ACM_PARAM(__INT_IN_EP, __BULK_IN_EP, __BULK_OUT_EP, __STREAM_RX, __STREAM_TX, __BAUDRATE)\
  2.             .ep = {                                                             \
  3.                 .notify         = __INT_IN_EP,                                  \
  4.                 .out            = __BULK_OUT_EP,                                \
  5.                 .in             = __BULK_IN_EP,                                 \
  6.             },                                                                  \
  7.             .line_coding        = __BAUDRATE,                                   \
  8.             .stream.tx.stream   = (vsf_stream_t *)__STREAM_TX,                  \
  9.             .stream.rx.stream   = (vsf_stream_t *)__STREAM_RX,
这里,__STREAM_RX和__STREAM_TX就是用户层的2个流接口。

我们正在评估去掉USB的端点号设置和接口号设置,完全通过宏自动分配,这样,用户估计真的也就只需要处理用户层的接口(CDC的2个流,MSC的scsi设备)
21mengnan 发表于 2019-12-26 15:06 | 显示全部楼层
不懂,这个怎么玩啊。。。
 楼主| vsfopen 发表于 2019-12-26 15:24 | 显示全部楼层
21mengnan 发表于 2019-12-26 15:06
不懂,这个怎么玩啊。。。

我们文档还需要不少时间,现在在处理其他文档。
以后有文档的话,照着文档天参数就行了
21mengnan 发表于 2019-12-26 16:27 | 显示全部楼层
vsfopen 发表于 2019-12-26 15:24
我们文档还需要不少时间,现在在处理其他文档。
以后有文档的话,照着文档天参数就行了 ...

好,坐等楼主大作。
 楼主| vsfopen 发表于 2019-12-27 13:21 | 显示全部楼层
21mengnan 发表于 2019-12-26 16:27
好,坐等楼主大作。

这周会准备一个更加简单的,20来行代码实现用户层的CDC,加几行可以实现2路CDC,在加几行还可以多一个MSC,实现的USB设备,用户简单可以配置。
東南博士 发表于 2019-12-27 13:37 | 显示全部楼层
USB转串口吗?
 楼主| vsfopen 发表于 2019-12-27 13:52 | 显示全部楼层

目前的demo是USB转串口,不过,这种设计方式在其他设备上一样可以用
americ 发表于 2020-1-17 18:03 | 显示全部楼层
仍然需要一个inf 在电脑上?  我在看HID, 键盘,这样完全不需要电脑的配置设置。只是应用程序配合。
 楼主| vsfopen 发表于 2020-1-21 12:03 | 显示全部楼层
americ 发表于 2020-1-17 18:03
仍然需要一个inf 在电脑上?  我在看HID, 键盘,这样完全不需要电脑的配置设置。只是应用程序配合。 ...

这个看PC端了,不过有一种方式,可以不需要驱动,加上winusb的描述符
上位机使用winusb或者libusb。

我这里弄的也只是简化USB设备端的开发,最新的在这里:
https://bbs.21ic.com/icview-2892282-1-3.html
598330983 发表于 2020-1-23 12:51 | 显示全部楼层
希望不用额外的驱动就行
gejigeji521 发表于 2020-1-25 15:48 | 显示全部楼层
多谢分享经
gejigeji521 发表于 2020-1-25 15:48 | 显示全部楼层
经验不错。
 楼主| vsfopen 发表于 2020-1-28 13:30 | 显示全部楼层
598330983 发表于 2020-1-23 12:51
希望不用额外的驱动就行

我们实验过的集中不需要额外驱动的USB通信方式:
1. HID,上位机使用libhid
2. winusb,需要加入特定的描述符,上位机使用winusb
3. U盘,模拟一个FAT文件系统,通过一个模拟的文件来通信(使用directIO方式)。这个相对最简单,上位机用脚本开发(我们测试的时候,脚本使用python,甚至是集成在模拟U盘的文件系统里的)
xixi2017 发表于 2020-1-28 16:14 | 显示全部楼层
来看大佬秀肌肉。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

90

主题

325

帖子

8

粉丝
快速回复 在线客服 返回列表 返回顶部