你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】OTG 做 U 盘主机的兼容性提高

[复制链接]
STMCU小助手 发布时间:2022-2-19 17:54
问题:
! Z$ K& c1 H: E# Z某客户使用 STM32F2 的 OTG 库中的 U 盘主机例程在连接 U 盘时,有些 U 盘不能识别,甚至出现操作死机的情况。现就针对版本 V2.1.0 的 USB 主机库中的 MSC Host 例程做一些修改,以能够兼容更多 U 盘。
7 b% k) X" d3 t: }  B5 I X8O(E)K2_FOKZ%Y22ZDB5EX.png
9 U5 b6 N5 Z3 _) f. q+ f# K
* C# o- }; B* X9 I' ?: ?/ }  k调研:: [% ~9 V  r  @) u# X
1.有些 U 盘在收到 BOT_RESET 这个 MSC 类相关命令时,就不再有反应了:设备一直对后续主机发来的 IN 令牌回复 NAK。通过对 BOT_RESET 命令的调查得知,USB 规范为大容量设备定义了两种类型的复位:USB 端口复位和大容量设备 BOT 复位。USB 规范并未规定这两种复位对应到 SCSI命令中是做什么操作,因此也没有规定在收到这些命令后 SCSI 的操作。通常设备把 USB 端口复位映射成 SCSI 的硬复位;有些设备把 BOT 复位映射到 hard reset,有的仅是映射成逻辑单元复位。该条命令通常用于主机对在 BOT 通信中出错的设备进行复位恢复。但是需要指出的是,有些 U 盘并没有完全遵守大容量规范,比如就不实现对 BOT_RESET 命令的支持。在这种情况下,( |0 [' @4 }$ A+ V  ]- U% k6 Z" T
设备一般会回复 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 命令,果然就可以正确操作了。修改代码如下:* Q$ |, G7 n. {) N
  1. <usbh_msc_core.c>6 J9 L' r4 b7 i3 i2 X; K" k
  2. USBH_MSC_Handle()
    ! S2 G% e" w/ L$ R3 t/ O
  3. {
    ! ^" E$ N6 u/ E# p5 z- f
  4. switch(USBH_MSC_BOTXferParam.MSCState)9 B) I/ S/ L9 C9 k. t3 Y  f$ |6 q
  5. {
    : [9 f5 X5 S4 W2 i% v
  6. case USBH_MSC_BOT_INIT_STATE:
    # b; d  h/ m/ j0 O, T
  7. USBH_MSC_Init(pdev);
    % P. F6 ]9 m: x3 A7 n# v( e( k
  8. //USBH_MSC_BOTXferParam.MSCState = USBH_MSC_BOT_RESET;
    ! \& T1 u5 C3 t4 R
  9. USBH_MSC_BOTXferParam.MSCState = USBH_MSC_GET_MAX_LUN;
    2 C* }3 o0 \  O) t* U' M
  10. break;
    / J. f9 A+ Q# g( k
  11. case …
复制代码

) z' R& _* ~. H. U
& E  |5 L$ F' C4 e$ v, P2.还有些 U 盘在收到 Get_Max_Lun 命令返回 STALL,但是 U 盘主机就走不下去了。抓到的 tracer文件如图:9 \" H3 y# Q9 d7 S
, k, i! e7 \/ n
4G}{[[I}[CUV8FQLK5$C`0E.png
9 h! ~. B2 k/ u* b5 {+ {+ F4 ?0 G$ O/ H# O. I# b, C
经查阅,有些只包含唯一一个逻辑盘符的 U 盘可以对该命令回复数值 0 或者直接回复 STALL。那么对于 USB 主机来说,在收到了该条命令的 STALL 回复后就应该第一:认为该 U 盘仅包含一个逻辑盘符;第二:对 STALL 应答进行处理,然后继续下面的命令流程。通过 USB2.0 协议规范(章节 9.2.7),我们得知在控制传输(Control Transfer)过程中,当设备收到的命令自己不支持或者不适合设备当前的设置,就认为是命令出错。那么设备通过在接下来的数据阶段或者状态阶段回复 STALL 应答来告知主机这个错误。这种“协议 STALL”是控制传输特有的;这样 STALL 的状态,会在下一个控制传输(Setup 令牌)的到来而解除。我们看看 Window 对 U 盘这样的回复是怎么处理,tracer 文件抓图如下:主机通过 Clear Feature 命令,参数 EP_Halt(这是一个控制传输)来把设备方端点的 Halt feature 清除掉。
9 ?8 u! ]1 X1 k* T
8 y  k; O6 N( L! ` $J$PS0OF?R7K`835)B0WP.png
$ K# A+ y# e: V# q2 P+ D
6 W1 }3 ~) M& \1 X从代码里可以看到,例程是有做这方面的处理的:如果主机发送的 Get_Max_Lun 命令不被设备支持,则将 MSCState 状态设定成 CTRL_ERROR_STATE,发送 Clear Feature 的命令,以及随后的 Test_Unit_Ready 命令。
  Y2 x' S5 C1 A" a
  1. <usbh_msc_core.c>" V3 O, `# @6 M' [  [' i/ ^* P
  2. USBH_MSC_Handle()
    + [, W6 v( D; j5 ]. K2 n2 \  _% e
  3. {
    - M. I: T1 c% _7 w% Y" y9 T
  4. switch(USBH_MSC_BOTXferParam.MSCState)4 X! s' ]9 \6 u4 m7 G6 I# G. `
  5. {5 w& t4 \2 D9 h! t+ x
  6. case USBH_MSC_GET_MAX_LUN:
    ! x/ O8 B4 s' I# ~2 z6 {( X
  7. status = USBH_MSC_GETMaxLUN(pdev, phost);
    ' \# |2 M$ _$ Z" g
  8. if(status == USBH_OK )" `' X$ e: v: M. R8 @' C
  9. { ……,
    6 N9 ], x" Z) ?
  10. USBH_MSC_BOTXferParam.MSCState = USBH_MSC_TEST_UNIT_READY;4 f! r7 D* B1 w
  11. }; d' O  |% C% `% H5 {9 z( g1 L
  12. if(status == USBH_NOT_SUPPORTED )' C- I! h8 L8 Y& ?! S, G6 A& {
  13. { ……,9 ^4 h2 \/ i. \3 R! @
  14. USBH_MSC_BOTXferParam.MSCStateBkp = USBH_MSC_TEST_UNIT_READY;: [2 Q1 j% L2 K
  15. USBH_MSC_BOTXferParam.MSCState = USBH_MSC_CTRL_ERROR_STATE;}
    + J" E3 |% e, D& i5 Y& u
  16. break ;" O7 _7 I3 y% ^; n9 g  C- A
  17. case USBH_MSC_CTRL_ERROR_STATE:1 E0 g) x( ]* _6 S- e+ }+ Y
  18. USBH_ClrFeature(pdev, phost, 0x00, pphost->Control.hc_num_out);/ `1 i, A  j2 ~4 ^1 [9 _  ?7 d
  19. ……
    ( h1 W6 R& V1 O' w& k
  20. USBH_MSC_BOTXferParam.MSCState = USBH_MSC_BOTXferParam.MSCStateBkp;
    1 K  Q" g6 O" e  s" ]5 j
  21. ……
复制代码
4 @5 ?# z, f. ], F7 y( B
但是从抓到的 tracer 文件却看不到主机走到了发送 Test_Unit_Ready 的命令。经过调试、代码跟踪,终于定位在 USBH_HandleControl()中。对 CTRL_DATA_IN_WAIT 的处理,当收到URB_STALL 的应答后,没有给 phost 的 Control.state 赋值成 CTRL_STALLED!9 _% {& b3 y5 k; C% g9 }* m
" u/ }/ g/ v4 I, X9 {3 S
I7BKJAFSACS6T1PH]@HA@[K.png
* T! G- }3 X9 T, e7 N+ b3 F: d+ x: s. o1 W, Q2 f: A5 N
补上以上状态语句赋值后,主机 Host 在收到 Get_Max_Lun 命令返回的 STALL 后,可正常运行。
1 l' m2 y% a, b8 H9 h3 U3.还有一点需要注意的是:本版的 U 盘主机例程,暂时不支持多盘符 U 盘。
; r0 r% ?2 i9 @+ k# x$ m7 U# G. [$ B" `5 Z8 B2 X4 V8 }- i; n
赞 收藏 评论0 发布时间:2022-2-19 17:54

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版