問(wèn)題回顧:
有客戶(hù)使用 STM32F2的 OTG 庫(kù)中的 U 盤(pán)主機(jī)例程在連接U盤(pán)時(shí),有些 U 盤(pán)不能識(shí)別,甚至出現(xiàn)操作死機(jī)的情況,F(xiàn)就針對(duì)版本ST官方提供的 V2.1.0 的 USB 主機(jī)庫(kù)中的 MSC Host 例程做一些修改,以能夠兼容更多U 盤(pán)。
問(wèn)題調(diào)研:
1、有些 U 盤(pán)在收到 BOT_RESET 這個(gè) MSC 類(lèi)相關(guān)命令時(shí),就不再有反應(yīng)了:設(shè)備一直對(duì)后續(xù)主機(jī)發(fā)來(lái)的 IN 令牌回復(fù) NAK 。通過(guò)對(duì) BOT_RESET 命令的調(diào)查得知,USB 規(guī)范為大容量設(shè)備定義了兩種類(lèi)型的復(fù)位:USB 端口復(fù)位和大容量設(shè)備BOT 復(fù)位。
然而USB 規(guī)范并未規(guī)定這兩種復(fù)位對(duì)應(yīng)到 SCSI 命令中是做什么操作。通常設(shè)備把 USB端口復(fù)位映射成 SCSI 的硬復(fù)位;有些設(shè)備把 BOT復(fù)位映射到設(shè)備的 hard reset,有的僅是映射成邏輯單元復(fù)位。該條命令通常用于主機(jī)對(duì)在 BOT 通信中出錯(cuò)的設(shè)備進(jìn)行復(fù)位恢復(fù)。但是需要指出的是,有些 U 盤(pán)并沒(méi)有完全遵守大容量規(guī)范,比如不實(shí)現(xiàn)對(duì) BOT_RESET 命令的支持。在這種情況下,設(shè)備一般會(huì)回復(fù) STALL,那么主機(jī)需要發(fā)送 Set Port Feature(PORT_RESET)來(lái)復(fù)位設(shè)備所連的 Hub 端口。但是這個(gè) U 盤(pán)并沒(méi)有回復(fù) STALL,且 U 盤(pán)是直接連在 STM32 USB 主機(jī)上的,并沒(méi)有連接 Hub。于是,參照該 U 盤(pán)在 Window 下的連接操作的過(guò)程文件(tracer file),發(fā)現(xiàn)在 枚舉完成后,Windows 并沒(méi)有發(fā)送 BOT_RESET 命令,而是直接就發(fā)送 GET_Max_Lun 命令來(lái)獲取 U 盤(pán)的邏輯盤(pán)符個(gè)數(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 盤(pán)在收到 Get_Max_Lun 命令返回 STALL,但是 U 抓到的 tracer 文件如圖 盤(pán)主機(jī)就走不下去了。
經(jīng)查閱,有些只包含一個(gè)邏輯盤(pán)符的 U 盤(pán)可以對(duì)該命令回復(fù)數(shù)值 0 或者直接回復(fù) STALL。 那么對(duì)于 USB 主機(jī)來(lái)說(shuō),在收到了該條命令的 STALL 回復(fù)后就應(yīng)該第一:認(rèn)為該 U 盤(pán)僅包含 一個(gè)邏輯盤(pán)符;第二:對(duì) STALL 應(yīng)答進(jìn)行處理,然后繼續(xù)下面的命令流程。
通過(guò) USB2.0 協(xié)議規(guī)范(章節(jié) 9.2.7),我們得知在控制傳輸(Control Transfer)過(guò)程中,當(dāng)設(shè)備收到的命令自己不支持或者不適合設(shè)備當(dāng)前的設(shè)置,就認(rèn)為是命令出錯(cuò)。那么設(shè)備通過(guò)在接 下來(lái)的數(shù)據(jù)階段或者狀態(tài)階段回復(fù) STALL 應(yīng)答來(lái)告知主機(jī)這個(gè)錯(cuò)誤。這種“協(xié)議 STALL”是 控制傳輸特有的;這樣 STALL 的狀態(tài),會(huì)在下一個(gè)控制傳輸(Setup 令牌)的到來(lái)而解除。
我們看看 Windows 對(duì) U 盤(pán)這樣的回復(fù)是怎么處理,tracer 文件抓圖如下:主機(jī)通過(guò) Clear Feature 命令,參數(shù) EP_Halt(這是一個(gè)控制傳輸)來(lái)把設(shè)備方端點(diǎn)的 Halt feature 清除掉。
從代碼里可以看到,例程是有做這方面的處理的:
如果主機(jī)發(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 文件卻看不到主機(jī)走到了發(fā)送 Test_Unit_Ready 的命令。經(jīng)過(guò)調(diào)試、代碼跟蹤,終于定位在 USBH_HandleControl()中。對(duì) CTRL_DATA_IN_WAIT 的處理,當(dāng)收到 URB_STALL 的應(yīng)答后,沒(méi)有給 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、還有一點(diǎn)需要注意的是:本版的 U 盤(pán)主機(jī)例程,暫時(shí)不支持多盤(pán)符 U 盤(pán)。 剛好幾天前有個(gè)客戶(hù)STM32F105的OTG模塊操作U盤(pán),發(fā)現(xiàn)個(gè)別U盤(pán)電腦能正常使用,而STM32F105OTG模塊無(wú)法識(shí)別。ST官方相關(guān)FAE有做相關(guān)應(yīng)用筆記,借花獻(xiàn)佛并致謝,轉(zhuǎn)過(guò)來(lái)與大家分享之。
問(wèn)題回顧:
有客戶(hù)使用 STM32F2的 OTG 庫(kù)中的 U 盤(pán)主機(jī)例程在連接U盤(pán)時(shí),有些 U 盤(pán)不能識(shí)別,甚至出現(xiàn)操作死機(jī)的情況,F(xiàn)就針對(duì)版本ST官方提供的 V2.1.0 的 USB 主機(jī)庫(kù)中的 MSC Host 例程做一些修改,以能夠兼容更多U 盤(pán)。
問(wèn)題調(diào)研:
1、有些 U 盤(pán)在收到 BOT_RESET 這個(gè) MSC 類(lèi)相關(guān)命令時(shí),就不再有反應(yīng)了:設(shè)備一直對(duì)后續(xù)主機(jī)發(fā)來(lái)的 IN 令牌回復(fù) NAK 。通過(guò)對(duì) BOT_RESET 命令的調(diào)查得知,USB 規(guī)范為大容量設(shè)備定義了兩種類(lèi)型的復(fù)位:USB 端口復(fù)位和大容量設(shè)備BOT 復(fù)位。
然而USB 規(guī)范并未規(guī)定這兩種復(fù)位對(duì)應(yīng)到 SCSI 命令中是做什么操作。通常設(shè)備把 USB端口復(fù)位映射成 SCSI 的硬復(fù)位;有些設(shè)備把 BOT復(fù)位映射到設(shè)備的 hard reset,有的僅是映射成邏輯單元復(fù)位。該條命令通常用于主機(jī)對(duì)在 BOT 通信中出錯(cuò)的設(shè)備進(jìn)行復(fù)位恢復(fù)。但是需要指出的是,有些 U 盤(pán)并沒(méi)有完全遵守大容量規(guī)范,比如不實(shí)現(xiàn)對(duì) BOT_RESET 命令的支持。在這種情況下,設(shè)備一般會(huì)回復(fù) STALL,那么主機(jī)需要發(fā)送 Set Port Feature(PORT_RESET)來(lái)復(fù)位設(shè)備所連的 Hub 端口。但是這個(gè) U 盤(pán)并沒(méi)有回復(fù) STALL,且 U 盤(pán)是直接連在 STM32 USB 主機(jī)上的,并沒(méi)有連接 Hub。于是,參照該 U 盤(pán)在 Window 下的連接操作的過(guò)程文件(tracer file),發(fā)現(xiàn)在 枚舉完成后,Windows 并沒(méi)有發(fā)送 BOT_RESET 命令,而是直接就發(fā)送 GET_Max_Lun 命令來(lái)獲取 U 盤(pán)的邏輯盤(pán)符個(gè)數(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 盤(pán)在收到 Get_Max_Lun 命令返回 STALL,但是 U 抓到的 tracer 文件如圖 盤(pán)主機(jī)就走不下去了。
經(jīng)查閱,有些只包含一個(gè)邏輯盤(pán)符的 U 盤(pán)可以對(duì)該命令回復(fù)數(shù)值 0 或者直接回復(fù) STALL。 那么對(duì)于 USB 主機(jī)來(lái)說(shuō),在收到了該條命令的 STALL 回復(fù)后就應(yīng)該第一:認(rèn)為該 U 盤(pán)僅包含 一個(gè)邏輯盤(pán)符;第二:對(duì) STALL 應(yīng)答進(jìn)行處理,然后繼續(xù)下面的命令流程。
通過(guò) USB2.0 協(xié)議規(guī)范(章節(jié) 9.2.7),我們得知在控制傳輸(Control Transfer)過(guò)程中,當(dāng)設(shè)備收到的命令自己不支持或者不適合設(shè)備當(dāng)前的設(shè)置,就認(rèn)為是命令出錯(cuò)。那么設(shè)備通過(guò)在接 下來(lái)的數(shù)據(jù)階段或者狀態(tài)階段回復(fù) STALL 應(yīng)答來(lái)告知主機(jī)這個(gè)錯(cuò)誤。這種“協(xié)議 STALL”是 控制傳輸特有的;這樣 STALL 的狀態(tài),會(huì)在下一個(gè)控制傳輸(Setup 令牌)的到來(lái)而解除。
我們看看 Windows 對(duì) U 盤(pán)這樣的回復(fù)是怎么處理,tracer 文件抓圖如下:主機(jī)通過(guò) Clear Feature 命令,參數(shù) EP_Halt(這是一個(gè)控制傳輸)來(lái)把設(shè)備方端點(diǎn)的 Halt feature 清除掉。
從代碼里可以看到,例程是有做這方面的處理的:
如果主機(jī)發(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 文件卻看不到主機(jī)走到了發(fā)送 Test_Unit_Ready 的命令。經(jīng)過(guò)調(diào)試、代碼跟蹤,終于定位在 USBH_HandleControl()中。對(duì) CTRL_DATA_IN_WAIT 的處理,當(dāng)收到 URB_STALL 的應(yīng)答后,沒(méi)有給 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、還有一點(diǎn)需要注意的是:本版的 U 盤(pán)主機(jī)例程,暫時(shí)不支持多盤(pán)符 U 盤(pán)。
歡迎光臨 (http://www.torrancerestoration.com/bbs/) | Powered by Discuz! X3.1 |