找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 20907|回復(fù): 1
打印 上一主題 下一主題
收起左側(cè)

STM32 OTG 模塊做U盤主機的兼容性問題

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:98618 發(fā)表于 2015-12-8 03:52 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
作者:milershao
剛好幾天前有個客戶STM32F105的OTG模塊操作U盤,發(fā)現(xiàn)個別U盤電腦能正常使用,而STM32F105OTG模塊無法識別。ST官方相關(guān)FAE有做相關(guān)應(yīng)用筆記,借花獻佛并致謝,轉(zhuǎn)過來與大家分享之。

問題回顧:

有客戶使用 STM32F2的 OTG 庫中的 U 盤主機例程在連接U盤時,有些 U 盤不能識別,甚至出現(xiàn)操作死機的情況�,F(xiàn)就針對版本ST官方提供的 V2.1.0 的 USB 主機庫中的 MSC Host 例程做一些修改,以能夠兼容更U 盤。


問題調(diào)研:

1、有些 U 盤在收到 BOT_RESET 這個 MSC 類相關(guān)命令時,就不再有反應(yīng)了:設(shè)備一直對后續(xù)主機發(fā)來的 IN 令牌回復(fù) NAK 通過對 BOT_RESET 命令的調(diào)查得知,USB 規(guī)范為大容量設(shè)備定義了兩種類型的復(fù)位:USB 端口復(fù)位和大容量設(shè)備BOT 復(fù)位。

然而USB 規(guī)范并未規(guī)定這兩種復(fù)位對應(yīng)到 SCSI 命令中是做什么操作。通常設(shè)備把 USB端口復(fù)位映射成 SCSI 的硬復(fù)位;有些設(shè)備把 BOT復(fù)位映射到設(shè)備的 hard reset,有的僅是映射成邏輯單元復(fù)位。該條命令通常用于主機對在 BOT 通信中出錯的設(shè)備進行復(fù)位恢復(fù)。但是需要指出的是,有些 U 盤并沒有完全遵守大容量規(guī)范,比如不實現(xiàn)對 BOT_RESET 命令的支持。在這種情況下,設(shè)備一般會回復(fù) STALL,那么主機需要發(fā)送 Set Port Feature(PORT_RESET)來復(fù)位設(shè)備所連的 Hub 端口。但是這個 U 盤并沒有回復(fù) STALL,且 U 盤是直接連在 STM32 USB 主機上的,并沒有接 Hub。于是,參照該 U 盤在 Window 下的連接操作的過程文件(tracer file),發(fā)現(xiàn)在 枚舉完成后,Windows 并沒有發(fā)送 BOT_RESET 命令,而是直接就發(fā)送 GET_Max_Lun 命令來獲取 U 盤的邏輯盤符個數(shù)。

于是在STM32 的 USB Host 例程中注釋掉 BOT_RESET 命令,果然可以正確操作了。修改代碼如下:

USBH_MSC_Handle()

