USB詳解


    USB作為一種串行接口,應用日益廣泛。如同每個工程設計人員必須掌握I2C,RS232這些接口一樣,我們也必須掌握USB.但是USB的接口協議實在有點費解,Linux UCHI驅動作者之一Alan Stern曾經就說過“The USB documentation is downright evil. Most of it is just crap, written by a committee. You're better off ignoring most of it ”。本文將從整體上介紹USB 協議,包括USB host ,USB hub,USB Function。希望能給讀者一個總體上的了解。也因此,文章將分成相應的三部分講解 。

一、USB Function

1、初識USB .

      USB 是一種串行接口協議,它靠D+,D-兩條數據線構成的差分線來進行數據傳輸,這讓我們非常感興趣它到底和我們通常熟悉兩線 RS232/485有何區別。了解這種區別有助於我們對USB 作一個深入的了           解。那么讓我們回想一下到底一個兩線RS232的數據是如何傳送的,如圖一:

USB詳解(轉) - 東海 - 東海的博客         在這里我們的重點在於,我們發現要在串行口傳送數據一個最體碼的要求恐怕就是:要知道數據傳輸何時開始,何時結束。即如何delimit.那么 RS232怎么做的。顯然,在idle(空閑)時,即無數據傳送時,       數據線處於高電平,等到有數據開始傳送,發送方首先拉低數據線(start),表示數 據傳輸開始,接受端也因為這個“start”信號開始准備接受即將到來的數據,類似一次握手,隨后,在兩者之間的數據傳送開始,     結束后主方再次拉高數據 線,表示結束傳輸,自此兩者重新進入Idle狀態。等待下一輪傳送開始。了解了RS232,那么我們自然想到USB如何做到這個呢,既然是串行位流傳輸,也理所當然的解決這個問題。沒         錯,USB協議必然要解決這個問題,讓我們作一個類似RS232的比較吧!類似於RS232,USB的傳輸楨如圖二:

USB詳解(轉) - 東海 - 東海的博客

        (這里我們暫時忽略這個傳輸所代表的意義)為了說明問題,我們對一些問題簡化,我們定義這樣幾個狀態:
        假設D+,D-分別表示USB信號線的電平信號。那么對於USB full speed Function(high speed ,low speed是不同的),我們定義差分數據線上可能出現的四個狀態:

        Data J state:D+=1,D-=0;

        Data K state:D+=0,D-=1;

        SE0:D+=D-=0;

        SE1:D+=D-=1;

       那么上面的圖中,相應的也可表示為圖三:

USB詳解(轉) - 東海 - 東海的博客

    這個對USB full speed Function來說,idle狀態將處於Data J state,se0表示一楨結束。看這個圖是不是很像我們熟悉的RS232。沒錯!!!他們確實很相似。在無數據傳輸時,它們都處於Idle狀態,當  要開 始傳輸數據時,先發一個sync(同步信號,RS232為start,USB為一sync字節,見協議說明)信號進行“握手”,而后開始傳輸,當傳輸要結 束時,發一stop信號(USB為一個se0狀態表示要結束傳輸),最  后又進入idle態等待新的傳輸。不過,你可能更加注意到,他們還是不同的。不同在 於USB是按"packet" 進行傳輸的,就是說它傳輸的最小單位是packet,而RS232是按字節傳送的,也即它的最小傳送單位是  字節。既然是按pakcet傳送,想想我們相較 於RS232的按字節單位傳輸,我們可以得到哪些“好處”。想想看,pakcet的好處不就在於我們可以靈活的定義數據的傳送格式,傳送方式,從而可以適 應各種各樣的  串行設備,這不就是所謂的“通用串行總線”嗎?

  簡介:從本節開始,我們將介紹USB的傳輸機制。這節先介紹USB現有傳輸方式的背景知識,做為對下節將要展開的四種傳輸類型,描述符,等相關知識的一個導引。

