找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 19862|回复: 1
收起左侧

STM32 OTG 模块做U盘主机的兼容性问题

[复制链接]
ID:98618 发表于 2015-12-8 03:52 | 显示全部楼层 |阅读模式
作者:milershao
刚好几天前有个客户STM32F105的OTG模块操作U盘,发现个别U盘电脑能正常使用,而STM32F105OTG模块无法识别。ST官方相关FAE有做相关应用笔记,借花献佛并致谢,转过来与大家分享之。

问题回顾:

有客户使用 STM32F2的 OTG 库中的 U 盘主机例程在连接U盘时,有些 U 盘不能识别,甚至出现操作死机的情况。现就针对版本ST官方提供的 V2.1.0 的 USB 主机库中的 MSC Host 例程做一些修改,以能够兼容更U 盘。


问题调研:

1、有些 U 盘在收到 BOT_RESET 这个 MSC 类相关命令时,就不再有反应了:设备一直对后续主机发来的 IN 令牌回复 NAK 通过对 BOT_RESET 命令的调查得知,USB 规范为大容量设备定义了两种类型的复位:USB 端口复位和大容量设备BOT 复位。

然而USB 规范并未规定这两种复位对应到 SCSI 命令中是做什么操作。通常设备把 USB端口复位映射成 SCSI 的硬复位;有些设备把 BOT复位映射到设备的 hard reset,有的仅是映射成逻辑单元复位。该条命令通常用于主机对在 BOT 通信中出错的设备进行复位恢复。但是需要指出的是,有些 U 盘并没有完全遵守大容量规范,比如不实现对 BOT_RESET 命令的支持。在这种情况下,设备一般会回复 STALL,那么主机需要发送 Set Port Feature(PORT_RESET)来复位设备所连的 Hub 端口。但是这个 U 盘并没有回复 STALL,且 U 盘是直接连在 STM32 USB 主机上的,并没有接 Hub。于是,参照该 U 盘在 Window 下的连接操作的过程文件(tracer file),发现在 枚举完成后,Windows 并没有发送 BOT_RESET 命令,而是直接就发送 GET_Max_Lun 命令来获取 U 盘的逻辑盘符个数。

于是在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 文件如图 盘主机就走不下去了。


经查阅,有些只包含一个逻辑盘符的 U 盘可以对该命令回复数值 0 或者直接回复 STALL。 那么对于 USB 主机来说,在收到了该条命令的 STALL 回复后就应该第一:认为该 U 盘仅包含 一个逻辑盘符;第二:对 STALL 应答进行处理,然后继续下面的命令流程。

通过 USB2.0 协议规范(章节 9.2.7),我们得知在控制传输(Control Transfer)过程中,当设备收到的命令自己不支持或者不适合设备当前的设置,就认为是命令出错。那么设备通过在接 下来的数据阶段或者状态阶段回复 STALL 应答来告知主机这个错误。这种“协议 STALL”是 控制传输特有的;这样 STALL 的状态,会在下一个控制传输(Setup 令牌)的到来而解除。

我们看看 Windows 对 U 盘这样的回复是怎么处理,tracer 文件抓图如下:主机通过 Clear Feature 命令,参数 EP_Halt(这是一个控制传输)来把设备方端点的 Halt feature 清除掉。


从代码里可以看到,例程是有做这方面的处理的:

如果主机发送的 Get_Max_Lun 命令不被设 备支持,则将 MSCState 状态设定成 CTRL_ERROR_STATE发送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 文件却看不到主机走到了发送 Test_Unit_Ready 的命令。经过调试、代码跟踪,终于定位在 USBH_HandleControl()中。对 CTRL_DATA_IN_WAIT 的处理,当收到 URB_STALL 的应答后,没有给 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盘,发现个别U盘电脑能正常使用,而STM32F105OTG模块无法识别。ST官方相关FAE有做相关应用笔记,借花献佛并致谢,转过来与大家分享之。

问题回顾:

有客户使用 STM32F2的 OTG 库中的 U 盘主机例程在连接U盘时,有些 U 盘不能识别,甚至出现操作死机的情况。现就针对版本ST官方提供的 V2.1.0 的 USB 主机库中的 MSC Host 例程做一些修改,以能够兼容更U 盘。


问题调研:

1、有些 U 盘在收到 BOT_RESET 这个 MSC 类相关命令时,就不再有反应了:设备一直对后续主机发来的 IN 令牌回复 NAK 通过对 BOT_RESET 命令的调查得知,USB 规范为大容量设备定义了两种类型的复位:USB 端口复位和大容量设备BOT 复位。

然而USB 规范并未规定这两种复位对应到 SCSI 命令中是做什么操作。通常设备把 USB端口复位映射成 SCSI 的硬复位;有些设备把 BOT复位映射到设备的 hard reset,有的仅是映射成逻辑单元复位。该条命令通常用于主机对在 BOT 通信中出错的设备进行复位恢复。但是需要指出的是,有些 U 盘并没有完全遵守大容量规范,比如不实现对 BOT_RESET 命令的支持。在这种情况下,设备一般会回复 STALL,那么主机需要发送 Set Port Feature(PORT_RESET)来复位设备所连的 Hub 端口。但是这个 U 盘并没有回复 STALL,且 U 盘是直接连在 STM32 USB 主机上的,并没有接 Hub。于是,参照该 U 盘在 Window 下的连接操作的过程文件(tracer file),发现在 枚举完成后,Windows 并没有发送 BOT_RESET 命令,而是直接就发送 GET_Max_Lun 命令来获取 U 盘的逻辑盘符个数。

于是在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 文件如图 盘主机就走不下去了。


经查阅,有些只包含一个逻辑盘符的 U 盘可以对该命令回复数值 0 或者直接回复 STALL。 那么对于 USB 主机来说,在收到了该条命令的 STALL 回复后就应该第一:认为该 U 盘仅包含 一个逻辑盘符;第二:对 STALL 应答进行处理,然后继续下面的命令流程。

通过 USB2.0 协议规范(章节 9.2.7),我们得知在控制传输(Control Transfer)过程中,当设备收到的命令自己不支持或者不适合设备当前的设置,就认为是命令出错。那么设备通过在接 下来的数据阶段或者状态阶段回复 STALL 应答来告知主机这个错误。这种“协议 STALL”是 控制传输特有的;这样 STALL 的状态,会在下一个控制传输(Setup 令牌)的到来而解除。

我们看看 Windows 对 U 盘这样的回复是怎么处理,tracer 文件抓图如下:主机通过 Clear Feature 命令,参数 EP_Halt(这是一个控制传输)来把设备方端点的 Halt feature 清除掉。


从代码里可以看到,例程是有做这方面的处理的:

如果主机发送的 Get_Max_Lun 命令不被设 备支持,则将 MSCState 状态设定成 CTRL_ERROR_STATE发送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 文件却看不到主机走到了发送 Test_Unit_Ready 的命令。经过调试、代码跟踪,终于定位在 USBH_HandleControl()中。对 CTRL_DATA_IN_WAIT 的处理,当收到 URB_STALL 的应答后,没有给 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 盘。

回复

使用道具 举报

ID:230640 发表于 2017-9-3 07:18 | 显示全部楼层
你好,我遇到类似问题,想请教一下,我的QQ是20767248,方便的时候联系一下吧,谢谢
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表