簡介
因項目需要,需要使用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)
評論
查看更多