2、USB傳輸。
    我們在上一節中了解到了USB的“packet”的感念,了解到了USB傳送一個packet總是以sync開始,以 eop結束,這個稱為delimiter,即標記packet的始末。有了packet,我們就可以在USB總線上傳輸數據  了。但是這還不夠,比如數據傳 送方向,即傳回USB主機還是傳下USB從機,數據傳送的地址,數據傳送的類型(這些后面我們將會知道)這些信息在傳輸之前是必須搞清楚的,那么這個信息 如何得知呢,看來  這就需要我們定一套基於packet的“協議”了。主機與從機在傳輸中均遵循這套“協議”,那么這些問題就可以迎刃而解。事實上,USB的一次數據傳輸總是遵循這樣的“協議”的:

    首先,主機發第1個packet給從機,聲明數據傳送方向,數據傳輸地址,數據傳輸類型。
    其次,主機發第2個至第n個packet載有實際數據
    最后,從機返回一個packet是一個ACK包,報告數據傳輸的結果,比如接受出錯或成功等信息,這樣主機就可以借此了解到這次傳輸情況,從而有可能來作出相應措施如決定是否重發

  這里我們考慮的是主機發數據給從機的情況,那么從機發數據給主機時,是不是也可以這樣呢?當然可以,比如從機要發數據給主機時,也可以采取同主機類似的方式:

    首先,從機發第1個packet給主機,聲明數據傳送方向,數據傳輸地址,數據傳輸類型。
    其次,從機發第2個至第n個packet載有實際數據
    最后,主機返回一個packet是一個ACK包,報告數據傳輸的結果,比如接受出錯或成功等信息,這樣從機就可以借此了解到這次傳輸情況,從而有可能來作出相應措施如決定是否重發。

  基本上可以歸結為一個“三段式”傳輸

  這里有人可能注意到了,對這樣一個傳輸機制,從機和主機的功能將是一樣的,因為這樣的實現機制,從機可能在某一時刻是主機,某一時刻又可能是從機,因為他們要實現同樣的功能。這樣實現起來的復雜性也  將是一樣的。

  注:這里概念或許容易混淆,其實,我們這里的主機(master)和從機(slaver)是一個transceiver,即可收可發。相應的,在某一時刻,master在發數據,我們稱其為transmitter,在接受時我們稱為receiver.對     slaver同樣。

    我們可能還注意到了,USB這種按pakcet傳輸的方式在實現時已經很復雜了(至少比RS232要復雜多吧),至少我們目前看來主從機功能一樣這 樣的實現方式似乎還是可行,但是后面我們談到USBhost時將  會了解到host的功能是如何的復雜,以至於讓一個USBFunction 也帶上如此的功能成本和實現復雜性將陡然上升。作為面向廣范應用的USB,這是我們不允許的。我們期望的是一個使用USB的udisk,使用USB  的光驅,使用USB的耳麥等等這些東西不要因為USB而變得昂貴,復雜。正是因為這個原因,USB從機的傳輸發式便由上面的方式改成了下面的方式進行:

    首先,主機發第1個packet給從機,聲明數據傳送方向,數據傳輸地址,數據傳輸類型。
    其次,從機收到主機送來的第一個packet后,再發第2個至第n個packet載有實際數據
    最后,主機返回一個packet是一個ACK包,報告數據傳輸的結果,比如接受出錯或成功等信息,這樣從機就可以借此了解到這次傳輸情況,從而有可能來作出相應措施如決定是否重發。

  而對於USB主機傳輸方式保持不變。

    對於這樣的改變,我們馬上就有疑問了:這個改變的傳輸方式是和未改變之前的等價嗎。當然,不全等價。問題在哪里?仔細觀察一下便知,兩者區 別在於第一個packet是由誰發起的。未改變之前,第一個  packet總是由要傳送數據的一方發起,而改變之后的第一個Packet總是由主機發起。這 樣,就變成如果從機要發送數據給主機時,總是由主機發起(第一個packet),然后從機開始傳送。
  可能初次接觸我們會感覺怪怪的,怎么從機要給主機發送數據前反而要主機先發packet給從機。   這樣行嗎,我們要說這樣是可以的,因為通常一次傳輸交互的產生,並非無來由的產生,這些都是由程序員控制  的,控制USB何時收,何時發,及發給誰!!!

    這里我們就注意到了,USB Function(總是作為從機)的功能一下從原來與主機具有相同功能的tranceiver變成了現在僅具發送(或接收)功能的transmitter(或Receiver)實現的復雜性及成本可想而知也  就相應得減小了。

  簡介:本節介紹USB full speed Function的四種傳輸類型。 


    上節中我們了解到了USBhost 與USBFunction 之間采用的是一種“非對稱”的傳輸,也就是說,無論USB接受數據還是發送數據,都是由USBhost首先發起。即傳輸的第一個packet總是由USBhost發出   的。這個packet將聲明本次即將進行的數據傳輸方向,數據傳輸地址和數據傳輸類型。 

