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

【经验分享】OTG 主机库在 BULK 传输上对 NAK 的处理

[复制链接]
STMCU小助手 发布时间:2022-2-19 18:10
问题:5 g$ O6 K7 A/ f" O5 s
某客户使用 STM32F4 的 OTG 库做 USB 主机控制 Wifi 网卡。使用 BULK 传输类型时,从数据读取数据时,如果设备返回需要把设备返回的 NAK 状态告知上层应用,该如何修改 OTG 库。; @6 ~6 \3 p0 ~8 L
调研:3 t2 r9 B: `4 [. H! F
先来看看 OTG 库当前对 BULK 类型传输,IN 和 OUT 方向上的 NAK 的处理方式:* n  a- E7 w5 F3 y& \3 _8 f
  1. @ BULK IN 通道
    + _  S; E' \2 A. Y
  2. If (nak)
    : B& r. K. b5 _8 ]# U
  3. 重新使能该通道: CHENA=1, CHDIS=0
    " ~2 T  g$ z) |2 I3 O; j8 l  F+ @
  4. 记录通道状态: Pdev->hostHC_Status[num] = HC_NAK
    % r8 k1 R0 K- s. o* {7 \
  5. 清零 NAK 位4 T' M# {/ c, w% g( Y6 s' c
  6. 退出该中断处理程序(ISR)
复制代码

5 g7 x  o) R+ S# ^: c* v' W
2 R' k3 `+ E( V9 Q& P一旦重新使能该通道,主机硬件又自动发送 IN 令牌来企图从设备获取数据,直到设备准备好数据后,不再回复 NAK 握手,而是回复主机要获取的数据,然后主机硬件回复 ACK 来结束本次 transfer。
* c' i* o! \& }& q! m8 @) O  O( [, d0 d3 r6 k. w
BULK IN 通道对 NAK 的处理和 CTRL IN 通道对 NAK 的处理,在 ISR 中是一样的;但是在驱动库里,对 CTRL IN 有超时限制,而对 BULK IN 没有。
就是说对于常用来做枚举传输的 CTRL 传输,当启动从设备获取信息,但是久久未得的情况下,会走到 Timeout 的处理分支。从代码里我们可以看到, C$ H6 X4 [/ s' t
  1. <usbh_core.c>& k$ {: \4 w/ b7 m: h5 y3 ~
  2. USBH_HandleControl()3 x4 L8 B& _; B( C+ D" C6 p
  3. {+ R# Q1 a7 `  U0 u5 H. l
  4. case CTRL_DATA_IN : 发出 IN 令牌7 x" Y' b: D5 i. ?" B- y8 q
  5. case CTRL_DATA_IN_WAIT :7 h4 Z4 R: ]2 S/ i4 o9 J# c
  6. get_urb_state
    % p8 i1 W8 R. g# V" Q" |$ K
  7. if (done)
    9 Z3 O8 @2 F9 I, D" _* d
  8. if (stall)
    2 i# e) ]4 K/ B% O/ I
  9. if (error)9 r1 \1 O) f. _/ V+ Z& G2 ~% [, ~
  10. if (超时) USBH Fail
复制代码

  i) V9 ?8 a0 [7 `0 Z  s% `& P! @9 @' Y8 A- _. w2 ^' V0 |$ o/ x
但是 BULK IN 通道对 NAK 的接收没有超时控制,因为 BULK 传输本身的性质就是不保证带宽的,即如果主机上有很多其他优先级更高的周期类型的传输(同步 ISO 传输和中断 INT 传输),则在 BULK传输有可能无限延迟。
! V9 F. |: C, ?* n
3 Q+ }1 g/ f. G! o& H- M, O% l& o' V" C" H/ j. \
CTRL IN 对 NAK 有超时处理,那么 CTRL OUT 对 NAK 是如何处理的呢?/ W! B  g+ N7 V2 b; ^3 q' T4 B
从代码里可以看到 CTRL OUT 收到 NAK 后会把该状态上传 APP,如图. ^# N6 Q- R/ L: u( R  _- z
  1. @ CTRL OUT 通道% p+ }4 |' M$ H, x( U. }
  2. If (nak)
    & \2 u* g" W$ r% B3 O, L
  3. 打开通道 halt 中断: CHMM @ OTG_FS_HCINTMSK% d6 F0 M* |2 s6 u6 e9 C
  4. Halt 该通道: CHENA=0, CHDIS=1
      W0 `. \# d' j6 A
  5. 记录通道状态:Pdev->hostHC_Status[num] = HC_NAK+ O" i* a! e+ m
  6. 错误计数清零" |8 W- L1 ^* U0 S/ |+ W
  7. 清零 NAK 标志:@HCINTx
    , n' ]0 ?: P3 O9 X
  8. 退出该中断处理程序(ISR),又进入通道 halt 中断
      Q! k' W" @( F0 M' Y" Z( j
  9. If (halt). ]+ y3 y( a3 C# \; ~
  10. 关闭通道 halt 中断
    $ w7 X) Y+ i5 q4 M( b# q% `5 t
  11. 记录通道状态以上传 APP:Pdev->host.URB_State[num] = URB_NOTREADY
复制代码
然后在库代码处理控制传输时,如果检测到这个状态,就会重新发送 OUT 令牌和数据包,如图
# ]. C' B3 s3 K5 c4 p. ^
  1. <usbh_core.c>
    8 j  m3 d! [: d
  2. USBH_HandleControl()
    + ^/ k. k# Q" a+ [  b+ w: a) d
  3. {
    8 X. F. C1 O7 Z( A- i! _/ F: {; w
  4. case CTRL_DATA_OUT : 发出 OUT 令牌和数据包
    3 h  a) X/ Y' \" E$ z  E, B, j
  5. case CTRL_DATA_OUT_WAIT :: @" Z9 t4 l6 F& D) ?
  6. get_urb_state" s, G1 @' b+ V7 C$ H9 R( F3 X
  7. if (done)4 B+ B( p. T- ~" l3 `* C
  8. if (stall)
    / m; R/ Y% c6 X( I) H
  9. if (error): M+ L- T! ?6 X6 Z; a  `8 k0 _
  10. if (URB_NOTREADY) 回到之前的 case CTRL_DATA_OUT
复制代码
# F$ _" e3 I, R* i' A

7 n# F5 |; {7 \/ h5 Z因此,当 CTRL IN 收到 NAK 后,如果想把状态上传给 App,则可以模仿 CTRL OUT 对 NAK 的处理。首先, ISR 中的处理可以模仿 CTRL OUT,在 BULK 传输的处理中,对每次发送 IN 令牌的地方(USBH_BulkReceiveData)查询传输状态,如果 URB_NOTREADY 就由 App 来决定如何处理。5 _6 ]; j/ Q+ y7 m$ e, m  o! l- V: |

8 c  g/ T4 N+ B9 O+ \处理:
7 @& d  ~( p' n基于 U 盘读写的例程,在每次 USBH_BulkReceiveData 之后检查状态,如果是 URB_NOTREADY 就重新发送 IN 令牌。于是全项目搜索 USBH_BulkReceiveData,有三个地方,且都在USBH_HandleBOTXfer()中调用,即在 BOT 传输中若干次读数据阶段(多次数据包整数长度读取和最后一次的尾巴数据读取)和 CSW 阶段的读取,如图:
- E* S! [4 C/ b8 I' z9 `0 y. b
  1. <usbh_core.c>0 N& X9 m9 S9 w. ?. r
  2. USBH_MSC_HandleBOTXfer()
    ! d' _3 s  h7 |/ j
  3. {
    9 l4 `. _! _8 d* I/ Q* X. J" V3 ?
  4. case USBH_MSC_BOT_DATAIN_STATE:
    4 Z$ ^0 }4 r9 j) k/ c
  5. if (URB_DONE)  |$ V7 u) S( P' z, F" D
  6. {3 ^) A4 }* V! a* u, E! Z/ ]
  7. if (剩余数据大于端点的 MPZ) USBH_BulkReceiveData(MPZ)
    ! q' W# T. p0 s& M) Y
  8. if (剩余数据小于端点的 MPZ) USBH_BulkReceiveData(剩余数据量)
    3 J9 x2 b# W) X% L3 f" I( e
  9. }
    ) n' r% r; s% n; J- F$ S7 f
  10. case USBH_MSC_RECEIVE_CSW_STATE :
    2 V5 A% s9 x: Z* y: o6 J* u
  11. USBH_BulkReceiveData(13)
复制代码

8 L3 I/ {" p! w; J$ z( ^; g0 A7 K& Z& W# I9 W4 h3 q
需要对每次 BULK IN 传输后检测状态,如果收到 NAK 则重新发起刚才的那次 BULK IN 传输,如图:
' o2 ?# O4 L: a" }8 d+ G
  1. <usbh_core.c>
    * b3 `* c! @+ Y' m5 h+ a
  2. USBH_MSC_HandleBOTXfer()
    * J0 `0 V8 R, D* V& P
  3. {' c' @- e" C9 ~; [- x/ V+ ]: K
  4. case USBH_MSC_BOT_DATAIN_STATE:9 ]: Y, }" n9 ]/ t& a
  5. if (URB_DONE)
    ' M) p5 ^6 O' |; t1 p6 l. a
  6. {+ T' f# O, R$ z% F
  7. if (剩余数据大于端点的 MPZ) USBH_BulkReceiveData(MPZ)
    # V- Q5 b8 \* E4 [4 g2 E
  8. if (剩余数据小于端点的 MPZ) USBH_BulkReceiveData(剩余数据量)0 G; ?5 c& j  j' Q* R3 u3 s
  9. }# @5 A% W# o' \
  10. If (URB_NOTREADY)# r. @) r- E. n" x7 x9 h. Z# }
  11. {重新发起刚才的 BULK IN 传输}) G9 h% N. l+ y3 n1 Y# L
  12. case USBH_MSC_RECEIVE_CSW_STATE :0 d5 Y, A0 W8 y/ p+ X$ g
  13. USBH_BulkReceiveData(13)
    0 R- b$ S8 o+ b2 J8 y7 f/ N0 m
  14. If (URB_NOTREADY); t: P# |# ^) J
  15. {重新发起刚才的 BULK IN 传输}
复制代码

4 V$ {1 m; d- h7 B6 D经过以上修改,以 FS 和 HS 都能对 U 盘正确读取。  n, P. I6 m2 p3 y) c1 A+ K! X
修改后的固件代码,请参看附件压缩包。
2 I; B; P) ^4 G6 o$ P1 a. l: t% i
赞 收藏 评论0 发布时间:2022-2-19 18:10

举报

0个回答

所属标签

相似技术帖

官网相关资源

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