簡介
 因項目需要,需要使用USB組合設(shè)備實現(xiàn)兩路虛擬串口并同時掛載虛擬U盤,rtthread目前默認(rèn)只支持一路虛擬串口,現(xiàn)在需要增加一路虛擬串口。
測試環(huán)境
 Rtthread版本:v4.1.0;
開發(fā)板:野火F407霸天虎V2;
計算機:windows11;
其他:串口調(diào)試助手、MobaXterm(作為shell終端)
已完成工作
 新增一路CDC vcom,初步完成了2路虛擬串口的掛載,用USB連接開發(fā)板和計算機后,計算機能夠識別出兩路串口,并且虛擬U盤也能夠使用;
遺留問題
 串口調(diào)試助手打開串口時,存在卡死的情況;
 兩路串口無法同時正常使用,在開發(fā)板寫的發(fā)送數(shù)據(jù)測試代碼,總有一路串口啟動后,計算機打開串口助手無法收到數(shù)據(jù)。
 出現(xiàn)上面兩個問題后,計算機顯示USB斷開,然后自動重新連接,但無法正常連接,顯示無法找到設(shè)備描述符。
 開發(fā)記錄
 前提條件
 已經(jīng)實現(xiàn)了USB組合設(shè)備配置模式下掛載虛擬串口和虛擬U盤。具體實現(xiàn)過程可參考其他開發(fā)者的文章,在此不做重復(fù)描述。
新增vcom
 通過查看rt-thread源碼,可知,各種USB設(shè)備的驅(qū)動代碼位于rt-threadcomponentsdriversusbusbdeviceclass目錄下,并且看到了虛擬串口設(shè)備驅(qū)動文件cdc_vcom.c以及其他各類如大容量存儲設(shè)備mstorage.c(用于虛擬U盤)等。所以我的思路就是最簡單直接暴力的方法,拷貝cdc_vcom.c并重命名為cdc_vcom2.c作為第二路虛擬串口驅(qū)動。

由于拷貝過來后避免編譯錯誤,所以需要修改,主要對cdc_vcom2.c修改如下:
修改設(shè)備名
由于設(shè)備名必須是唯一的,以及存在了vcom,故這里重新命名為vcom2。
#define VCOM_DEVICE "vcom2" // vcom->vcom2
 修改事件名和線程名
修改函數(shù)rt_usb_vcom_init內(nèi)代碼
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);
- 修改注冊函數(shù)
  避免函數(shù)重復(fù)定義,修改注冊函數(shù)部分,主要就是在函數(shù)名添加了后綴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
編譯后下載,運行后調(diào)試終端顯示錯誤:
endpoint assign error
端點分配錯誤。
通過定位發(fā)現(xiàn)在文件usbdevice_core.c的rt_usbd_device_add_config()函數(shù)中報錯:

進入函數(shù)rt_usbd_ep_assign()后通過調(diào)試發(fā)現(xiàn),USB設(shè)備的端點列表無法有效分配給各接口設(shè)備,而端點列表的定義位于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 },
 };
重新編譯,下載,連接開發(fā)板,計算機正常識別出了兩個串口:

目前就剩下前面所說的遺留問題了。
附錄
 串口測試代碼
 添加測試文件example_vcom.c,加入編譯,啟動后在調(diào)試終端輸入如下命令即可:
$ 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)
                        電子發(fā)燒友App
                    
                
                
          
        
        










           
            
            
                
            
評論