Control Transfers)

     或許你已經注意到了,一個USBhost端口並不是僅僅支持一個USBFunction.如圖1,

USB詳解(轉) - 東海 - 東海的博客

    通過USB hub,一個USB host端口可以連接USB鼠標,USB鍵盤,USB寫字板......。要連接這么多東西在同一個USB host上,我們通常會有一個基本問題,即USB host如何識別這些被連接在它的端口上  的設備呢。正如通常的主從式通訊系統一樣,如rs485多機通訊,我們通常是用一個特定的地址標志每一個從設備。 對這里的USB,我們采用同樣的方法,將為每個掛接在該USB host上的USB Function指定一個  特定地址,通過這個特定地址來識別每個USB Function.看來這將是一個USB Function在數據傳輸之前必須解決的問題--得到它的地址分配。

    這個“地址指定”的過程需要USB host通知USB Function才能完成,這個交互過程就是一個控制式傳輸。通過這個“控制式傳輸”,USB host將指定地址給USB Function ,以為即將進行的正式通訊做好准備  工作。這里細心的讀者可能已經注意到了,既然USB host總要分配地址給USB Function才能進行正式的數據傳輸工作,那么USB host將如何與一個初始時未分配地址的USB Function進行交互來分配地址呢。  這里,是這樣解決的:USB協議保留了一個“通用地址”0,USB host 通過這個地址0來和初始未分配地址的USB Function進行通訊,進行一些初始的准備工作,諸如這里的為它非配一個特定地址。后面我們就會  了解到,USB除了配置地址外,還有一些其它參數需要 事先主從雙方達成共識。這些參數也都是通過控制式傳輸完成的。一個USB的控制式傳輸如圖二示:

USB詳解(轉) - 東海 - 東海的博客

  一個USB的控制式傳輸總是分為兩個或三個階段進行傳輸:setup stage,data stage(視情況而定),status stage。 

  1. 首先是setup stage,聯系上節所說的USB傳輸模式,USBHost總是先發起第一個packet--這里它
    1. 首先發起setup,
    2. 之后發起以data0為起始的setup data,
    3. 最后USBFunction回應ack結束一次交互。
  2. 其次如果有data stage,類似的,還是按照上節說的USB傳輸模式,
      1. USBhost總是先發起第一個Packet--Out(或in),
      2. 之后USBhost(或USBFunction)發起以data1為起始的payload data,
      3. 最后USBfuction(或USBhost)回應ack結束一次交互。
    1. 如果數據未傳完,繼續data stage,同上繼續。
  3. 最后是status stage,類似的,
    1. USBhost首先發起第一個Packet--in(或out),
    2. 之后USBFunction(或USBhost)發起以data1為起始的Null data(0長度),
    3. 最后USBhost(或USBFunction)回應ack結束一次交互。

    如此,整個控制式傳輸結束。 你或許有疑問,data stage為什么進行了多次而非一次完成?實際上,USB總是將一批大量的數據分成了許多小段來進行傳輸,稱為一個pay load。這樣傳輸的目的是容易對傳  輸進行控制。既然一次大量的數據總是被分成一段一段來分次傳輸,那么這里就出現了一個需要事先確定的參數 (wMaxPacketSize):即每次這個小段有多大。這個參數如地址指派一樣,正式傳輸之前需要事  先達成共識。通過控制式傳輸,現在我們已經完成了 USBFunction的地址指定等參數的設置工作,下一步可以進行正式的數據傳輸了。

bulk Transactions

  我們終於等到USBFunction 配置完成,現在我們的任務是要傳送一批數據,這里可以使用批量數據傳輸(bulk Transactions)。 一個批量傳輸總是按照如圖所示方式進行,

