1. 程式人生 > >從零開始學USB(六、USB通訊的資料格式)

從零開始學USB(六、USB通訊的資料格式)

USB中用NRZI來編碼資料

前面章節已經學習過了USB的引腳定義了,但是對於其中的USB 2.0的兩根資料線D+和D-所對應的資料傳輸,卻沒有詳細介紹。此處就是介紹,在此序列資料線中,資料是如何被編碼和傳送的。

USB所傳輸的資料,用的資料編碼方式是NRZI(Non-Return-to-Zero Inverted),其具體的含義解釋,看到有位網友已經非常清晰的分析過了,我就不重複造輪子了。

USB 的 NRZI 編碼

為了防止這位網友的伺服器出問題,下面我再複製一份。

這兩天繼續看 USB 相關的內容,準備用純軟體實現一下 USB 裝置傳輸,為將來的專案打好基礎。

首先碰到的就是這個 NRZI 編碼的問題了,基礎太薄弱,看了一上午總算明白了大概。

首先,USB 的資料是序列傳送的,就像 UART、I2C、SPI 等等,連續的01 訊號只通過一根資料線傳送給接受者。

但是因為傳送者和接收者執行的頻率不一樣,訊號的同步就是個問題,比如,接受者接收到了一個持續一段時間的低電平,無法得知這究竟是代表了5個0 還是1000個0。

一個解決辦法,就是在傳輸資料訊號的同時,附加一個時鐘訊號,用來同步兩端的傳輸,接受者在時鐘訊號的輔助下對資料訊號取樣,就可以正確解析出傳送的資料了,比如 I2C 就是這樣做的,SDA 來傳輸資料,SCL 來傳輸同步時鐘:

圖為I2C資料編碼格式

I2C資料編碼格式

 

雖然這樣解決了問題,但是卻需要附加一根時鐘訊號線來傳輸時鐘。有沒有不需要附加的時鐘訊號,也能保持兩端的同步呢?

有的,這就是 RZ 編碼(Return-to-zero Code),也叫做歸零編碼。

在 RZ 編碼中,正電平代表邏輯 1,負電平代表邏輯 0,並且,每傳輸完一位資料,訊號返回到零電平,也就是說,訊號線上會出現 3 種電平:正電平、負電平、零電平:

圖為歸零編碼

歸零編碼

 

從圖上就可以看出來,因為每位傳輸之後都要歸零,所以接收者只要在訊號歸零後取樣即可,這樣就不在需要單獨的時鐘訊號。實際上, RZ 編碼就是相當於把時鐘訊號用歸零編碼在了資料之內。這樣的訊號也叫做自同步(self-clocking)訊號。

這樣雖然省了時鐘資料線,但是還是有缺點的,因為在 RZ 編碼中,大部分的資料頻寬,都用來傳輸“歸零”而浪費掉了。

那麼,我們去掉這個歸零步驟,NRZ 編碼(Non-return-to-zero Code)就出現了,和 RZ 的區別就是 NRZ 是不需要歸零的:

圖為非歸零編碼

非歸零編碼

 

這樣,浪費的頻寬又回來了,不過又喪失寶貴的自同步特性了,貌似我們又回到了原點,其實這個問題也是可以解決的,不過待會兒再講,先看看什麼是 NRZI:

NRZI 編碼(Non-Return-to-Zero Inverted Code)和 NRZ 的區別就是 NRZI 用訊號的翻轉代表一個邏輯,訊號保持不變代表另外一個邏輯。

USB 傳輸的編碼就是 NRZI 格式,在 USB 中,電平翻轉代表邏輯 0,電平不變代表邏輯1:

圖為NRZ和NRZI

NRZ和NRZI

 

翻轉的訊號本身可以作為一種通知機制,而且可以看到,即使把 NRZI 的波形完全翻轉,所代表的資料序列還是一樣的,對於像 USB 這種通過差分線來傳輸的訊號尤其方便~

現在再回到那個同步問題:

的確,NRZ 和 NRZI 都沒有自同步特性,但是可以用一些特殊的技巧解決。

比如,先發送一個同步頭,內容是 0101010 的方波,讓接受者通過這個同步頭計算出傳送者的頻率,然後再用這個頻率來取樣之後的資料訊號,就可以了。

在 USB 中,每個 USB 資料包,最開始都有個同步域(SYNC),這個域固定為 0000 0001,這個域通過 NRZI 編碼之後,就是一串方波(複習下前面:NRZI 遇 0 翻轉遇 1

此外,因為在 USB 的 NRZI 編碼下,邏輯 0 會造成電平翻轉,所以接收者在接收資料的同時,根據接收到的翻轉訊號不斷調整同步頻率,保證資料傳輸正確。

但是,這樣還是會有一個問題,就是雖然接收者可以主動和傳送者的頻率匹配,但是兩者之間總會有誤差。

假如資料訊號是 1000個邏輯1,經過 USB 的 NRZI 編碼之後,就是很長一段沒有變化的電平,在這種情況下,即使接受者的頻率和傳送者相差千分之一,就會造成把資料取樣成 1001個或者 999個了。

USB中用Bit-Stuffing來同步時鐘訊號

USB對這個問題的解決辦法,就是強制插0,也就是傳說中的bit-stuffing,如果要傳輸的資料中有7個連續的1,傳送前就會在第6個1後面強制插入一個0,讓傳送的訊號強制出現翻轉,從而強制接受者進行頻率調整。接受者只要刪除6個連續 1 之後的0,就可以恢復原始的資料了。

 

當然在協議中,這兩點說的也比較清晰,對著協議看一下就可以知道NRZI的編碼規則。