建設一個網(wǎng)站大概費用大連seo網(wǎng)站推廣
USB是很常用的接口,目前大多數(shù)的設備都是USB接口的,比如鼠標、鍵盤、USB攝像
頭等,在實際開發(fā)中也常常遇到USB接口的設備,本章就來學習一下如何使能Linux內核自帶的USB驅動。這里不會具體學習USB的驅動開發(fā)。
USB接口簡介
什么是USB
USB全稱為Universal Serial Bus,翻譯過來就是通用串行總線。由英特爾與眾多電腦公司提出來,用于規(guī)范電腦與外部設備的連接與通訊。目前USB接口已經得到了大范圍的應用,已經是電腦、手機等終端設備的必配接口,甚至取代了大量的其他接口。比如最新的智能手機均采用USB TypeC取到了傳統(tǒng)的3.5mm耳機接口,蘋果最新的MacBook只有 USB TypeC接口,至于其他的HDMI、網(wǎng)口等均可以通過USB TypeC擴展塢來擴展。
按照大版本劃分,USB目前可以劃分為USB1.0、USB2.0、USB3.0以及正在即將到來的USB4.0。
- USB1.0:USB規(guī)范于1995年第一次發(fā)布,由Inter、IBM、Microsoft等公司組成的USB-IF(USB Implement Forum)組織提出。USB-IF在1996年正式發(fā)布USB1.0,理論速度為1.5Mbps。1998 年USBIF在USB1.0的基礎上提出了USB1.1規(guī)范。
- USB2.0:USB2.0依舊由Inter、IBM、Microsoft等公司提出并發(fā)布,USB2.0分為兩個版本:Full-Speed和High-Speed,也就是全速(FS)和高速(HS)。USB2.0 FS的速度為12Mbps,USB2.0 HS速度為480Mbps。目前大多數(shù)單片機以及低端Cortex-A芯片配置的都是USB2.0接口,比如STM32MP157。USB2.0全面兼容USB1.0標準。
- USB3.0:USB3.0同樣由Inter等公司發(fā)起的,USB3.0最大理論傳輸速度為5.0Gbps,USB3.0引入了全雙工數(shù)據(jù)傳輸,USB2.0的480Mbps為半雙工。USB3.0中兩根線用于發(fā)送數(shù)據(jù),另外兩根用于接收數(shù)據(jù)。在USB3.0的基礎上又提出了USB3.1、USB3.2等規(guī)范,USB3.1理論傳輸速度提升到了10Gbps,USB3.2理論傳輸速度為20Gbps。為了規(guī)范 USB3.0標準的命名,USB-IF公布了最新的USB命名規(guī)范,原來的USB3.0和USB3.1命名將不會采用,所有的3.0 版本的USB都命名為 USB3.2,以前的USB3.0、USB3.1和USB3.2分別叫做USB3.2 Gen1、USB3.2 Gen2、USB3.2 Gen 2X2。
- USB4.0:目前還在標準定制中,目前還沒有設備搭載,據(jù)說是在Inter的雷電3接口上改進而來。USB4.0的速度將提升到了40Gbps,最高支持100W的供電能力,只需要一根線就可以完成數(shù)據(jù)傳輸與供電,極大的簡化了設備之間的鏈接線數(shù),期待USB4.0設備上市。
如果按照接口類型劃分的話USB就要分為很多種了,最常見的就是USB A插頭和插座,如下圖所示:
使用過JLINK調試器的朋友應該還見過USB B插頭和插座,USB B插頭和插座如下圖所示:
USB插頭在不斷的縮小,由此產生了Mini USB接口,Mini USB插頭和插座如下圖所示:
比Mini USB更小的就是Micro USB接口了,以前的智能手機基本都是Micro USB接口的,Micro USB插頭和插座如下圖所示:
現(xiàn)在最流行的就是USB Typec了,正點原子的STM32MP1開發(fā)板使用的是USB Typec接口,USB Typec插頭和插座如下圖所示:
USB電氣特性
Mini USB電氣屬性
先以Mini USB為例講解一下USB的基本電氣屬性。Mini USB線一般都是一頭為USB A插頭,一頭為Mini USB插頭。一共有四個觸點,也就是4根線,這四根線的順序如下圖所示:
如上圖所示,USB A插頭從左到右線序依次為 1,2,3,4,第1根線為VBUS,電壓為5V,第2根線為D-,第3根線為D+,第4根線為GND。USB采用差分信號來傳輸數(shù)據(jù),因此有D-和D+兩根差分信號線。仔細觀察的話會發(fā)現(xiàn)USB A插頭的1和4這兩個觸點比較
長,2和3這兩個觸點比較短。1和4分別為VBUS和GND,也就是供電引腳,當插入 USB的時候會先供電,然后再接通數(shù)據(jù)線。拔出的時候先斷開數(shù)據(jù)線,然后再斷開電源線。
再觀察一下Mini USB插頭,會發(fā)現(xiàn)Mini USB插頭有5個觸點,也就是5根線,線序
從左往右依次是1-5。第1根線為VCC(5V),第2根線為D-,第3根線為D+,第4根線為ID,第5根線為GND??梢钥闯?strong>Mini USB插頭相比USB A插頭多了一個ID線,這個ID線用于
實現(xiàn)OTG功能,通過ID線來判斷當前連接的是主設備(HOST)還是從設備(SLAVE)。
USB是一種支持熱插拔的總線接口,使用差分線(D-和 D+)來傳輸數(shù)據(jù),USB支持兩種供電模式:總線供電和自供電,總線供電就是由USB接口為外部設備供電,在USB2.0下,總線供電最大可以提供500mA的電流。
USB拓補結構
USB是主從結構的,也就是分為主機和從機兩部分,一般主機叫做Host,從機叫做Device。主機通過USB A插座來連接外部的設備,比如電腦作為主機,對外提供USB A插座,可以通過USB線來連接一些USB設備,比如聲卡、手機等。因此電腦帶的USB A插座數(shù)量就決定了能外接多少個USB設備,如果不夠用的話可以購買USB集線器來擴展電腦的USB插口,USB集線器也叫做USB HUB,USB HUB如下圖所示:
上圖是一個一拖四的USB HUB,也就是將一個USB接口擴展為4個。主機一般會帶幾個原生的USB主控制器,比如STM32MP1就有兩個原生的USB主控制器,因此STM32MP1
對外提供兩個USB接口,這兩個接口肯定不夠用,正點原子的STM32MP1開發(fā)板上有6個HOST接口,六路都是USB2通過USB HUB芯片擴展出來的,稍后會講解其原理圖。
雖然可以對原生的USB口數(shù)量進行擴展,但是不能對原生USB口的帶寬進行擴展,比如STM32MP1的兩個原生USB口都是USB2.0的,帶寬最大為480Mbps,因此接到下面的所有USB設備總帶寬最大為480Mbps。
USB只能主機與設備之間進行數(shù)據(jù)通信,USB 主機與主機、設備與設備之間是不能通信的。因此兩個正常通信的USB接口之間必定有一個主機,一個設備。為此使用了不同的插頭和插座來區(qū)分主機與設備,比如主機提供 USB A插座,從機提供Mini USB、Micro USB 等插座。在一個USB系統(tǒng)中,僅有一個USB主機,但是可以有多個USB設備,包括USB功能設備和USB HUB,最多支持127個設備。一個USB主控制器支持128個地址,地址0是默認地址,只有在設備枚舉的時候才會使用,地址0不會分配給任何一個設備。所以一個USB主控制器最多可以分配127個地址。整個USB的拓撲結構就是一個分層的金字塔形,如下圖所示:
上圖中可以看出從Root Hub開始,一共有7層,金字塔頂部是Root Hub,這個是USB控制器內部的。圖中的Hub就是連接的USB集線器,Func就是具體的USB設備。
USB主機和從機之間的通信通過管道(Pipe)來完成,管道是一個邏輯概念,任何一個USB設備一旦上電就會存在一個管道,也就是默認管道,USB主機通過管道來獲取從機的描述符、配置等信息。在主機端管道其實就是一組緩沖區(qū),用來存放主機數(shù)據(jù),在設備端管道對應一個特定的端點。
USB OTG
USB分為HOST(主機)和從機(或DEVICE),有些設備可能有時候需要做HOST,有時候又需要做DEVICE,配兩個USB口當然可以實現(xiàn),但是太浪費資源了。如果一個USB接口既可以做HOST又可以做DEVICE那就太好了,使用起來就方便很多。為此,USB OTG 應運而生,OTG是On-The-Go的縮寫,支持USB OTG功能的USB接口既可以做HOST,也可以做DEVICE。為了區(qū)分當前的工作狀態(tài),這里就引入了ID線這個概念,前面講解USB電氣屬性的時候已經說過了,Mini USB插頭有5根線,其中一條就是ID線。ID線的高低電平表示USB口工作在HOST還是DEVICE模式:
- ID=1:OTG設備工作在從機模式。
- ID=0:OTG設備工作在主機模式。
支持OTG模式的USB接口一般都是Mini USB、Micro USB 等這些帶有ID線的接口。正點原子的STM32MP1開發(fā)板OTG模式是使用USB Type C做接口,沒有ID線。USB Type C有自己的識別方法,稍后會講解TypeC接口電氣屬性。正點原子的STM32MP157開發(fā)板USB_OTG連接到了STM32MP1的USB1接口上。如果要使用OTG的主機模式,那么就需要一根OTG線,TypeC接口的OTG線如下圖所示:
可以看出,TypeC OTG線一頭是USB A插座,一頭是Typec插頭,將TypeC插頭插入機器的TypeC口上,需要連接的USB設備插到另一端的USB A插座上,比如U盤。TypeC的CC引腳檢查到USB設備已經接入,就會建立USB設備為主模式,機器就知道自己要做為一個主機,用來連接外部的從機設備(U 盤)。
STM32MP1 USB接口簡介
STM32MP157提供了兩個USB2.0接口,這兩個USB接口都是支持高速模式,也就是480Mbit/S,這兩個USB接口都內置了高速PHY。其中USB2支持OTG功能,正點原子STM32MP157開發(fā)板上的USB OTG接口就是鏈接到USB2接口上的。USB1接口連接了一個HUB芯片,實現(xiàn)了USB Host接口擴展。
STM32MP1內部集成了三個跟USB相關的控制器名字分別為:USB OTG控制器、USB Host控制器和USB HS PHY控制器,提供一個簡稱方便書寫:OTG、USBH和PHY。接著分析一下這三個控制器是如何工作的。
PHY控制器
PHY(英語:Port Physical Layer),中文可稱之為端口物理層,是一個對OSI模型物理層的共同簡稱。PHY控制器主要是提供兩個端口,端口1已經規(guī)定分配給USB Host控制器,端口2可以分配給USB OTG和USB Host。
OTG控制器
此控制器是支持OTG功能,它的內部特性如下所示:
- 此控制器有一個獨立的內核USB OTG HS。
- 該控制器支持HS、FS和LS模式,不管是主機還是從機模式都支持HS/FS/LS,硬件支持OTG信號、會話請求協(xié)議和主機協(xié)商協(xié)議,支持8個雙向端點,還支持PHY接口。
- 內嵌一個DMA。
- 支持片上全速PHY、連接外部全速PHY的I2C接口和連接外部高速PHY的ULPL接口。
- 具有采用高級FIFO控制的4 KB專用RAM。
OTG控制器有兩個模式:正常模式(normal mode)和低功耗模式(low power mode)。OTG控制器都可以運行在高速模式(HS 480Mbps)、全速模式(LS 12Mbps)和低速模式(1.5Mbps)。正常模式下每個OTG控制器都可以工作在主機(HOST)或從機(DEVICE)模式下,每個USB控制器都有其對應的接口。低功耗模式顧名思義就是為了節(jié)省功耗,USB2.0 協(xié)議中要求,設備在上行端口檢測到空閑狀態(tài)以后就可以進入掛起狀態(tài)。在從機(DEVICE)模式下,端口停止活動3ms以后OTG控制器內核進入掛起狀態(tài)。在主機(HOST)模式下,OTG控制器內核不會自動進入掛起狀態(tài),但是可以通過軟件設置。不管是本地還是遠端的USB主從機都可以通過產生喚醒序列來重新開始USB通信。
USBH控制器
USBH控制器這是一個主機控制器,此控制器由EHCI控制器和OHCI控制器組成。USBH控制器只能做主機模式。
這里簡單提一下OHCI、UHCI、EHCI和xHCI,這四個是用來描述USB控制器規(guī)格
的,區(qū)別如下:
- OHCI:全稱為Open Host Controller Interface,這是一種USB控制器標準,廠商在設計USB控制器的時候需要遵循此標準,用于USB1.1標準。OHCI不僅僅用于USB,也支持一些其他的接口,比如蘋果的Firewire等,OHCI由于硬件比較難,所以軟件要求就降低了,軟件相對來說比較簡單。OHCI主要用于非X86的USB,比如擴展卡、嵌入式USB控制器。
- UHCI:全稱是Universal Host Controller Interface,UHCI是Inter主導的一個用于USB1.0/1.1的標準,與OHCI不兼容。與OHCI相比UHCI硬件要求低,但是軟件要求相應就高了,因此硬件成本上就比較低。
- EHCI:全稱是Enhanced Host Controller Interface,是Inter主導的一個用于USB2.0的USB控制器標準。EHCI僅提供USB2.0的高速功能,至于全速和低速功能就由OHCI或UHCI來提供。
- xHCI:全稱是eXtensible Host Controller Interface,是目前最流行的USB3.0控制器標準,在速度、能效和虛擬化等方面比前三個都有較大的提高。xHCI支持所有速度種類的USB設備,xHCI出現(xiàn)的目的就是為了替換前面三個。
通俗來講,OHCI就是FS模式,也就是低速模式,EHCI是HS模式,也就是高速模式。
USB Typec電氣屬性
USB TypeC接口引腳定義
STM32MP157有兩個USB2接口,所以可以直接使用Mini USB或者Micro USB。但是目前USB TypeC接口非常普及,為了方便使用,正點原子STM32MP157開發(fā)板上的USB接口采用了TypeC。
接下來就看一下USB TypeC接口(根據(jù)USB協(xié)議,也叫做USB3.1接口)電氣屬性,由于TypeC功能比較復雜,比如支持PD充電、顯示、音頻等,這里只講解一下TypeC的數(shù)據(jù)
通信部分。首先來看一下TypeC的接口定義,這里只看母頭的引腳定義,如下圖所示:
從上圖中可以看出,標準的USB TypeC有24根線,分為上下兩部分,明顯比前面講的Mini USB要多不少引腳,這些引腳按照功能分類:
- A1、A12、B1、B12:這4個引腳為GND。
- A2、A3、B2、B3:這4個引腳是USB3.1特有的,為超高速差分發(fā)送信號線,這個是USB2.0和USB1.0所沒有的。
- A10、A11、B10、B11:這4個引腳也是USB3.1特有的,為超高速差分接收信號線,這個也是USB2.0和USB1.0所沒有的。
- A4、A9、B4、B9:VBUS引腳,這個USB2.0也有。
- A5、B5:CC1和CC2這2個引腳為USB3.1特有的配置通道引腳。Type-C的插座中有兩個CC腳,USB通信中的角色檢測都是通過CC腳進行的。對于TypeC插頭或者線纜正常只有一個CC引腳,兩個端口連接在一起之后,只存在一個CC引腳連接,通過檢測哪一個CC有連接,就可以判斷連接的方向。如果USB線纜中有需供電的器件,其中一個CC引腳將作為VCONN供電。
對于正點原子linux驅動教程里的USB章節(jié)來說,主要使用CC1和CC2引腳來實現(xiàn)USB OTG功能。 - A8、B8:SBU1和SBU2引腳,這兩個并不是USB信號,而是用作其他功能的,比如TypeC作為DP接口使用的時候SBU用作音頻傳輸通道。
- A6、A7、B6、B7:這4個引腳就是USB2.0的D+和D-,因為USB3.1要兼容USB2.0和USB1.0接口,所以必須要有D+和D-。
仔細看上圖可看出,上下兩排引腳是對應的,比如(A1,B1)、(A2,B2)等,一直到(A12,B12)。這是因為USB3.1要有能夠正反插,因此上下兩排引腳肯定要是一樣的,這樣才能在正反插的時候都能正常工作。
上圖是TypeC接口標準的24P母頭引腳,在進行TypeC母頭選型的時候會發(fā)現(xiàn)也有16P甚至6P封裝的接口。比如正點原子STM32MP157開發(fā)板上使用的就是16P的TypeC母座,16P 的母座引腳結構如下圖所示:
上圖就是16P的TypeC引腳示意圖,從左到右依次是1-16 腳,注意1,2 腳、3,4 腳、13,14 腳和15,16腳離得很近,看起來像是一個引腳,其實他們是兩個引腳。16P對應的引腳功能如下圖所示:
可以看出,相比于標準24P引腳定義,16P的母座少了8根USB3.1高速差分收發(fā)數(shù)據(jù)線。
USB TypeC的Data Role
USB2.0根據(jù)數(shù)據(jù)傳輸方向定義了HOST/Device/OTG這三種類型的設備角色,其中OTG既可以做HOST也可以做Device,USB2.0的OTG設備接口通過ID線來區(qū)分HOST還是Device。在TypeC領域,也有類似的概念,但是名字變了:
- DFP:DFP全稱是Downstream Facing Port,也就是下行端口,可以理解為HOST,DFP提供VBUS、VCONN,可以接收數(shù)據(jù)。
- UFP:UFP全稱是Upstream Facing Port,也就是上行端口,可以理解為Device,UFP 從VBUS中取電源,UFP設備也可以傳輸數(shù)據(jù),比如U盤,鍵盤鼠標等。
- DRP:DRP全稱是Dual Role Port,也就是雙角色端口,可以理解為OTG,DRP既可以做DFP,也可以做UFP。也可以在DFP和UFP之間進行動態(tài)切換。這個切換過程就用到了CC引腳,具體識別過程比較復雜,這里就不講解了。如果要在USB TypeC接口上實現(xiàn)DRP功能,那么就需要使用到外置的TypeC芯片!正點原子STM32MP157開發(fā)板使用了STUSB1600或FUSB302MPX這兩種TypeC芯片。這兩種芯片都有一個IIC配置接口,也就是需要編寫驅動程序,否則的話DRP功能無法實現(xiàn)。
硬件原理圖分析
正點原子的STM32MP1開發(fā)板USB部分原理圖可以分為兩部分:USB HUB以及USB OTG。
USB TypeC本來是給USB3.1準備的,單位了方便使用,所以正點原子STM32MP157開發(fā)板也使用了TypeC接口,但是本質上還是USB2.0協(xié)議,所以不要看到TypeC就以為支持USB3.0!
另外,使用TypeC接口實現(xiàn)OTG功能的話就需要外界TypeC芯片!通過專用的TypeC芯片來控制CC引腳實現(xiàn)USB的主從切換。V1.3版本以前的底板使用STUSB1600這顆TypeC芯片,V1.5版本以后的底板都使用FUSB302MPX。
依次來看一下這兩部分的硬件原理圖。
USB HUB原理圖分析
首先來看一下USB HUB原理圖,STM32MP1使用FE2.1這個HUB芯片將STM32MP1的USB2擴展成了7路HOST接口,其中一路供4G模塊使用,因此就剩下了6個通用的USB A插座,原理圖如下圖所示:
上圖中U21就是USB HUB芯片F(xiàn)E2.1,FE2.1是一款符合USB2.0標準的USB HUB芯片,支持一拖七擴展,可以將一路USB擴展為7路USB HOST接口。這里將STM32MP1的USB1擴展出了7路USB HOST接口,分別為HUB_DP1/DM1、HUB_DP2/DM2、HUB_DP3/DM3、HUB_DP4/DM4、HUB_DP5/DM5、HUB_DP6/DM6和HUB_DP7/DM7。其中HUB_DP7/DM7用于4G模塊,因此對外提供的只有六個USB HOST接口,這三個USB HOST接口如下圖所示:
注意,使用FE2.1擴展出來的7路USB接口只能用作HOST!
USB OTG原理圖分析
正點原子的STM32MP1開發(fā)板上還有一路USB OTG接口,使用STM32MP1的USB OTG接口。此路USB OTG既可以作為主機(HOST),也可以作為從機(DEVICE),從而實現(xiàn)完整的OTG功能。V1.4版本以前的底板上TypeC芯片使用STUSB1600,V1.5及以后版本的底板使用FUSB302MPX這顆芯片。
現(xiàn)在購買的話都是V1.5以后的版本了,開發(fā)板的USB OTG是使用FUSB302MPX做控制。原理圖如下圖所示:
FUSB302PMX也是負責控制切換主機和從機模式的,MT9700HT5是負載開關,用來控制VBUS輸出,當OTG_PWR_CTRL輸出高電平的時候OUT引腳就輸出5V電壓,也就是VBUS變?yōu)?V。當OTG_PWR_CTRL輸出低電平的時候OUT輸出0V,相當于VBUS關閉。
所以當開發(fā)板上的TypeC接口作為主設備的時候,OTG_PWR_CTRL要輸出高電平,VBUS輸出5V,為外部USB設備供電。當TypeC接口作為從設備的時候,OTG_PWR_CTRL輸出低電平。OTG_PWR_CTRL對應的GPIO 引腳為PZ6。
USB協(xié)議簡介
USB描述符
USB描述符就是用來描述USB信息的,描述符就是一串按照一定規(guī)則構建的字符串,USB設備使用描述符來向主機報告自己的相關屬性信息,常用的描述符如下圖所示:
依次來看一下上圖中這5個描述符的含義。
設備描述符
設備描述符用于描述USB設備的一般信息,USB設備只有一個設備描述符。設備描述符里面記錄了設備的USB版本號、設備類型、VID(廠商 ID)、PID(產品 ID)、設備序列號等。設備描述符結構如下圖所示:
配置描述符
設備描述符的bNumConfigurations域定義了一個USB設備的配置描述符數(shù)量,一個USB設備至少有一個配置描述符。配置描述符描述了設備可提供的接口(Interface)數(shù)量、配置編號、供電信息等,配置描述符結構如下圖所示:
字符串描述符
字符串描述符是可選的,字符串描述符用于描述一些方便閱讀的信息,比如制造商、設備名稱等。如果一個設備沒有字符串描述符,那么其他描述符中和字符串有關的索引值都必須為0,字符串描述符結構如下圖所示:
wLANGID[0]~wLANGID[x]指明了設備支持的語言 , 具體含義要查閱文檔《USB_LANGIDs.pdf》。
主機會再次根據(jù)自己所需的語言向設備請求字符串描述符,這次主機會指明要得到的字符串索引值和語言。設備返回Unicode編碼的字符串描述符,結構如下圖所示:
接口描述符
配置描述符中指定了該配置下的接口數(shù)量,配置可以提供一個或多個接口,接口描述符用于描述接口屬性。接口描述符中一般記錄接口編號、接口對應的端點數(shù)量、接口所述的類等,接口描述符結構如下圖所示:
端口描述符
接口描述符定義了其端點數(shù)量,端點是設備與主機之間進行數(shù)據(jù)傳輸?shù)倪壿嫿涌?#xff0c;除了端點0是雙向端口,其他的端口都是單向的。端點描述符描述了樹傳輸類型、方向、數(shù)據(jù)包大小、端點號等信息,端點描述符結構如下圖所示:
USB數(shù)據(jù)包類型
USB是串行通信,需要一位一位的去傳輸數(shù)據(jù),USB傳輸?shù)臅r候先將原始數(shù)據(jù)進行打包,所以USB中傳輸?shù)幕締卧褪菙?shù)據(jù)包。根據(jù)用途的不同,USB協(xié)議定義了4種不同的包結構:令牌(Token)包、數(shù)據(jù)(Data)包、握手(Handshake)包和特殊(Special)包。這四種包通過包標識符PID來區(qū)分,PID共有8位,USB協(xié)議使用低4位PID3-PID0,另外的高四位PID7-PID4是PID3-PID0的取反,傳輸順序是PID0、PID1、PID2、PID3…PID7。令牌包的PID1-0為01,數(shù)據(jù)包的PID1-0 為11,握手包的PID1-0為10,特殊包的PID1-0為00。每種類型的包又有多種具體的包,如下圖所示:
一個完整的包分為多個域,所有的數(shù)據(jù)包都是以同步域(SYNC)開始,后面緊跟著包標識符(PID),最終都以包結束(EOP)信號結束。不同的數(shù)據(jù)包中間位域不同,一般有包目標地址(ADDR)、包目標端點(ENDP)、數(shù)據(jù)、幀索引、CRC等,這個要具體數(shù)據(jù)包具體分析。接下來簡單看一下這些數(shù)據(jù)包的結構。
令牌包
令牌包結構如下圖所示:
上圖是一個SETUP令牌包結構,首先是SYNC同步域,包同步域為00000001,也就是連續(xù)7個0,后面跟一個1,如果是高速設備的話就是31個0后面跟一個1。緊跟著是PID,這里是SETUP包,為0XB4,是0XB4的原因如下:
- ETUP包的PID3-PID0 為1101,因此對應的PID7~PID4就是0010。
- PID傳輸順序為PID0、PID1、PID2…PID7,因此按照傳輸順序排列的話此處的PID就是10110100=0XB4,并不是0X2D。
PID后面跟著地址域(ADDR)和端點(ENDP),為目標設備的地址和端點號。CRC5域是5位CRC值,是ADDR和ENDP這兩個域的校驗值。最后就是包結束域(EOP),標記本數(shù)據(jù)包結束。其他令牌包的結構和SETUP基本類似,只是SOF令包中間沒有ADDR和ENDP這兩個域,而是只有一個11位的幀號域。
數(shù)據(jù)包
數(shù)據(jù)包結構如下圖所示:
數(shù)據(jù)包比較簡單,同樣的,數(shù)據(jù)包從SYNC同步域開始,然后緊跟著是PID,這里就是DATA0,PID值為0XC3。接下來就是具體的數(shù)據(jù),數(shù)據(jù)完了以后就是16位的CRC校驗值,最后是EOP。
握手包
握手包結構如下圖所示:
上圖是ACK握手包,很簡單,首先是SYNC同步域,然后就是ACK包的PID,為0X4B,最后就是EOP。其他的NAK、STALL、NYET和ERR握手包結構都是一樣的,只是其中的PID不同而已。
USB傳輸類型
在端點描述符中bmAttributes指定了端點的傳輸類型,一共有4種,本節(jié)來看一下這四種傳輸類型的區(qū)別。
控制傳輸
控制傳輸一般用于特定的請求,比如枚舉過程就是全部由控制傳輸來完成的,比如獲取描述符、設置地址、設置配置等。控制傳輸分為三個階段:建立階段(SETUP)、數(shù)據(jù)階(DATA)和狀態(tài)階段(STATUS),其中數(shù)據(jù)階段是可選的。建立階段使用SETUP令牌包,SETUP使用DATA0包。數(shù)據(jù)階段是 0 個、1個或多個輸入(IN)/輸出(OUT)事務,數(shù)據(jù)階段的所有輸入事務必須是同一個方向的,比如都為IN或都為OUT。數(shù)據(jù)階段的第一個數(shù)據(jù)包必須是DATA1,每次正確傳輸以后就在DATA0和DATA1之間進行切換。數(shù)據(jù)階段完成以后就是狀態(tài)階段,狀態(tài)階段的傳輸方向要和數(shù)據(jù)階段相反,比如數(shù)據(jù)階段為IN的話狀態(tài)階段就要為OUT,狀態(tài)階段使用DATA1包。比如一個讀控制傳輸格式如下圖所示:
同步傳輸
同步傳輸用于周期性、低時延、數(shù)據(jù)量大的場合,比如音視頻傳輸,這些場合對于時延要求很高,但是不要求數(shù)據(jù)100%正確,允許有少量的錯誤。因此,同步傳輸沒有握手階段,即使數(shù)據(jù)傳輸出錯了也不會重傳。
批量傳輸
批量傳輸就是用于大批量傳輸大塊數(shù)據(jù)的,這些數(shù)據(jù)對實時性沒有要求,比如MSD類設備(存儲設備),U盤之類的。批量傳輸分為批量讀(輸入)和批量寫(輸出),如果是批量讀的話第一階段就是IN令牌包,如果是批量寫那么第一階段就是OUT令牌包。
就以批量寫為例簡單介紹一下批量傳輸過程:
- 主機發(fā)出OUT令牌包,令牌包里面包含了設備地址、端點等信息。
- 如果OUT令牌包正確的話,也就是設備地址和端點號匹配,主機就會向設備發(fā)送一個數(shù)據(jù)(DATA)包,發(fā)送完成以后主機進入接收模式,等待設備返回握手包,一切都正確的話設備就會向主機返回一個ACK握手信號。
批量讀的過程剛好相反:
- 主機發(fā)出IN令牌包,令牌包里面包含了設備地址、端點等信息。發(fā)送完成以后主機就進入到數(shù)據(jù)接收狀態(tài),等待設備返回數(shù)據(jù)。
- 如果IN令牌包正確的話,設備就會將一個DATA包放到總線上發(fā)送給主機。主機收到這個DATA包以后就會向設備發(fā)送一個ACK握手信號。
中斷傳輸
這里的中斷傳輸并不是傳統(tǒng)意義上的硬件中斷,而是一種保持一定頻率的傳輸,中斷傳輸適用于傳輸數(shù)據(jù)量小、具有周期性并且要求響應速度快的數(shù)據(jù),比如鍵盤、鼠標等。中斷的端點會在端點描述符中報告自己的查詢時間間隔,對于時間要求嚴格的設備可以采用中斷傳輸。
USB枚舉
當USB設備與USB主機連接以后主機就會對USB設備進行枚舉,通過枚舉來獲取設備的
描述符信息,主機得到這些信息以后就知道該加載什么樣的驅動、如何進行通信等。USB 枚舉過程如下:
- 第一回合,當USB主機檢測到USB設備插入以后機會發(fā)出總線復位信號來復位設備。USB設備復位完成以后地址為0,主機向地址0的端點0發(fā)送數(shù)據(jù),請求設備的描述符。設備得到請求以后就會按照主機的要求將設備描述符發(fā)送給主機,主機得到設備發(fā)送過來的設備描述符以后,如果確認無誤就會向設備返回一個確認數(shù)據(jù)包(ACK)。
- 第二回合,主機再次復位設備,進入地址設置階段。主機向地址0的端點0發(fā)送設置地址請求數(shù)據(jù)包,新的設備地址就包含在這個數(shù)據(jù)包中,因此沒有數(shù)據(jù)過程。設備進入狀態(tài)過程,等待主機請求狀態(tài)返回,收到以后設備就會向主機發(fā)送一個0字節(jié)狀態(tài)數(shù)據(jù)包,表明設備已經設置好地址了,主機收到這個0字節(jié)狀態(tài)數(shù)據(jù)包以后會返回一個確認包(ACK)。設備收到主機發(fā)送的ACK包以后就會使用這個新的設備地址,至此設備就得到了一個唯一的地址。
- 第三回合,主機向新的設備地址端點0發(fā)送請求設備描述符數(shù)據(jù)包,這一次主機要獲取整個設備描述符,一共是18個字節(jié)。
- 和第3步類似,接下來依次獲取配置描述符、配置集合、字符串描述符等等。
STM32MP1 USB HOST驅動編寫
接下來就開始編寫USB HOST的驅動。USB子系統(tǒng)是一個標準和復雜的接口,所以驅動基本不用寫,都是內核里有現(xiàn)成的,只需要在設備樹提供對應的設備節(jié)點即可。
之前的學習有說到USBH是只能主機模式,要編寫USB HOST就用USBH控制器即可。ST官方的STM3MP157C-DK2開發(fā)板已經配置好了USBH的節(jié)點信息,所以直接參考此節(jié)點即可,這樣開發(fā)板就能夠使用 USB Host 模式。
USBH控制器節(jié)點信息
打開“stm32mp151.dtsi”文件,找到USBH兩個控制器的節(jié)點信息,名字分別為“usbh_ohci”和“usbh_ehci”。如下示例代碼所示:
示例代碼 50.4.1 USBH 下兩個控制器節(jié)點信息
1 usbh_ohci: usbh-ohci@5800c000 {
2 compatible = "generic-ohci";
3 reg = <0x5800c000 0x1000>;
4 clocks = <&rcc USBH>;
5 resets = <&rcc USBH_R>;
6 interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
7 status = "disabled";
8 };
9
10 usbh_ehci: usbh-ehci@5800d000 {
11 compatible = "generic-ehci";
12 reg = <0x5800d000 0x1000>;
13 clocks = <&rcc USBH>;
14 resets = <&rcc USBH_R>;
15 interrupts-extended = <&exti 43 IRQ_TYPE_LEVEL_HIGH>;
16 companion = <&usbh_ohci>;
17 power-domains = <&pd_core>;
18 wakeup-source;
19 status = "disabled";
20 };
從上面的代碼可以知道USBH是支持USB2.0和USB1.1的。使用USB2.0就要配置usbh_ehci節(jié)點,使用USB1.1就要配置usbh_ohci 節(jié)點。這兩個節(jié)點的信息是不需要修改的,這是STM32MP1一些通用配置信息。需要做的就是在stm32mp157d-atk.dts文件中追加對應屬性信息,然后status屬性值改為“okay”,還要配置USBH使用哪個PHY端口。根據(jù)兩個節(jié)點的compatible屬性找到對應的驅動路徑為:drivers/usb/host/ohci-platform.c和drivers/usb/host/ehci-platform.c。
配置PHY控制器
先了解一下PHY控制器,一些通用配置,打開 stm32mp151.dtsi文件,找的如下內容所示:
示例代碼 50.4.2 usbphyc 控制器節(jié)點信息
1 usbphyc: usbphyc@5a006000 {
2 #address-cells = <1>;
3 #size-cells = <0>;
4 #clock-cells = <0>;
5 compatible = "st,stm32mp1-usbphyc";
6 reg = <0x5a006000 0x1000>;
7 clocks = <&rcc USBPHY_K>;
8 resets = <&rcc USBPHY_R>;
9 vdda1v1-supply = <®11>;
10 vdda1v8-supply = <®18>;
11 status = "disabled";
12
13 usbphyc_port0: usb-phy@0 {
14 #phy-cells = <0>;
15 reg = <0>;
16 };
17
18 usbphyc_port1: usb-phy@1 {
19 #phy-cells = <1>;
20 reg = <1>;
21 };
22 };
示例代碼50.4.1.2 usbphyc節(jié)點就是STM32MP1的USB PHY。已經知道PHY控制器有兩個端口,剛好usbphyc節(jié)點里有兩個子節(jié)點名字分別為:usbphyc_port0和usbphyc_port1,這兩個子節(jié)點就是PHY控制器的兩個端口,其中usbphyc_port0只能分配給USB Host。注意:“#phy-cells”屬性和“#gpio-cells”屬性作用是一樣的,如果#phy-cells為1,表示一個cell,此cell表示端口做USBH的PHY端口還是OTG的PHY端口,0表示做OTG的PHY端口,1表示做USBH的PHY端口。
打開“stm32mp15xx-dkx.dtsi”文件找到“usb_phy_tuning”節(jié)點,把此節(jié)點的內容拷貝到stm32mp157d-atk.dts的根目錄下,拷貝內容如下所示:
示例代碼 50.4.3 添加的 usb_phy_tuning 節(jié)點信息
1 usb_phy_tuning: usb-phy-tuning {
2 st,hs-dc-level = <2>;
3 st,fs-rftime-tuning;
4 st,hs-rftime-reduction;
5 st,hs-current-trim = <15>;
6 st,hs-impedance-trim = <1>;
7 st,squelch-level = <3>;
8 st,hs-rx-offset = <2>;
9 st,no-lsfs-sc;
10 };
usb_phy_tuning此節(jié)點負責調整PHY的配置,對于此節(jié)點的屬性內容感興趣的可以去看Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.yaml文件 。 接著還是在stm32mp157d-atk.dts文件中使能usbphyc以及向usbphyc_port0節(jié)點追加的內容,要修改的如下所示:
示例代碼 50.4.4 使能 usbphyc 和追加 usbphyc_port0 的內容
1 &usbphyc {
2 status = "okay";
3 };
4
5 &usbphyc_port0 {
6 phy-supply = <&v3v3>;
7 st,phy-tuning = <&usb_phy_tuning>;
8 };
第2行,這里把usbphyc的status屬性修改為“okay”,使能usbphyc。
第6行,給usbphyc_port0節(jié)點追加phy-supply屬性,添加一個電源管理屬性。
第7行,把要修改的PHY配置,添加到usbphyc_port0節(jié)點里。
配置usbh_ehci
最后在stm32mp157d-atk.dts文件,使能usbh_ehci和指定PHY端口。
示例代碼 50.4.5 追加 usbh_ehci 節(jié)點內容
1 &usbh_ehci {
2 phys = <&usbphyc_port0>;
3 status = "okay";
4 };
這里的內容很簡單,就是修改status屬性為“okay”和指定使用usbphyc_port0端口。修改完就重新編譯設備樹,使用新的stm32mp157d-atk.dtb設備樹重新啟動開發(fā)板。就會有以下輸出所示:
如果有上圖這些輸出信息,說明usb host驅動加載到內核了。
Linux內核自帶Host實驗
USB鼠標鍵盤測試
首先做一下USB HOST試驗,也就是正點原子的STM32MP1開發(fā)板做USB主機,然后外接USB設備,比如USB鼠標鍵盤、USB 轉TTL串口線、U盤等設備。Linux內核已經集成了大量的USB設備驅動,尤其是常見的USB鼠標鍵盤、U盤等,本節(jié)就來學習一下如何使能Linux內核常見的USB設備驅動。
USB鼠標鍵盤驅動使能
USB鼠標鍵盤屬于HID設備,內核已經集成了相應的驅動,ST官方提供的linux內核默認已經使能了USB鼠標鍵盤驅動,但是還要學習一下如何手動使能這些驅動。輸入“make
menuconfig”,打開linux內核配置界面,首先打開HID驅動,按照如下路徑到相應的配置項目:
-> Device Drivers -> HID support -> HID bus support -> <*> Generic HID driver //使能通用 HID 驅動 |
使能后結果如下圖所示:
接下來需要使能USB鍵盤和鼠標驅動,配置路徑如下:
-> Device Drivers -> HID support -> USB HID support -> <*> USB HID transport layer //USB 鍵盤鼠標等 HID 設備驅動 |
使能后如下圖所示:
可以將光標放到上圖中“USB HID Transport layer”這一行,然后按下“?”鍵打開對應的幫助信息就可以看到對于這個配置項的描述,簡單總結一下:
此選項對應配置項就是CONFIG_USB_HID,也就是USB接口的HID設備。如果要使用USB接口的keyboards(鍵盤)、mice(鼠標)、joysticks(搖桿)、graphic tablets(繪圖板)等其他的HID設備,那么就需要選中“USB HID Transport layer”。但是要注意一點,此驅動和HIDBP(Boot Protocol)鍵盤、鼠標的驅動不能一起使用!所以要是在網(wǎng)上查閱linux內核USB鍵盤鼠標驅動的時候,發(fā)現(xiàn)推薦使用“USB HIDBP Keyboard (simple Boot) support”和“USB HIDBP Mouse (simple Boot) support”這兩個配置項的時候也不要覺得教程這里寫錯了。
測試USB鼠標和鍵盤
完成以后重新編譯linux內核并且使用得到的 uImage啟動開發(fā)板。啟動以后插入USB鼠標,會有如下圖所示的提示信息:
從上圖可以看出,系統(tǒng)檢測到了鼠標,如果成功驅動的話就會在/dev/input目錄下生成一個名為eventX(X=0,1,2,3…)的文件,這個就是前面講的輸入子系統(tǒng),鼠標和鍵盤都是作為輸入子系統(tǒng)設備的。教程中這里對應的就是/dev/input/event1這個設備,使用如下命令查看鼠標的原始輸入值,結果如下圖:
上圖就是鼠標作為輸入子系統(tǒng)設備的原始輸入值,這里就不去分析了,在移植GUI圖形庫以后就可以直接使用鼠標,比如QT等。
最后再來測試一下USB鍵盤,屏幕已經驅動起來了,所以可以直接將屏幕作為終端,然后接上鍵盤直接輸入命令來進行各種操作。首先將屏幕設置為控制臺,打開開發(fā)板根文件系統(tǒng)中的/etc/inittab文件,然后在里面加入下面這一行:
tty1::askfirst:-/bin/sh |
完成以后重啟開發(fā)板,此時屏幕就會作為終端控制臺,會有“Please press Enter to activate
this console.”這樣提示,如下圖所示:
接上鍵盤,然后根據(jù)上圖中的提示,按下鍵盤上的Enter(回車)鍵即可使能LCD屏幕控制臺,然后就可以輸入各種命令來執(zhí)行相應的操作,如下圖所示:
U盤實驗
ST提供的Linux內核默認也已經使能了U盤驅動,因此可以直接插上去使用。但是還是需要學習一下如何手動配置Linux內核,使能U盤驅動。
使能U盤驅動
U盤使用SCSI協(xié)議,因此要先使能Linux內核中的SCSI協(xié)議,配置路徑如下:
-> Device Drivers -> SCSI device support -> <*> SCSI disk support //選中此選項 |
結果如下圖所示:
還需要使能USB Mass Storage,也就是USB 接口的大容量存儲設備,配置路徑如下:
-> Device Drivers -> USB support -> USB Gadget Support -> USB Gadget functions configurable through configfs -> [*] Mass storage //選中 |
結果如下圖所示:
U盤測試
準備好一個U盤,注意U盤要為FAT32格式的!NTFS和exFAT由于版權問題所以在Linux下支持的不完善,操作的話可能會有問題,比如只能讀,不能寫或者無法識別等。準備好以后將U盤插入到開發(fā)板USB HUB擴展出來的HOST接口上,此時會輸出如下圖所示信息:
從上圖可以看出,系統(tǒng)檢測到U盤插入,大小為16GB對應的設備文件為/dev/sda和/dev/sda1,可以查看一下/dev目錄下有沒有sda和sda1這兩個文件。/dev/sda是整個U盤,/dev/sda1是U盤的第一個分區(qū),一般使用U盤的時候都是只有一個分區(qū)。要想訪問U盤需要先對U盤進行掛載,理論上掛載到任意一個目錄下都可以,這里可以創(chuàng)建一個/mnt/usb_disk目錄,然后將U盤掛到/mnt/usb_disk目錄下,命令如下:
mkdir /mnt/usb_disk -p //創(chuàng)建目錄 mount /dev/sda1 /mnt/usb_disk/ -t vfat -o iocharset=utf8 //掛載 |
-t指定掛載所使用的文件系統(tǒng)類型,這里設置為vfat,也就是FAT文件系統(tǒng),“-o iocharset”
設置硬盤編碼格式為utf8,否則的話U盤里面的中文會顯示亂碼!
掛載成功以后進入到/mnt/usb_disk目錄下,輸入ls命令查看U盤文件,如下圖所示:
至此U盤就能正常讀寫操作了,直接對/mnt/usb_disk目錄進行操作就行了。如果要拔出U盤要執(zhí)行一個sync命令進行同步,然后在使用unmount進行U盤卸載,命令如下所示:
sync //同步 cd / //如果處于/mnt/usb_disk 目錄的話先退出來,否則卸載的時候提示設//備忙,導致卸載失敗,切記! umount /mnt/usb_disk //卸載 |
Linux內核自帶USB OTG實驗
STUSB1600設備樹編寫
STUSB1600是ST出的一款TypeC 芯片,也是ST官方開發(fā)板搭配STM32MP1的。STUSB1600的驅動設備樹編寫參考文檔“Documentation/devicetree/bindings/usb/st,typec-stusb.txt”。此文檔描述了STUSB1600 設備相關信息。
USB OTG控制器節(jié)點信息
進入到Linux內核源碼目錄,打開arch/arm/boot/dts/stm32mp151.dtsi 設備樹文件,在這個設備樹文件有一個usbotg_hs節(jié)點,此節(jié)點就是USB OTG控制器節(jié)點,內容如下:
示例代碼 50.6.1.1 usbotg_hs 控制器
1 usbotg_hs: usb-otg@49000000 {
2 compatible = "st,stm32mp1-hsotg", "snps,dwc2";
3 reg = <0x49000000 0x10000>;
4 clocks = <&rcc USBO_K>;
5 clock-names = "otg";
6 resets = <&rcc USBO_R>;
7 reset-names = "dwc2";
8 interrupts-extended = <&exti 44 IRQ_TYPE_LEVEL_HIGH>;
9 g-rx-fifo-size = <512>;
10 g-np-tx-fifo-size = <32>;
11 g-tx-fifo-size = <256 16 16 16 16 16 16 16>;
12 dr_mode = "otg";
13 usb33d-supply = <&usb33>;
14 power-domains = <&pd_core>;
15 wakeup-source;
16 status = "disabled";
17 };
示例代碼50.6.1.1中的usbotg_hs節(jié)點不需要修改,這里只是查看一下usbotg_hs完整節(jié)點信息。根據(jù)第2行的compatible屬性就是可以找到STM32MP1的usbotg_hs驅動源文件,驅動文件名為drivers/usb/dwc2/params.c。第12行,dr_mode屬性用來配置控制器做otg功能還是host功能,不配置此屬性默認為otg功能。第16行的status屬性為disabled,所以usbotg_hs默認關閉的,如果要使能就是要修改status屬性為 okay、配置一個PHY端口和設置使用那個控制器去控制usbotg_hs。
使能usbotg_hs節(jié)點
首先先去配置PHY接口,在stm32mp157d-atk.dts文件中追加usbphyc_port1節(jié)點,內容如下所示:
示例代碼 50.6.1.2 usbphyc_port1 節(jié)點配置
1 &usbphyc_port1 {
2 phy-supply = <&vdd_usb>;
3 st,phy-tuning = <&usb_phy_tuning>;
4 };
注意:要先使能usbphyc節(jié)點,這里在USB HOST實驗已經使能就不用配置。
接著去追加usbotg_hs的相關屬性信息。追加的內容如下所示:
示例代碼 50.6.1.3 usbotg_hs 節(jié)點內容
1 &usbotg_hs {
2 phys = <&usbphyc_port1 0>;
3 phy-names = "usb2-phy";
4 usb-role-switch;
5 status = "okay";
6
7 port {
8 usbotg_hs_ep: endpoint {
9 remote-endpoint = <&con_usbotg_hs_ep>;
10 };
11 };
12 };
第2行,配置usbotg_hs的PHY接口,這里0表示為OTG USB的PHY端口。
第5行,把status屬性改為okay,使能usbotg_hs。
第7-11行,添加了一個port節(jié)點,第9行指定usbotg_hs 節(jié)點使用con_usbotg_hs_ep做控制器,con_usbotg_hs_ep會在STUSB1600節(jié)點里創(chuàng)建。
最后還需要添加vdd_usb電源節(jié)點,因為示例代碼50.6.1.2中的usbphyc_port1節(jié)點需要用到vdd_usb節(jié)點,在stm32mp157d-atk.dts中添加vdd_usb電源節(jié)點,在根節(jié)點下添加內容如下:
示例代碼 50.6.1.4 vdd_usb 電源節(jié)點
1 vdd_usb: regulator-vdd-usb {
2 compatible = "regulator-fixed";
3 regulator-name = "vdd_usb";
4 regulator-min-microvolt = <3300000>;
5 regulator-max-microvolt = <3300000>;
6 regulator-always-on;
7 regulator-boot-on;
8 };
使能I2C1節(jié)點
控制Typec的芯片是STUSB1600,此芯片是使用I2C協(xié)議和CPU進行通訊,所以要使能I2C1。把示例代碼50.6.1.4拷貝到stm32mp157d-atk.dts文件里,代碼如下所示:
示例代碼 50.6.1.5 使能 i2c1 節(jié)點
1 &i2c1 {
2 pinctrl-names = "default", "sleep";
3 pinctrl-0 = <&i2c1_pins_b>;
4 pinctrl-1 = <&i2c1_pins_sleep_b>;
5 status = "okay";
6 };
正點原子STM32MP157開發(fā)板I2C1_SCL和I2C1_SDA這兩個引腳為PF14和PF15。這兩個引腳的pinctrl配置已經在stm32mp15-pinctrl.dtsi文件里面提供了,如果使用的其他引腳需要自行配置。
配置STUSB1600節(jié)點
先配置STUSB1600的中斷引腳電氣屬性和電源管理,STUSB1600中斷引腳為PG2,在stm32mp15-pinctrl.dtsi文件中輸入如下內容:
示例代碼 50.6.1.6 stusb1600 中斷電氣屬性
1 stusb1600_pins_b: stusb1600-0 {
2 pins {
3 pinmux = <STM32_PINMUX('G', 2, ANALOG)>;
4 bias-pull-up;
5 };
6 };
把STUSB1600的中斷引腳改為內部上拉。因為USB OTG需要5V電源管理,前面沒有此配置,所以要一個5V的電源配置,在根節(jié)點下添加如下示例代碼所示:
示例代碼 50.6.1.7 5V 的 vin 節(jié)點
1 vin: regulator-vin {
2 compatible = "regulator-fixed";
3 regulator-name = "vin";
4 regulator-min-microvolt = <5000000>;
5 regulator-max-microvolt = <5000000>;
6 regulator-always-on;
7 regulator-boot-on;
8 };
接下來配置STUSB1600節(jié)點,此節(jié)點屬于I2C1的子節(jié)點。STUSB1600的配置內容如下所示:
示例代碼 50.6.1.8 stusb1600 節(jié)點信息
1 stusb1600@28 {
2 compatible = "st,stusb1600";
3 reg = <0x28>;
4 interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
5 interrupt-parent = <&gpiog>;
6 pinctrl-names = "default";
7 pinctrl-0 = <&stusb1600_pins_b>;
8 status = "okay";
9 vdd-supply = <&vin>;
10
11 connector {
12 compatible = "usb-c-connector";
13 label = "USB-C";
14 power-role = "dual";
15 power-opmode = "default";
16
17 port {
18 con_usbotg_hs_ep: endpoint {
19 remote-endpoint = <&usbotg_hs_ep>;
20 };
21 };
22 };
23 };
示例代碼50.6.1.7代碼中可以分為兩個部分:第1-9行屬于控制STUSB1600芯片相關屬性,第11-22行屬于Typec端口相關屬性。
第2行,compatible的屬性值為“st,stusb1600”,在Linux源碼目錄下,搜索此屬性值,會找到stusb1600的驅動源碼為drivers/usb/typec/typec_stusb.c。
第3行,reg屬性值為“0x28”,stusb1600芯片通訊地址為0x28。
第4-5行,設置中斷相關配置,中斷觸發(fā)為下降沿觸發(fā)。
第6-7行,設置中斷的電氣屬性。
第9行,設置電源配置。
第12-15行,可以查看Documentation/devicetree/bindings/connector/usb-connector.txt 文件。
第17-20行,定義了一個con_usbotg_hs_ep端口,同時指定此端口連接到usbotg_hs節(jié)點的usbotg_hs_ep端口。
重新編譯設備樹,使用新的stm32mp157d-atk.dtb 文件去啟動開發(fā)板。
FUSB302驅動移植
在上一小節(jié)已經完成了一部分的設備樹配置,由于只是改了USB TypeC的芯片,所以只需要把STUSB1600相關的部分改為FUSB302 即可。其實就是上一小節(jié)前面的1-3小點不用修改,只需要改第4小點。
首先配置FUSB302的中斷電氣屬性,配置如下所示:
示例代碼 50.6.2.1 fusb302 中斷電氣屬性
1 fusb302_pins_a: fusb302-0 {
2 pins {
3 pinmux = <STM32_PINMUX('G', 2, ANALOG)>;
4 bias-pull-up;
5 };
6 };
在 stm32mp157d-atk.dts文件中添加頭文件“dt-bindings/usb/pd.h”,如下圖所示:
接著配置FUSB302節(jié)點,配置的代碼如下所示:
示例代碼 50.6.2.2 fusb302 節(jié)點信息
1 fusb302@22 {
2 compatible = "fcs,fusb302","fairchild,fusb302";
3 reg = <0x22>;
4 pinctrl-names = "default";
5 pinctrl-0 = <&fusb302_pins_a>;
6 int-n-gpios = <&gpiog 2 GPIO_ACTIVE_HIGH>;
7 vbus-5v-gpios = <&gpioz 6 GPIO_ACTIVE_HIGH>;
8 status = "okay";
9
10 connector {
11 compatible = "usb-c-connector";
12 label = "USB-C";
13 power-role = "dual";
14 power-opmode = "default";
15
16 try-power-role = "sink";
17 source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
18 sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)
19 PDO_VAR(3000, 12000, 3000)
20 PDO_PPS_APDO(3000, 11000, 3000)>;
21 op-sink-microwatt = <10000000>;
22 port {
23 con_usbotg_hs_ep: endpoint {
24 remote-endpoint = <&usbotg_hs_ep>;
25 };
26 };
27 };
28 };
fusb302的設備樹沒有使用電源管理,而是用PZ6 引腳去控制電壓。其它的屬性和stusb1600一樣。
最后就是去改驅動了,Linux內核提供的fusb302驅動是沒讀取connector相關的屬性,所以此驅動是不能使用。在github里找到了可用的fusb302驅動,改動的部分是如何讀取connector節(jié)點和使用PZ6引腳控制電壓。想看如何修改的,可以用文件對比軟件,就能知道修改了那些內容。將25_fusb302目錄的fusb302.c和fusb302.h文件拷貝到linux源碼下的drivers/usb/typec/tcpm目錄里,注意要把原來的fusb302.c覆蓋掉,拷貝結果如下圖所示:
拷貝完成后,進入內核的配置選項圖形界面,配置路徑如下:
-> Device Drivers -> USB support -> USB Type-C Support -> USB Type-C Port Controller Manager -> <*> Fairchild FUSB302 Type-C chip driver //選中 |
如下圖所示:
重新編譯設備樹和內核,使用新的設備樹stm32mp157d-atk.dtb和內核uImage去啟動開發(fā)
板,有如下圖打印信息,說明加載驅動成功。如圖所示:
OTG主機實驗
系統(tǒng)重啟成功以后就可以正常使用USB_OTG接口,OTG既可以做主機,也可以做從機,做主機的話測試方法和之前的測試一模一樣,直接在正點原子的USB_OTG接口上使用Typec OTG線接入鼠標鍵盤、U盤等設備。USB_OTG接口如下所示:
OTG從機實驗
OTG從機就是將開發(fā)板作為一個USB設備連接到其他的主機上,這里來做兩個USB從機實驗:模擬U盤以及USB聲卡。
模擬U盤實驗
模擬U盤實驗就是將開發(fā)板當做一個U盤,可以將開發(fā)板上的U盤或者TF卡掛載到PC上,首先需要配置Linux,配置路徑如下:
-> Device Drivers -> USB support -> USB Gadget Support -> < > USB Gadget functions configurable through configfs //不要編譯進內核 -> USB Gadget precomposed configurations ( [=m]) -> Mass Storage Gadget //大容量存儲 |
結果如下圖所示:
這里需要將驅動編譯為模塊!使用的時候直接輸入命令加載驅動模塊即可。配置好
以后執(zhí)行下面這些命令重新編譯Linux內核、編譯模塊:
make uImage LOADADDR=0XC2000040 -j32 make modules -j32 |
編譯完成后會得到3個.ko內核模塊文件,對應路徑為:
drivers/usb/gadget/libcomposite.ko drivers/usb/gadget/function/usb_f_mass_storage.ko drivers/usb/gadget/legacy/g_mass_storage.ko |
將上述三個.ko 模塊拷貝到開發(fā)板根文件系統(tǒng)/lib/modules/5.4.31目錄下,如圖所示:
拷貝完成以后使用新編譯出來的uImage啟動開發(fā)板,在開發(fā)板上插入一個U盤,記住這個U盤對應的設備文件,比如這里是/dev/sda 和/dev/sda1,以后要將/dev/sda1掛載到PC上,也就是把/dev/sda1作為模擬U盤的存儲區(qū)域。
使用TypeC數(shù)據(jù)線將開發(fā)板和電腦連接,連接好以后依次加載libcomposite.ko、usb_f_mass_storage.ko和g_mass_storage.ko這三個驅動文件,順序不能錯了!命令如下:
depmod modprobe libcomposite.ko modprobe usb_f_mass_storage.ko modprobe g_mass_storage.ko file=/dev/sda1 removable=1 |
加載g_mass_storage.ko的時候使用file參數(shù)指定使用的大容量存儲設備,這里使用U盤對應的/dev/sda1。如果加載成功的話電腦就會出現(xiàn)一個U盤,這個U盤就是開發(fā)板模擬的,可以直接在電腦上對這個U盤進行讀寫,實際上就是操作插在開發(fā)板上的U盤。操作完成后要退出需要執(zhí)行如下命令:
rmmod g_mass_storage.ko rmmod usb_f_mass_storage.ko rmmod libcomposite.ko |
注意!不要將開發(fā)板上的EMMC或者NAND作為模擬U盤的存儲區(qū)域,因為linux下EMMC和NAND使用的文件系統(tǒng)一般都是EXT3/EXT4和UBIFS,這些文件系統(tǒng)類型和windows下的不兼容,如果掛載的話就會在windows下提示要格式化U盤!
USB聲卡實驗
USB聲卡就是USB接口的外置聲卡,一般電腦內部都自帶了聲卡,但是內部自帶的聲卡效果相對來說比較差,不能滿足很多HIFI玩家的需求。USB聲卡通過USB接口來傳遞音頻數(shù)據(jù),具體的ADC和DAC過程由聲卡完成,擺脫了電腦主板體積的限制,外置USB聲卡就可以做的很好。STM32MP1開發(fā)板板載了音頻解碼芯片,因此可以將STM32MP1開發(fā)板作為一個外置USB聲卡,配置Linux內核,配置路徑如下:
-> Device Drivers -> USB suppor -> USB Gadget Support -> USB Gadget precomposed configurations -> Audio Gadget //選中音頻,編譯為模塊 -> UAC 1.0 //選中 -> [*] UAC 1.0 (Legacy) //選中 UAC |
配置如下圖所示:
注意,這里也是編譯為驅動模塊,配置完成以后重新編譯內核、編譯模塊,會得到3個驅動模塊文件,模塊文件路徑如下:
drivers/usb/gadget/libcomposite.ko drivers/usb/gadget/function/usb_f_uac1_legacy.ko drivers/usb/gadget/legacy/g_audio.ko |
將上述三個.ko模塊文件拷貝到開發(fā)板根文件系統(tǒng)/lib/modules/5.4.31目錄下,拷貝完成以后使用新編譯出來的uImage啟動開發(fā)板,首先要按照之前學習的音頻驅動的方法配置STM32MP1的聲卡,保證聲卡播放正常!使用Typec數(shù)據(jù)線將開發(fā)板與電腦連接起來,最后依次加載 libcomposite.ko、usb_f_uac1_legacy.ko和g_audio.ko這三個驅動模塊,命令如下:
depmod modprobe libcomposite.ko modprobe usb_f_uac1_legacy.ko modprobe g_audio.ko |
加載完成以后稍等一會虛擬出一個USB聲卡,打開電腦的設備管理器,選擇“聲音、視頻和游戲控制器”,會發(fā)現(xiàn)有一個名為“AC Interface”設備,如下圖所示:
上圖中的“AC Interface”就是開發(fā)板模擬出來的USB聲卡,設置Windows,選擇音頻輸出使用“AC Interface”,Windows10設置如下圖所示:
一切設置好以后就可以從開發(fā)板上聽到電腦輸出的聲音,此時開發(fā)板就完全是一個USB聲
卡設備了。
關于USB驅動就講解到這里,本章并沒有深入到USB驅動具體編寫方式,只是對USB的協(xié)議做了簡單的介紹,后面講解了一下Linux內核自帶的USB HOST和DEVICE驅動的使用,Linux 內核已經集成了大量的USB設備驅動,至于其他特殊的就需要具體情況具體分析了。
總結
本章的學習重點,主要就是對USB設備做了一個大致的了解,然后對USB的傳輸協(xié)議大致做了介紹,這一部分可以多看看,如果之后想做項目有要用到USB設備的話這一部分要多琢磨一下。
然后就是具體的STM32MP157開發(fā)板的USB驅動的使用。
對于USB HOST來說,這一部分需要在設備樹中(.dts),在根節(jié)點下添加usb_phy_tuning節(jié)點(可以直接從stm32mp15xx-dkx.dtsi復制),然后在設備樹中添加usbphyc和usbphyc_port0的節(jié)點,之后在添加usbh_ehci節(jié)點。
以上就配置完成了,之后要具體使用USB驅動設備的話,就進入Linux內核里面取使能對應設備就可以了。
至于USB OTG的驅動,因為我這邊新買的肯定是最新的,就是FUSB302芯片。在設備樹里面追加usbphyc_port1節(jié)點,然后再加一個usbotg_hs節(jié)點,然后在根節(jié)點加上usbphyc_port1所需要的vdd_usb節(jié)點;之后添加i2c1節(jié)點并使能;最后配置fusb302的電氣屬性,在i2c1節(jié)點下添加fusb302節(jié)點。最后再修改一下驅動,把提供的驅動文件拷貝到drivers/usb/typec/tcpm目錄里面,最后進入內核配置使能FUSB302配置就可以了。
OTG主機實驗和HOST是一樣的;從機就需要先進入內核配置使能,然后需要“make modules”并按照前面寫的復制.ko到/lib/modules/5.4.31然后按照順序來modprobe,最后不用了就rmmod就可以了。