USB詳解(轉) - 東海 - 東海的博客

  1. 首先,USBhost發起第一個Packet--in(或out),表示要開始數據傳輸了。
  2. 其次,USBFunction(或USBhost)發起以data1(或data0)為起頭的payload data,開始一次交互。
  3. 再其次,USBhost(或USBFunction)發起ack回應這次交互。 如果數據還為傳完,繼續上述過程,即:
    1. 首先,USBhost再次發起一個Packet--in(或out),表示又要開始數據傳輸了。
    2. 其次,USBFunction(或USBhost)發起以data0(或data1)為起頭的payload data,開始又一次交互。
    3. 再次,USBhost(或USBFunction)發起ack回應這次交互。
    如此繼續直至傳輸完成

    這里的疑問依然是為什么一次可能傳完的數據為什么分成多次進行傳輸,原因在上次介紹控制式傳輸式已經說明。后面我們就會明白,為什么這樣可以方便控制傳輸過程。 仔細看看控制式的data stage采用的  傳輸方式,是否就是批量傳輸方式呢?!注意,每次payload data的“牽頭人”(preamble)在輪番掉換,最先是data1,接着data0,再是data1,......如此接替,只要有一次交互出現問題,這個接替規則就會被打破  進而被USBhost識別而發現傳輸異常。所以這個交替的“牽頭人”規則是可靠數據傳輸的所采取的措施之一。 

  Isochronous Transactions)和中斷式傳輸(Interrupt Transactions

    在批量數據傳輸中,觸發一次批量數據傳輸總是“被動”的,就是說需要數據傳輸時USBhost並不會主動發起傳輸,而是需要得到你的指令。當你告訴它:“一切ok,讓我們開始吧!” 這時它才開始數據傳輸。  這種方式顯然在某些情況下並不適合。比如音視頻流,你無法要求它聽從你的“指揮”,讓它等你發指令給USB host,然后開始一次傳輸。我們需要的是一種“及時”傳輸。一個好的方案就是設置一個timer,按照tick  發起USB傳輸。這個tick通常以 1ms(USBfull speed)為最小單位。這時,可以設置為每次1ms tick出現,USB host“自動”發起一次數據傳輸。那么這種方案具體如何來實現呢?看來最基本的要素便是一個發出  tick的timer,而這個“timer”需要USBhost和USBFunction(事實上還要包括USBhub)雙方均能“看到”,從而協調工作,否則單方面的timer又有何意義?這個"timer"(或tick)在USB中使用一個特殊的packet實   現,即是SOF。這個SOF由USB HOST 相當精確的以每1.00 ms ±0.0005 ms的時間周期發送給USBdevice,來在二者之間定時。從而USB Function能夠“及時”的了解到“現在時刻”。 現在我們在USBhost和  USBFunction之間建立起了“對時”機制。那么接下來看看剛才設想的“自動”傳輸如何實現。事實上,一旦USBhost及USBFunction雙方建立了一種時間機制,那么這種“自動”傳輸是很容易實現的。USB實現同步  式傳輸或中斷式傳輸總是以一種類似於批量數據傳輸的方式進行的,唯一不同的是傳輸的觸發不再是“被動”的,而是由SOF所建立的tick觸發。

  1. 首先,時間到達,USBhost發起第一個Packet--in(或out),表示要開始數據傳輸了。
  2. 其次,USBFunction(或USBhost)發起以data1(或data0)為起頭的payload data,開始一次交互。
  3. 再其次,如果是中斷式傳輸,USBhost(或USBFunction)發起ack回應這次交互,如果是同步式傳輸,該步跳過。

  如此重復上述步驟,即USBhost等待下一個tick到達,並開始新一輪的交互。

  這里我們注意到了,同步式傳輸和中斷式傳輸二者雖然都是時間觸發,但是中斷式傳輸需要ack應答,而相反,同步式傳輸不需要。這個最大的區別決定了 同步式傳輸是一種非可靠傳輸,但是因此換來了更多的    USB傳輸時間。也因此,同步式傳輸的 payload data(對應wMaxPacketSize )通常相較於其他傳輸方式比較大,因為它消掉了ack所占有數據傳輸時間。這里還有一個地方值得注意的是tick的設定,這個tick也  是需要事先USBhost 和USBFunction達成共識的參數之一。

 

摘自:http://blog.chinaunix.net/uid-12461657-id-3044136.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM