usb增加多路vcom的问题解析

简介
因项目需要,需要使用usb组合设备实现两路虚拟串口并同时挂载虚拟u盘,rtthread目前默认只支持一路虚拟串口,现在需要增加一路虚拟串口。
测试环境
rtthread版本:v4.1.0;
开发板:野火f407霸天虎v2;
计算机:windows11;
其他:串口调试助手、mobaxterm(作为shell终端)
已完成工作
新增一路cdc vcom,初步完成了2路虚拟串口的挂载,用usb连接开发板和计算机后,计算机能够识别出两路串口,并且虚拟u盘也能够使用;
遗留问题
串口调试助手打开串口时,存在卡死的情况;
两路串口无法同时正常使用,在开发板写的发送数据测试代码,总有一路串口启动后,计算机打开串口助手无法收到数据。
出现上面两个问题后,计算机显示usb断开,然后自动重新连接,但无法正常连接,显示无法找到设备描述符。
开发记录
前提条件
已经实现了usb组合设备配置模式下挂载虚拟串口和虚拟u盘。具体实现过程可参考其他开发者的文章,在此不做重复描述。
新增vcom
通过查看rt-thread源码,可知,各种usb设备的驱动代码位于rt-threadcomponentsdriversusbusbdeviceclass目录下,并且看到了虚拟串口设备驱动文件cdc_vcom.c以及其他各类如大容量存储设备mstorage.c(用于虚拟u盘)等。所以我的思路就是最简单直接暴力的方法,拷贝cdc_vcom.c并重命名为cdc_vcom2.c作为第二路虚拟串口驱动。
由于拷贝过来后避免编译错误,所以需要修改,主要对cdc_vcom2.c修改如下:
修改设备名
由于设备名必须是唯一的,以及存在了vcom,故这里重新命名为vcom2。
#define vcom_device vcom2 // vcom->vcom2
修改事件名和线程名
修改函数rt_usb_vcom_init内代码
rt_event_init(&data- >tx_event, “vcom2”, rt_ipc_flag_fifo); // vcom- >vcom2 rt_thread_init(&vcom_thread, vcom2, // vcom- >vcom2 vcom_tx_thread_entry, func, vcom_thread_stack, vcom_task_stk_size, 16, 20);- 修改注册函数 避免函数重复定义,修改注册函数部分,主要就是在函数名添加了后缀2,在文件最后代码,修改如下: ```c struct udclass vcom_class2 = { .rt_usbd_function_create = rt_usbd_function_cdc_create2 }; int rt_usbd_vcom_class_register2(void) { rt_usbd_class_register(&vcom_class2); return 0; } init_prev_export(rt_usbd_vcom_class_register2); #endif编译并解决bug编译后下载,运行后调试终端显示错误:endpoint assign error端点分配错误。通过定位发现在文件usbdevice_core.c的rt_usbd_device_add_config()函数中报错:
进入函数rt_usbd_ep_assign()后通过调试发现,usb设备的端点列表无法有效分配给各接口设备,而端点列表的定义位于librarieshal_driversdrv_usbd.c,新增了一个虚拟串口后,需要在该列表中增加端点,修改如下:
static struct ep_id _ep_pool[] =
{
{0x0, usb_ep_attr_control, usb_dir_inout, 64, id_assigned },
#ifdef bsp_usbd_ep_isoc
{0x1, usb_ep_attr_isoc, usb_dir_in, 64, id_unassigned},
{0x1, usb_ep_attr_isoc, usb_dir_out, 64, id_unassigned},
#else
{0x1, usb_ep_attr_bulk, usb_dir_in, 64, id_unassigned},
{0x1, usb_ep_attr_bulk, usb_dir_out, 64, id_unassigned},
#endif
{0x2, usb_ep_attr_int, usb_dir_in, 64, id_unassigned},
{0x2, usb_ep_attr_int, usb_dir_out, 64, id_unassigned},
{0x3, usb_ep_attr_bulk, usb_dir_in, 64, id_unassigned},
// 添加一个vcom, 需要2个bulk,1个int
{0x5, usb_ep_attr_int, usb_dir_in, 64, id_unassigned},
{0x6, usb_ep_attr_bulk, usb_dir_out, 64, id_unassigned},
{0x6, usb_ep_attr_bulk, usb_dir_in, 64, id_unassigned},
#if !defined(soc_series_stm32f1)
{0x3, usb_ep_attr_bulk, usb_dir_out, 64, id_unassigned},
#endif
{0xff, usb_ep_attr_type_mask, usb_dir_mask, 0, id_assigned },
};
重新编译,下载,连接开发板,计算机正常识别出了两个串口:
目前就剩下前面所说的遗留问题了。
附录
串口测试代码
添加测试文件example_vcom.c,加入编译,启动后在调试终端输入如下命令即可:
$ cmd_vcom vcom # 测试虚拟串口1
$ cmd_vcom vcom2 # 测试虚拟串口2
代码如下:
#include
#include
#include
#ifdef rt_using_ulog
#define log_tag example_vcom
#define log_lvl log_lvl_dbg
#include
#endif
int example_vcom(int argc, char *argv[]) {
if(argc<2){
return rt_error;
}
rt_device_t dev = rt_null;
char buf[] = hello rt-thread!rn;
dev = rt_device_find(argv[1]);
if (dev) {
log_i(open usb %s, argv[1]);
rt_device_open(dev, rt_device_flag_rdwr);
} else {
log_e(could not open vcom);
return -rt_error;
}
for (int i = 0; i < 10; ++i) {
log_i(send %d, i);
rt_device_write(dev, 0, buf, rt_strlen(buf));
rt_thread_mdelay(500);
}
rt_device_close(dev);
return rt_eok;
}
// msh_cmd_export(example_vcom, usb device vcom example)
msh_cmd_export_alias(example_vcom, cmd_vcom, usb device vcom example)

CEA-Leti发布“突破性”3D循序集成 (3DSI)
NVIDIA Mellanox网络的以太网被广泛应用于服务器等端到端的领域
LT8330单芯片满足众多工业和汽车应用的要求
日本农业IoT新突破,世界首款多功能土壤传感单芯片亮相
中兴通讯力推TD-SCDMA“多通道”室内覆盖解决方案
usb增加多路vcom的问题解析
根据数据看出各国之间的制造业机器人密度情况
一文解析光纤冷接和熔接的区别
数学模型如何捕获真实世界的信号失真
大力补贴新能源下乡,激励比亚迪等造车势力
MAX8903B 2A 1节Li+电池DC-DC充电器,用于
为什么Dc对于决定麦克风放置的位置很重要呢?
索尼Xperia 2曝光采用了带鱼屏设计和位于电源键上方的侧边指纹
闲话Zynq UltraScale+ MPSoC(连载4)
全国首例网约车交通事故宣判结果:交强险平台及司机均有责任
工业以太网交换机原理与应用
LinkedIn机器学习解决方案
为什么汽包液位计的指示灯有时不亮
开源芯片设计将迎来一次更大的升级
SiC MOSFET的设计和制造