{......

{ switch(USBH_MSC_BOTXferParam.MSCState)

{ case USBH_MSC_BOT_INIT_STATE:

USBH_MSC_Init(pdev);

//USBH_MSC_BOTXferParam.MSCState = USBH_MSC_BOT_RESET;

USBH_MSC_BOTXferParam.MSCState = USBH_MSC_GET_MAX_LUN;

break;

case…

2、還有些 U 盤在收到 Get_Max_Lun 命令返回 STALL,但是 U 抓到的 tracer 文件如圖 盤主機就走不下去了。


經(jīng)查閱,有些只包含一個邏輯盤符的 U 盤可以對該命令回復(fù)數(shù)值 0 或者直接回復(fù) STALL。 那么對于 USB 主機來說,在收到了該條命令的 STALL 回復(fù)后就應(yīng)該第一:認為該 U 盤僅包含 一個邏輯盤符;第二:對 STALL 應(yīng)答進行處理,然后繼續(xù)下面的命令流程。

通過 USB2.0 協(xié)議規(guī)范(章節(jié) 9.2.7),我們得知在控制傳輸(Control Transfer)過程中,當設(shè)備收到的命令自己不支持或者不適合設(shè)備當前的設(shè)置,就認為是命令出錯。那么設(shè)備通過在接 下來的數(shù)據(jù)階段或者狀態(tài)階段回復(fù) STALL 應(yīng)答來告知主機這個錯誤。這種“協(xié)議 STALL”是 控制傳輸特有的;這樣 STALL 的狀態(tài),會在下一個控制傳輸(Setup 令牌)的到來而解除。

我們看看 Windows 對 U 盤這樣的回復(fù)是怎么處理,tracer 文件抓圖如下:主機通過 Clear Feature 命令,參數(shù) EP_Halt(這是一個控制傳輸)來把設(shè)備方端點的 Halt feature 清除掉。


從代碼里可以看到,例程是有做這方面的處理的:

如果主機發(fā)送的 Get_Max_Lun 命令不被設(shè) 備支持,則將 MSCState 狀態(tài)設(shè)定成 CTRL_ERROR_STATE發(fā)送Clear Feature 的命令,以及隨后 的 Test_Unit_Ready 命令。

USBH_MSC_Handle()

......

{ switch(USBH_MSC_BOTXferParam.MSCState)

{ case USBH_MSC_GET_MAX_LUN:

/* Issue GetMaxLUN request */

status = USBH_MSC_GETMaxLUN(pdev, phost);

if(status == USBH_OK )

{

MSC_Machine.maxLun = *(MSC_Machine.buff) ;

/* If device has more that one logical unit then it is not supported */

if((MSC_Machine.maxLun > 0) && (maxLunExceed == FALSE))

{

maxLunExceed = TRUE;

pphost->usr_cb->DeviceNotSupported();

break;

}

USBH_MSC_BOTXferParam.MSCState = USBH_MSC_TEST_UNIT_READY;

}

if(status == USBH_NOT_SUPPORTED )

{

/* If the Command has failed, then we need to move to Next State, after

STALL condition is cleared by Control-Transfer */

USBH_MSC_BOTXferParam.MSCStateBkp = USBH_MSC_TEST_UNIT_READY;

/* a Clear Feature should be issued here */

USBH_MSC_BOTXferParam.MSCState = USBH_MSC_CTRL_ERROR_STATE;

}

break;

……

但是從抓到的 tracer 文件卻看不到主機走到了發(fā)送 Test_Unit_Ready 的命令。經(jīng)過調(diào)試、代碼跟蹤,終于定位在 USBH_HandleControl()中。對 CTRL_DATA_IN_WAIT 的處理,當收到 URB_STALL 的應(yīng)答后,沒有給 phost 的 Control.state 賦值成 CTRL_STALLED



USBH_HandleControl( )

{

......

switch (phost->Control.state)

{

case CTRL_DATA_IN_WAIT:

URB_Status = HCD_GetURB_State(pdev , phost->Control.hc_num_in);

/* check is DATA packet transfered successfully */

if (URB_Status == URB_DONE)

{

phost->Control.state = CTRL_STATUS_OUT;

}

/* manage error cases*/

if (URB_Status == URB_STALL)

{

/* In stall case, return to previous machine state*/

phost->gState = phost->gStateBkp;

phost->Control.state = CTRL_STALLED; //

}

else if ......


3、還有一點需要注意的是:本版的 U 盤主機例程,暫時不支持多盤符 U 盤。 剛好幾天前有個客戶STM32F105的OTG模塊操作U盤,發(fā)現(xiàn)個別U盤電腦能正常使用,而STM32F105OTG模塊無法識別。ST官方相關(guān)FAE有做相關(guān)應(yīng)用筆記,借花獻佛并致謝,轉(zhuǎn)過來與大家分享之。

問題回顧:

有客戶使用 STM32F2的 OTG 庫中的 U 盤主機例程在連接U盤時,有些 U 盤不能識別,甚至出現(xiàn)操作死機的情況�,F(xiàn)就針對版本ST官方提供的 V2.1.0 的 USB 主機庫中的 MSC Host 例程做一些修改,以能夠兼容更U 盤。


問題調(diào)研:

1、有些 U 盤在收到 BOT_RESET 這個 MSC 類相關(guān)命令時,就不再有反應(yīng)了:設(shè)備一直對后續(xù)主機發(fā)來的 IN 令牌回復(fù) NAK 。通過對 BOT_RESET 命令的調(diào)查得知,USB 規(guī)范為大容量設(shè)備定義了兩種類型的復(fù)位:USB 端口復(fù)位和大容量設(shè)備BOT 復(fù)位。

然而USB 規(guī)范并未規(guī)定這兩種復(fù)位對應(yīng)到 SCSI 命令中是做什么操作。通常設(shè)備把 USB端口復(fù)位映射成 SCSI 的硬復(fù)位;有些設(shè)備把 BOT復(fù)位映射到設(shè)備的 hard reset,有的僅是映射成邏輯單元復(fù)位。該條命令通常用于主機對在 BOT 通信中出錯的設(shè)備進行復(fù)位恢復(fù)。但是需要指出的是,有些 U 盤并沒有完全遵守大容量規(guī)范,比如不實現(xiàn)對 BOT_RESET 命令的支持。在這種情況下,設(shè)備一般會回復(fù) STALL,那么主機需要發(fā)送 Set Port Feature(PORT_RESET)來復(fù)位設(shè)備所連的 Hub 端口。但是這個 U 盤并沒有回復(fù) STALL,且 U 盤是直接連在 STM32 USB 主機上的,并沒有接 Hub。于是,參照該 U 盤在 Window 下的連接操作的過程文件(tracer file),發(fā)現(xiàn)在 枚舉完成后,Windows 并沒有發(fā)送 BOT_RESET 命令,而是直接就發(fā)送 GET_Max_Lun 命令來獲取 U 盤的邏輯盤符個數(shù)。

于是在STM32 的 USB Host 例程中注釋掉 BOT_RESET 命令,果然可以正確操作了。修改代碼如下:

USBH_MSC_Handle()

{......

{ switch(USBH_MSC_BOTXferParam.MSCState)

{ case USBH_MSC_BOT_INIT_STATE:

USBH_MSC_Init(pdev);

//USBH_MSC_BOTXferParam.MSCState = USBH_MSC_BOT_RESET;

USBH_MSC_BOTXferParam.MSCState = USBH_MSC_GET_MAX_LUN;

break;

case…

2、還有些 U 盤在收到 Get_Max_Lun 命令返回 STALL,但是 U 抓到的 tracer 文件如圖 盤主機就走不下去了。


經(jīng)查閱,有些只包含一個邏輯盤符的 U 盤可以對該命令回復(fù)數(shù)值 0 或者直接回復(fù) STALL。 那么對于 USB 主機來說,在收到了該條命令的 STALL 回復(fù)后就應(yīng)該第一:認為該 U 盤僅包含 一個邏輯盤符;第二:對 STALL 應(yīng)答進行處理,然后繼續(xù)下面的命令流程。

通過 USB2.0 協(xié)議規(guī)范(章節(jié) 9.2.7),我們得知在控制傳輸(Control Transfer)過程中,當設(shè)備收到的命令自己不支持或者不適合設(shè)備當前的設(shè)置,就認為是命令出錯。那么設(shè)備通過在接 下來的數(shù)據(jù)階段或者狀態(tài)階段回復(fù) STALL 應(yīng)答來告知主機這個錯誤。這種“協(xié)議 STALL”是 控制傳輸特有的;這樣 STALL 的狀態(tài),會在下一個控制傳輸(Setup 令牌)的到來而解除。

我們看看 Windows 對 U 盤這樣的回復(fù)是怎么處理,tracer 文件抓圖如下:主機通過 Clear Feature 命令,參數(shù) EP_Halt(這是一個控制傳輸)來把設(shè)備方端點的 Halt feature 清除掉。


從代碼里可以看到,例程是有做這方面的處理的:

如果主機發(fā)送的 Get_Max_Lun 命令不被設(shè) 備支持,則將 MSCState 狀態(tài)設(shè)定成 CTRL_ERROR_STATE,發(fā)送Clear Feature 的命令,以及隨后 的 Test_Unit_Ready 命令。

USBH_MSC_Handle()

......

{ switch(USBH_MSC_BOTXferParam.MSCState)

{ case USBH_MSC_GET_MAX_LUN:

/* Issue GetMaxLUN request */

status = USBH_MSC_GETMaxLUN(pdev, phost);

if(status == USBH_OK )

{

MSC_Machine.maxLun = *(MSC_Machine.buff) ;

/* If device has more that one logical unit then it is not supported */

if((MSC_Machine.maxLun > 0) && (maxLunExceed == FALSE))

{

maxLunExceed = TRUE;

pphost->usr_cb->DeviceNotSupported();

break;

}

USBH_MSC_BOTXferParam.MSCState = USBH_MSC_TEST_UNIT_READY;

}

if(status == USBH_NOT_SUPPORTED )

{

/* If the Command has failed, then we need to move to Next State, after

STALL condition is cleared by Control-Transfer */

USBH_MSC_BOTXferParam.MSCStateBkp = USBH_MSC_TEST_UNIT_READY;

/* a Clear Feature should be issued here */

USBH_MSC_BOTXferParam.MSCState = USBH_MSC_CTRL_ERROR_STATE;

}

break;

……

但是從抓到的 tracer 文件卻看不到主機走到了發(fā)送 Test_Unit_Ready 的命令。經(jīng)過調(diào)試、代碼跟蹤,終于定位在 USBH_HandleControl()中。對 CTRL_DATA_IN_WAIT 的處理,當收到 URB_STALL 的應(yīng)答后,沒有給 phost 的 Control.state 賦值成 CTRL_STALLED!



USBH_HandleControl( )

{

......

switch (phost->Control.state)

{

case CTRL_DATA_IN_WAIT:

URB_Status = HCD_GetURB_State(pdev , phost->Control.hc_num_in);

/* check is DATA packet transfered successfully */

if (URB_Status == URB_DONE)

{

phost->Control.state = CTRL_STATUS_OUT;

}

/* manage error cases*/

if (URB_Status == URB_STALL)

{

/* In stall case, return to previous machine state*/

phost->gState = phost->gStateBkp;

phost->Control.state = CTRL_STALLED; //

}

else if ......


3、還有一點需要注意的是:本版的 U 盤主機例程,暫時不支持多盤符 U 盤。

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏2 分享淘帖 頂 踩
回復(fù)

使用道具 舉報

沙發(fā)
ID:230640 發(fā)表于 2017-9-3 07:18 | 只看該作者
你好,我遇到類似問題,想請教一下,我的QQ是20767248,方便的時候聯(lián)系一下吧,謝謝
回復(fù)

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機教程網(wǎng)

快速回復(fù) 返回頂部 返回列表