STM32 USB Mass Storage 例程調(diào)試筆記
調(diào)試前的準(zhǔn)備
二、調(diào)試前準(zhǔn)備
調(diào)試之前花了三天的時(shí)間,大致的看了一下USB的框架,后來(lái)才發(fā)現(xiàn),沒(méi)什么必要,不過(guò)多學(xué)點(diǎn)知識(shí)總是好的。
作用:USB系統(tǒng)用來(lái)主要進(jìn)行查詢配置和給USB設(shè)備發(fā)送通用的命令,它要保證數(shù)據(jù)傳輸過(guò)程的數(shù)據(jù)完整性。設(shè)備枚舉過(guò)程中的各種設(shè)備描述符的獲取以及設(shè)置地址、設(shè)置配置都是通過(guò)控制傳輸來(lái)實(shí)現(xiàn)的。特點(diǎn):控制傳輸是雙向傳輸,數(shù)據(jù)量通常較小;數(shù)據(jù)傳送是無(wú)損性的。
僅批量傳輸協(xié)議中規(guī)定了兩個(gè)特殊的類請(qǐng)求:bulk-only Mass Storage Reset 和Get Max LUN,前者是復(fù)位到命令狀態(tài)的請(qǐng)求,后者是獲取最大邏輯單元的請(qǐng)求。
usb協(xié)議中采用的是小端格式,這一點(diǎn)要格外注意,比如ASCII 0x55、0x53,用小端格式表示就是0x5355
bmRequestType為0xa1,表示它是發(fā)送到接口的類輸入請(qǐng)求,bRequest為0xfe,wIndex為請(qǐng)求的接口號(hào),傳輸?shù)臄?shù)據(jù)長(zhǎng)度為1字節(jié),設(shè)備將在數(shù)據(jù)過(guò)程返回1字節(jié)的數(shù)據(jù),表示設(shè)備有多少個(gè)邏輯單元,0表示1個(gè)邏輯單元,1表示有兩個(gè)。
2.bulk-only Mass Storage Reset 的格式如下圖
bulk-only Mass Storage Reset請(qǐng)求是通知設(shè)備接下來(lái)的批量端點(diǎn)輸出數(shù)據(jù)為命令快封裝包CBW(Command Block Wrapper),在這個(gè)請(qǐng)求中,僅需要設(shè)置一下?tīng)顟B(tài),說(shuō)明接下來(lái)的數(shù)據(jù)是CBW,然后返回一個(gè)長(zhǎng)度為0的狀態(tài)數(shù)據(jù)包。
3.僅批量傳輸?shù)牡臄?shù)據(jù)流
類請(qǐng)求完成后,就進(jìn)入了數(shù)據(jù)傳輸過(guò)程,在僅批量數(shù)據(jù)傳輸協(xié)議中規(guī)定,數(shù)據(jù)傳輸分為三個(gè)階段:命令階段、數(shù)據(jù)階段和狀態(tài)階段。命令階段是由主機(jī)通過(guò)批量端點(diǎn)發(fā)送一個(gè)CBW(命令封裝包)的結(jié)構(gòu),在CBW中定義了要操作的命令以及傳輸數(shù)據(jù)的方向和數(shù)量,數(shù)據(jù)階段的傳輸方向由命令階段決定,而狀態(tài)階段則總是由設(shè)備返回該命令完成的狀態(tài)。
CBW的結(jié)構(gòu)如下圖
官方文檔對(duì)這些字段的介紹:
dCBWSignature:
Signature that helps identify this data packet as a CBW. The signature field shall contain the value
43425355h (little endian), indicating a CBW.
dCBWTag:
A Command Block Tag sent by the host. The device shall echo the contents of this field back to the
host in the dCSWTag field of the associated CSW. The dCSWTag positively associates a CSW with the
dCBWDataTransferLength:
The number of bytes of data that the host expects to transfer on the Bulk-In or Bulk-Out endpoint (as
bmCBWFlags:
The bits of this field are defined as follows:
Bit 7 Direction - the device shall ignore this bit if the dCBWDataTransferLength field is
zero, otherwise:
0 = Data-Out from host to the device,
1 = Data-In from the device to the host.
Bit 6 Obsolete. The host shall set this bit to zero.
Bits 5..0 Reserved - the host shall set these bits to zero.
bCBWLUN:
The device Logical Unit Number (LUN) to which the command block is being sent. For devices that
support multiple LUNs, the host shall place into this field the LUN to which this command block is
addressed. Otherwise, the host shall set this field to zero.
bCBWCBLength:
The valid length of the CBWCB in bytes. This defines the valid length of the command block. The
only legal values are 1 through 16 (01h through 10h). All other values are reserved.
CBWCB:
The command block to be executed by the device. The device shall interpret the first bCBWCBLength
bytes in this field as a command block as defined by the command set identified by bInterfaceSubClass .
If the command set supported by the device uses command blocks of fewer than 16 (10h) bytes in
length, the significant bytes shall be transferred first, beginning with the byte at offset 15 (Fh). The
device shall ignore the content of the CBWCB field past the byte at offset (15 + bCBWCBLength - 1).
命令封裝包CSW
dCSWSignature:
Signature that helps identify this data packet as a CSW. The signature field shall contain the value
53425355h (little endian), indicating CSW.
dCSWTag:
The device shall set this field to the value received in the dCBWTag of the associated CBW.
bCSWStatus:
bCSWStatus indicates the success or failure of the command. The device shall set this byte to zero if
the command completed successfully. A non-zero value shall indicate a failure during command
execution according to the following table:
Value Description
00h Command Passed ("good status")
01h Command Failed
02h Phase Error
03h and 04h Reserved (Obsolete)
05h to FFh Reserved
定義一個(gè)緩沖區(qū)用來(lái)接收命令塊封裝包CBW,然后進(jìn)入到數(shù)據(jù)處理階段,在數(shù)據(jù)處理中,對(duì)CBW進(jìn)行解碼,返回或者接收響應(yīng)的數(shù)據(jù)。數(shù)據(jù)發(fā)送或者接收完畢后,進(jìn)入到狀態(tài)階段,返回命令執(zhí)行的情況,然后再次進(jìn)入命令階段,等待主機(jī)發(fā)送CBW包。
3.SCSI命令集
小型計(jì)算機(jī)系統(tǒng)接口(英語(yǔ):Small Computer System Interface; 簡(jiǎn)寫:SCSI),一種用于計(jì)算機(jī)和智能設(shè)備之間(硬盤、軟驅(qū)、光驅(qū)、打印機(jī)、掃描儀等)系統(tǒng)級(jí)接口的獨(dú)立處理器標(biāo)準(zhǔn)。 SCSI是一種智能的通用接口標(biāo)準(zhǔn)。它是各種計(jì)算機(jī)與外部設(shè)備之間的接口標(biāo)準(zhǔn)。
在U盤中經(jīng)常用到的命令有:INQUIRY、READ CAPACITY 、READ(10)、WRITE(10)命令等。
INQUIRY命令請(qǐng)求查詢目標(biāo)設(shè)備的一些基本信息,操作碼為0x12,。
READ FORMAT CAPACITIES命令可以讓主機(jī)讀取設(shè)備各種可能的格式化容量的列表,如果設(shè)備中沒(méi)有存儲(chǔ)設(shè)備,則設(shè)備返回最大能夠支持的格式化容量。
讀容量命令READ CAPACITY可以讓主機(jī)讀取到當(dāng)前存儲(chǔ)媒介的容量,操作代碼為0x25,READ CAPACITY讀取的是實(shí)際的磁盤容量。
主機(jī)使用READ(10)命令來(lái)讀取實(shí)際磁盤的數(shù)據(jù),使用WRITE(10)來(lái)往設(shè)備中寫入實(shí)際的磁盤數(shù)據(jù)。
4.STM32 相關(guān)知識(shí)
STM32提供的有USB全速設(shè)備接口,支持USB全速總線、USB掛起/恢復(fù)操作,可以停止設(shè)備時(shí)鐘實(shí)現(xiàn)低功耗。USB和CAN共用一個(gè)專用的512字節(jié)的SRAM存儲(chǔ)器用于數(shù)據(jù)的發(fā)送和接收,不能同時(shí)使用USB和CAN總線。
PC主機(jī)和微控制器之間的數(shù)據(jù)傳輸是通過(guò)共享這一專用的數(shù)據(jù)緩沖區(qū)來(lái)完成的,數(shù)據(jù)緩沖區(qū)能被USB外設(shè)直接訪問(wèn)。這塊專用數(shù)據(jù)緩沖區(qū)的大小由所使用的端點(diǎn)數(shù)目和每個(gè)端點(diǎn)最大的數(shù)據(jù)分組大小所決定,每個(gè)端點(diǎn)最大可使用512 字節(jié)緩沖區(qū),最多可用于16個(gè)單向或8 個(gè)雙向端點(diǎn)。USB模塊同PC主機(jī)通信,根據(jù)USB規(guī)范實(shí)現(xiàn)令牌分組的檢測(cè),數(shù)據(jù)發(fā)送/ 接收的處理,和握手分組的處理。整個(gè)傳輸?shù)母袷接捎布瓿?,其中包括CRC的生成和校驗(yàn)。每個(gè)端點(diǎn)都有一個(gè)緩沖區(qū)描述塊,描述該端點(diǎn)使用的緩沖區(qū)地址、大小和需要傳輸?shù)淖止?jié)數(shù)。 當(dāng)USB模塊識(shí)別出一個(gè)有效的功能/ 端點(diǎn)的令牌分組時(shí),( 如果需要傳輸數(shù)據(jù)并且端點(diǎn)已配置) 隨之發(fā)生相關(guān)的數(shù)據(jù)傳輸。USB模塊通過(guò)一個(gè)內(nèi)部的16位寄存器實(shí)現(xiàn)端口與專用緩沖區(qū)的數(shù)據(jù)交換。在所有的數(shù)據(jù)傳輸完成后,如果需要,則根據(jù)傳輸?shù)姆较?,發(fā)送或接收適當(dāng)?shù)奈帐址纸M。在數(shù)據(jù)傳輸結(jié)束時(shí),USB模塊將觸發(fā)與端點(diǎn)相關(guān)的中斷,通過(guò)讀狀態(tài)寄存器和/ 或者利用不同的中斷處理程序,微控制器可以確定
● 哪個(gè)端點(diǎn)需要得到服務(wù)
● 產(chǎn)生如位填充、格式、CRC、協(xié)議、缺失ACK、緩沖區(qū)溢出/ 緩沖區(qū)未滿等錯(cuò)誤時(shí),正在進(jìn)行的是哪種類型的傳輸。
USB模塊對(duì)同步傳輸和高吞吐量的批量傳輸提供了特殊的雙緩沖區(qū)機(jī)制,在微控制器使用一個(gè)緩沖區(qū)的時(shí)候,該機(jī)制保證了USB外設(shè)總是可以使用另一個(gè)緩沖區(qū)。在任何不需要使用USB模塊的時(shí)候,通過(guò)寫控制寄存器總可以使USB模塊置于低功耗模式(SUSPEND模式) 。在這種模式下,不產(chǎn)生任何靜態(tài)電流消耗,同時(shí)USB時(shí)鐘也會(huì)減慢或停止。通過(guò)對(duì)USB線上數(shù)據(jù)傳輸?shù)臋z測(cè),可以在低功耗模式下喚醒USB模塊。也可以將一特定的中斷輸入源直接連接到喚醒引腳上,以使系統(tǒng)能立即恢復(fù)正常的時(shí)鐘系統(tǒng),并支持直接啟動(dòng)或停止時(shí)鐘系統(tǒng)。
三、例程分析
1.首先進(jìn)行系統(tǒng)配置,如時(shí)鐘、USB、NAND FLASH、SD卡的初始化等
USB低優(yōu)先級(jí)中斷(通道20):可由所有USB事件觸發(fā)(正確傳輸,USB復(fù)位等)。固件在處理中斷前應(yīng)當(dāng)首先確定中斷源。中斷處理函數(shù)為:USB_Istr
USB高優(yōu)先級(jí)中斷(通道19):僅能由同步和雙緩沖批量傳輸?shù)恼_傳輸事件觸發(fā),目的是保證最大的傳輸速率。它的中斷處理函數(shù)是CTR_HP。
說(shuō)明:函數(shù)CTR_HP和CTR_LP最終都會(huì)調(diào)用Mass_Storage_In(端點(diǎn)1)和Mass_Storage_Out(端點(diǎn)2)兩個(gè)函數(shù)來(lái)和PC端的USB HOST 通信
為了讓SD I/O卡能夠中斷多媒體卡/SD 模塊,在SD接口上有一個(gè)具有中斷功能的引腳——第8腳,在4 位SD模式下這個(gè)腳是SDIO_D1,卡用它向多媒體卡/SD 模塊提出中斷申請(qǐng)。對(duì)于每一個(gè)卡或卡內(nèi)的功能,中斷功能是可選的。SD I/O的中斷是電平有效,即在被識(shí)別并得到多媒體卡/SD 模塊的響應(yīng)之前,中斷信號(hào)線必須保持有效電平( 低) ,在中斷過(guò)程結(jié)束后保持無(wú)效電平(高)。在多媒體卡/SD 模塊服務(wù)了中斷請(qǐng)求后,通過(guò)一個(gè)I/O 寫操作,寫入適當(dāng)?shù)奈坏絊D I/O卡的內(nèi)部寄存器,即可清除中斷狀態(tài)位。所有SD I/O卡的中斷輸出是低電平有效,多媒體卡/SD 模塊在所有數(shù)據(jù)線(SDIO/D[3:0])上提供上拉電阻。多媒體卡/SD 模塊在中斷階段對(duì)第8 腳(SDIO_D/IRQ) 采樣并進(jìn)行中斷檢測(cè),其它時(shí)間該信號(hào)線上的數(shù)值將被忽略。
4.進(jìn)入while循環(huán),等待中斷的發(fā)生
主機(jī)發(fā)送Get Max LUN請(qǐng)求,獲取最大邏輯單元。
主機(jī)通過(guò)批量端點(diǎn)發(fā)送CBW包,在CBW中定義了要操作的命令以及傳輸數(shù)據(jù)的方向和數(shù)量,返回該命令完成的狀態(tài),即由設(shè)備返回CSW包,端點(diǎn)2用于輸出,端點(diǎn)1用于輸入數(shù)據(jù)至主機(jī)。CBW的標(biāo)志是0x55,0x53,0x42,0x43。
在USB主機(jī)和設(shè)備的通信過(guò)程中,數(shù)據(jù)會(huì)先被放到一個(gè)大小為512字節(jié)的專用SRAM緩沖區(qū)里面,然后再傳輸?shù)街鳈C(jī)或者USB設(shè)備。
四、例程問(wèn)題現(xiàn)象和解決方法
1.NAND FLASH盤可以被識(shí)別,格式化失敗。既然NAND FLASH盤可以被識(shí)別,那就表明USB的控制傳輸沒(méi)出現(xiàn)問(wèn)題,USB批量傳輸出問(wèn)題了,而且最可能的是NAND FLASH的驅(qū)動(dòng)有問(wèn)題,仔細(xì)看完代碼,發(fā)現(xiàn)在建立壞塊表,對(duì)Spare 區(qū)域進(jìn)行讀操作中,對(duì)NAND FLASH 有一個(gè)NAND_CMD_AREA_TRUE1命令操作,查看代碼,
#define NAND_CMD_AREA_TRUE1
2.SD盤也能被識(shí)別,不能格式化。開(kāi)始用的是2G的SD卡,后來(lái)嘗試1G和512M的,它們都能用,也就是說(shuō),這個(gè)SD卡驅(qū)動(dòng)只識(shí)別1G和512M的SD卡。
在代碼中添加調(diào)試信息,結(jié)果是寫入的塊長(zhǎng)度出錯(cuò)。通過(guò)對(duì)讀SD卡信息了解到,2G的SD卡,塊大小是1024字節(jié),其它的卡都是512字節(jié)。我在SDIO例程中設(shè)置塊大小為1024字節(jié),讀寫出錯(cuò),設(shè)置512字節(jié),居然是正確的。
USB MassStorage例程中是首先從SD卡中讀取SD卡塊大小的值,按照這個(gè)值來(lái)讀寫SD卡,而實(shí)際上2G的SD卡只能按照512字節(jié)來(lái)讀寫。所以在讀取塊大小的值后,把塊的大小除以2,塊數(shù)目乘以2,卡的總?cè)萘坎蛔?,程序運(yùn)行后,一切正常了。
評(píng)論