2020年1月27日 星期一

USB DIY --- USB Host 端的軟體開發(四) Delay 有用嗎?

上回在 USB DIY --- USB Host 端的軟體開發(三) 與韌體之間的關係 的文章中,

有讀者提出關於在PC 端APP 軟體中,塞 Delay 有沒有用的問題。

我當然有簡單的提出說明,這是我在搞USB 系統中常碰到的問題。也是經驗。

但往往一般人一碰到這種問題,可能是搞軟體的人也真的不知道寫USB 裝置韌體的

工程師的想法,更不清楚USB 裝置韌體,所以就會自作主張的塞這一種方式來

解問題的。那為什麼會這一種想法呢?首先先說明一下:在PC APP 軟體端塞Delay

其實就是在C 語言裡加一行:Sleep(mSec);。很好用啊。為什麼,可以降低程式

執行速度,也好讓程式發展者容易除錯,最好也看看是否可以抓到USB 裝置韌體的

bug,那就可以順利的把問題往外推了。哈~哈~

因為USB 的通訊協定真的有點複雜,而且執行速度真的很快,而往往現在許多

現成的USB 裝置的驅動程式也都掌握在作業系統中,也真的沒有人想花那麼多時間

想去鑽研,所以在知其然不知所以然的情形下就很容易囫圇吞棗的亂搞一通了。

剛我最近碰到一個可以拿出來舉例說明的情形,藉此分享給各位:

我們都知道:USB HID Class 有一個很基本的通訊協定要求,那就是一定要有

Interrupt In -Token。這個主要就是拿來讓USB 裝置可以主動地以固定的時間(interval)

把一些訊息主動的傳輸給PC Host 端,因為USB 是屬於主從架構,往往是若PC Host 端

沒有下達任何命令或資料傳輸要求的話, USB 裝置可能也無法主動發送資料給PC端。

所以在 USB HID Class 的裝置宣告中,就得要明確的定義出這個間隔時間 Interval

為多少?上回讀者有提到這一時間到底有沒有甚麼作用呢?

那我們就利用這一例子一起說明給各位:


上圖就是一個很標準的  USB HID Class 的描述宣告。(Descriptor)

我們在這個範例中,宣告這個時間為 32 mSec 。
---

那接下來我們來看這個宣告參數在實際USB 系統開發中他所造成的影響是甚麼?

如果是一般我們是此用這一種 USB HID Class 來做系統的命令/資料傳輸的話,

有可能就是一個 Set Report 再搭配一個 Interrupt In 來完成一組命令/資料傳輸。

(當然你也可以用 Set Report 與Get Report 來做,但會比較複雜一點,因為Set Report

及Get Report 都是走 Setup Token (Endpoint 0),可能會造成USB 裝置系統的命令

解釋與解碼複雜度,在韌體維護上不方便。)

但在PC Host 端的上層程式就沒多大差別,反正就是下一組命令。然後再回讀

USB 裝置回復的內容。

 
就是上圖中的最上面那四組命令的搭配使用而已。

好了,我們就來看範例吧:


上圖就是一個很簡單的PC 端利用 Set Report 下了一組命令或資料傳輸,然後再由USB

裝置端利用 Interrupt In-Token (Endpoint 1) 來回覆接收結果。

結果呢?你看到了甚麼?怎麼會有兩組資料回覆呢?那請問一下:在PC 端上層的程式

會讀到哪一組呢?答案當然就是第二組(最後一組),結果答案是錯的。

完了。怎麼會這樣子呢?這下該由誰來除錯呢?是啊。整個通訊協定沒有不對的地方。

PC 軟體端的確也沒有讀到第一組回覆內容,你要微軟能怎麼辦?這種問題肯定會造成

PC 端軟體工程師與USB 裝置端系統工程師在那邊爭執,到底誰該去解呢?

喔~大家吵不完之下,這下神奇的 Sleep(mSec) delay 方法就出現了。

其實,這個問題連Delay 也救不了你,因為這是微軟的USB 底層驅動程式造成的,

那微軟的驅動程式是因為你的USB HID 描述宣告造成的。

要解這個問題要先從上圖中的Packet # 中的數字去觀察的。因為Packet# 數字就是代表

USB 通訊協定中的反應速率,也就是 Delay 可以發揮的空間啦。

如果我們仔細的解讀內容:



你看到了甚麼數字?對的~就是你自己在USB HID 裝置中宣告的 interval (32msec)。

所以啦,PC 端微軟的作業系統中的USB 底層驅動程式就會依照你的宣告

每隔 32 msec 就會來跟你USB 裝置要一次回覆資料,所以這個問題就出在USB 裝置

在兩者系統之間的 Handshake 中,不應該亂回這一筆資料的。所以問題是出在

USB 裝置韌體程式中,當然,如果要塞Delay 的話,那就應該把 Interval 的時間

加長的。這樣子也可以避開這個問題:


看到沒有?如果在 32 msec 之內,緊接著趕快下一筆Set Report 命令下來,

也是可以解的,但你永遠不知道PC 端微軟作業系統底層驅動程式的反應時間如何?

如果不同CPU 或不同版本的作業系統是否也會不同?這當然也會影響的。

這可能要去問微軟了。當然還有另一個解法:


 就是利用 USB 裝置中的硬體支援的 NAK 幫你擋一下,這也算是另類的Delay 方法。

至於怎麼在USB 裝置中,啟動這個機制,那就麻煩你自己要研究一下你所採用的

USB 裝置控制器的規格使用說明書了。(每一家USB MCU 的設定方法不同的。)

其實從上面那張圖也可以順便說明一下,其實不只是 Interrupt In -Token 會用 NAK 擋,

就連一般 Set Report 的Setup Token 也會擋的,就看你USB 裝置的韌體程式要怎麼寫囉。

所以你會發現:其實PC 端的USB 是很"兇"的,他真的是一路緊盯著你USB 裝置系統

拼命的傳資料與要資料的,只要稍微不慎,你可能就會發生意想不到的結果。

---

結語:搞USB 裝置系統及寫這一種文章,不比寫Arduino 開箱文那麼熱門與吃香。

但這個東西卻是許多碰到類似問題的人永遠難解的痛苦,只是想藉由簡單的經驗

分享,讓大家從另一個角度來了解其實我們在經常使用的 IT 產品的特性而已。

謝謝各位的閱讀與敬請指教。


沒有留言:

張貼留言