Saturday, October 11, 2014

RS232 over USB 簡介

RS232 over USB就是所謂的USB UART。現在這個東西會流行的原因,主要是現在很多電腦根本就沒有COM port,所以只好用USB來橋接並模擬UART。下圖是個很簡單的示意圖,會有這種需求的大多是工程師吧...。


USB對於這個東西的規範是落在Communication Device Class內,縮寫就是CDC。以下都用CDC描述。因為CDC包含太多類別了,所以CDC規格書裡面有定義這些類別的對應規格:


RS232 over USB是屬於Abstract  Control Model這個類別裡,所以請參考USBPSTN這個規格書吧,以下都會用CDC-ACM來代表RS232 over USB。

翻開PSTN規格書,它裡面定義了三種Model:
  • Direct Line Control Model 
  • Abstract Control Model 
  • Telephony Control Model 
本文只介紹Abstract Control Model,因為它就是我們要的。注意一下,因為UART並不需要支援AT command,所以Class Protocol Code可以是0:

接著就是如何寫CDC-ACM的descriptor了。請注意,CDC規格定義一個CDC裝置必須支援兩個Interface,一個Interface描述這個function所支援的功能,而另外一個則是描述資料傳輸的通道。然而,如果一個裝置宣告它支援兩個Interface,一般就表示它支援兩個function。這很明顯跟USB 2.0規範相衝突,所以IAD就上場啦。IAD全名是Interface Association Descriptor,它的功用就是拿來宣告某幾個interface其實是屬於同一個function,這樣就解決這個問題。IAD的規格現在已經包含在USB2.0之內,usb.org可以下載的到。

CDC規格有規定第一個interface要額外支援的descriptor:
  • Header Functional Descriptor:沒甚麼特殊,照抄即可。
  • Union Functional Descriptor :沒甚麼特殊,照抄即可。
  • Country Selection Functional Descriptor:雖然說是必須的,但是好像不用提供也可以?
  • Interrupt Endpoint Descriptor (Optional) :雖然說是非必須,但是最好要提供?
PSTN規格還規定第一個Interface要額外支援的Descriptor:
  • Call Management Functional Descriptor:比較值得注意的是bmCapability這個欄位,其實都是0就可以了...。
  • Abstract Control Management Functional Descriptor:一樣,比較值得注意的是bmCapability這個欄位,只要支援D1這個bit就可以,其他的就看要不要支援了。

而第二個Interface則是很簡單,它單純只是宣告資料傳輸的途徑:
  • Standard Interface Descriptor
  • Bulk-In Endpoint Descriptor
  • Bulk-Out Endpoint Descriptor 
接下來是CDC-ACM必須支援的Class Requests:


如果只是要實作CDC-ACM,其實不用管SendEncapsulatedCommmand跟GetEncapsulatedResponse,因為不用支援AT command,所以Host根本就不會發這兩個Class Request。SetLineCoding、GetLineCoding、跟SetControlLineStatus則是要支援,因為我們在Abstract Control Management Functional Descriptor內的bmCapability欄位說有支援。

提供正確的descriptor給Host之後,Host就會認到你的CDC-ACM裝置,如果你用任何一個Terminal工具像是TeraTerm去開啟它的話,Host會透過SetLineCoding跟SetControlLineStatus去設定這個CDC-ACM的屬性,而你的裝置就應該可以開始傳輸資料了。運氣好的話,就可以在TeraTerm內看到一些字了。

市面上有蠻多便宜的CDC-ACM裝置,他們的主要缺點是,只要印多一點的字,就會開始印亂碼,我猜這主要是因為這些裝置通常內建記憶體很小,當從實體UART來的資料超多時,他們就會來不及把這些資料傳給Host,然後就開始掉字,如果很不幸,掉的是一些控制字元,就會出現亂碼了。便宜沒好貨啊。

10 comments:

said...

現在才入坑 windows usb driver開發
windows document上都只剩下最新的WDF的function可用
請問PO主知不知道WDM版本的

OD said...

書的話Amazon還是找的到啊?不然看微軟的線上說明應該也夠了:
https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/introduction-to-wdm

said...

我想請問 在driver的程式內 USB descriptor是不是只能 get 不能 set
我想讓我寫的virtual com driver被辨認為CDC

設定desciptor必須在Win32 app下嗎

OD said...

你是要寫個虛擬的USB driver嗎?
這有點複雜耶,我記得要掛到某個bus driver上才可以。sample code這裡應該有
https://github.com/microsoft/Windows-driver-samples/tree/master/usb。

不過如果只是要寫個虛擬的comport driver,會比較簡單。虛擬的USB CDC driver感覺沒有甚麼好處。

said...

感謝回覆
virtual comport driver我已經完成
我現在正在想辦法 讓實體裝置也能使用這份我寫的inf和sys
虛擬和實體comport應該差不了太多 (可能實體com port 會需要更多IRP處理? 但大部分IRP我已經處理完)

然後再想辦法 插入USB時能將此份 com port 辨認成 CDC USB (應該是開URB去拿Descriptor?)

我再慢慢研究QQ

OD said...

等一下,不對啊,你的virtual comport driver是真的需要跟實體USB driver溝通的喔?如果是這樣的話,為什麼還要這樣做?要嘛它是個標準的USB CDC裝置,要嘛它不是。前者你不需要寫windows driver(Windows已經內建),後者你只要把你的virtual comport driver掛到USB bus driver上就好了啊,根本就不需要是CDC裝置,只要Windows認為它是個compport就好。

said...

應該是後者喔
所以我只要將我的 virtual com port 掛在 windows usb bus driver上 windows 就會認為他是CDC USB 且辨識成comport嗎

https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/usb-3-0-driver-stack-architecture

應該是掛在這裡的sys上?

另外我想問 我寫了Win32可以跟我的comport溝通 簡單的設定baudrate Line control 並且可以收發資料

那麼我想讓我丟資料到comA 上 然後能在comB上收到 兩個com port中間是不是還缺少 null modem

如果是跑在單個機器上的兩個virtual com port溝通應該叫 virtual null modem?
這部分應該是中間寫一個win32嗎? 還是也是在virtual com port裡的code實作呢?

said...

阿抱歉
看起來Null modem的機制應該是實作在driver內
我用了com0com的 virtual com port 寫了Win32 app 去對配對起來的其中之一的comport作WriteFile的動作 另一個comport則是作 ReadFile的動作

發現資料有正確的流到另一端 猜測是裡面多create device object當上層bus並讓兩個port成為下層 藉此互通 當然可能還要實作很多 IOCTL細節

我自己再Trace code看看它到底做了什麼QQ

OD said...

我還是不太懂你最後要做的東西到底是甚麼 :(

感覺你只是要弄個虛擬的comport driver然後作一些資料傳輸,但是其中是沒有真正的硬體存在的。這樣子的話要怎樣都可以啊。

said...

是我沒有表達清楚

其實要做的目標不只一個

1.實現virtual com port 和 類似virtial modem的功能讓 一對com port互相傳輸
2.實現實體com port 並且可以資料傳輸
3.實現實體CDC USB 讓windows辨識其為virtual com port 並且可以資料傳輸

其實3 windows有內建Usbser 但我並不打算使用Usbser

而我現在只完成1的virtual com port 並驗證可以對com port丟資料 接下來是virtual modem讓com port形成pair使資料流通

codeblock