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

【经验分享】OTG主机库在不同传输类型上对NAK的处理

[复制链接]
STMCU小助手 发布时间:2022-2-11 18:28
问题:某客户使用 STM32F4 的 OTG 库做 USB 主机控制 Wifi 网卡。使用 BULK 传输类型时,从数据读取数据时,如果设备返回需要把设备返回的 NAK 状态告知上层应用,该如何修改 OTG 库。
( @  z& d; O7 P8 h* a) e调研:  w5 j1 f5 e+ f7 y
先来看看 OTG 库当前对 BULK 类型传输,IN 和 OUT 方向上的 NAK 的处理方式:
! U' F( y# P4 _. D, a% U- q
  1. @ BULK IN 通道
    ; F- F5 L1 R" H" ]7 R) D  @3 C
  2. If (nak)
    0 ~6 s7 ^0 v+ M# [9 Y& m, m
  3. 重新使能该通道: CHENA=1, CHDIS=09 S$ ?/ K' f; u  d
  4. 记录通道状态: Pdev->hostHC_Status[num] = HC_NAK
    % e! @% ?4 |2 x. ~! P: n# P
  5. 清零 NAK 位
    9 q- z! ~" h2 t
  6. 退出该中断处理程序(ISR)6 ]7 O& I$ R% ]' X5 ?7 q. Y" h, Q0 b
复制代码

: J* T* @5 k1 Y( [+ P) O3 B3 k' O. X* j
一旦重新使能该通道,主机硬件又自动发送 IN 令牌来企图从设备获取数据,直到设备准备好数据后,不再回复 NAK 握手,而是回复主机要获取的数据,然后主机硬件回复 ACK 来结束本次 transfer。
' [: |0 g& v! w0 _- l4 U/ YBULK IN 通道对 NAK 的处理和 CTRL IN 通道对 NAK 的处理,在 ISR 中是一样的;但是在驱动库里,对 CTRL IN 有超时限制,而对 BULK IN 没有。就是说对于常用来做枚举传输的 CTRL 传输,当启动从设备获取信息,但是久久未得的情况下,会走到 Timeout 的处理分支。从代码里我们可以看到
1 h8 ~$ D+ R" R+ E9 O- F9 V
  1. <usbh_core.c>& |' F. p- u% @) [5 n+ M
  2. USBH_HandleControl()0 {! m) l1 R# K
  3. {9 h2 A# L9 H% N3 d
  4. case CTRL_DATA_IN : 发出 IN 令牌' w& I% C  n, e# A1 T
  5. case CTRL_DATA_IN_WAIT :2 q7 i* C* d% A# N
  6. get_urb_state
    ! X+ n: @1 j) Y
  7. if (done)3 H; ]" Y2 A) x) W3 p# ]
  8. if (stall); N4 k: l8 r, \! \1 b7 L
  9. if (error)1 i3 d# X7 h, R0 a  C4 \+ B, d3 x
  10. if (超时) USBH Fail
复制代码
' z0 Q: g3 o1 X) _1 D

+ k. d" q+ ?3 L- b3 w但是 BULK IN 通道对 NAK 的接收没有超时控制,因为 BULK 传输本身的性质就是不保证带宽的,即如果主机上有很多其他优先级更高的周期类型的传输(同步 ISO 传输和中断 INT 传输),则在 BULK传输有可能无限延迟。; q! K+ m, h5 u8 h6 I4 M6 Z
CTRL IN 对 NAK 有超时处理,那么 CTRL OUT 对 NAK 是如何处理的呢?
) V+ E" c2 t$ O1 M" l. p) q从代码里可以看到 CTRL OUT 收到 NAK 后会把该状态上传 APP,如图! r; G3 o) ?. h
  1. @ CTRL OUT 通道
    ; w8 K4 X7 [. C4 t- U
  2. If (nak)
    / _( w9 S1 O! p0 `( z
  3. 打开通道 halt 中断: CHMM @ OTG_FS_HCINTMSK
    ; T0 O5 q5 q5 n; w/ m$ v5 ^
  4. Halt 该通道: CHENA=0, CHDIS=1# B% u; b; ~$ [' o* j: E9 c# C
  5. 记录通道状态:Pdev->hostHC_Status[num] = HC_NAK
    : }; I+ c$ O/ E+ O4 V0 N1 w
  6. 错误计数清零# `' w% l& N  n' k  z% y
  7. 清零 NAK 标志:@HCINTx
    6 {, R7 R& X$ @$ U7 K/ J
  8. 退出该中断处理程序(ISR),又进入通道 halt 中断
    . M" P9 k- V6 S8 \
  9. If (halt)
    # P9 n$ e* b* w' Z( I& r
  10. 关闭通道 halt 中断
    * Z3 ?3 U" n1 ~; Q
  11. 记录通道状态以上传 APP:Pdev->host.URB_State[num] = URB_NOTREADY
复制代码
然后在库代码处理控制传输时,如果检测到这个状态,就会重新发送 OUT 令牌和数据包,如图
" |8 g% ]+ n1 x8 R
  1. <usbh_core.c>
    6 C4 g2 l: J" E) M; x5 p
  2. USBH_HandleControl()
    ) N4 S! E& W6 t* k+ r. S
  3. {3 z: p% v& z( m' `5 x$ |" `
  4. case CTRL_DATA_OUT : 发出 OUT 令牌和数据包
    ' @; ~/ ?8 `& ]' ~! ^' n
  5. case CTRL_DATA_OUT_WAIT :! I& a6 |# O8 T4 u2 J! u& r
  6. get_urb_state1 }# w  K& b3 `- S# q1 V0 w
  7. if (done)- Z2 z" _0 k3 M  V# h
  8. if (stall)9 W/ c; b/ G( ~
  9. if (error)' I8 r% C: a# \+ ^  e" v" V
  10. if (URB_NOTREADY) 回到之前的 case CTRL_DATA_OUT
复制代码
' w% p# x* U/ i* R; G7 l$ Y
因此,当 CTRL IN 收到 NAK 后,如果想把状态上传给 App,则可以模仿 CTRL OUT 对 NAK 的处理。首先, ISR 中的处理可以模仿 CTRL OUT,在 BULK 传输的处理中,对每次发送 IN 令牌的地方(USBH_BulkReceiveData)查询传输状态,如果 URB_NOTREADY 就由 App 来决定如何处理。
0 O6 p( G9 t$ ?  b" _* `0 ]# Q! c5 r1 S$ @3 |% a* b
处理:
# |/ E* f1 I) r基于 U 盘读写的例程,在每次 USBH_BulkReceiveData 之后检查状态,如果是 URB_NOTREADY 就重新发送 IN 令牌。于是全项目搜索 USBH_BulkReceiveData,有三个地方,且都在USBH_HandleBOTXfer()中调用,即在 BOT 传输中若干次读数据阶段(多次数据包整数长度读取和最后一次的尾巴数据读取)和 CSW 阶段的读取,如图:3 [/ J; {$ i  [; \3 p) ]
  1. <usbh_core.c>
    % r4 F( x' R+ f( Z  ^5 \/ L, @6 L
  2. USBH_MSC_HandleBOTXfer()
    9 a) f. @/ U* `: K
  3. {) I1 x" g# B6 k: i. y
  4. case USBH_MSC_BOT_DATAIN_STATE:8 P1 H" L1 ]6 V: c/ ]$ `
  5. if (URB_DONE)6 }5 [( K  |% ?. R
  6. {& E2 k" ?; F; Y8 a: i( i
  7. if (剩余数据大于端点的 MPZ) USBH_BulkReceiveData(MPZ), _- e2 U7 X" H* n1 x$ ~
  8. if (剩余数据小于端点的 MPZ) USBH_BulkReceiveData(剩余数据量)
    , h9 _( Q1 u/ W' C* X+ ^
  9. }) F1 Q3 D6 t( c# {  T$ F
  10. case USBH_MSC_RECEIVE_CSW_STATE :
    & T) ?# j  |6 R. S
  11. USBH_BulkReceiveData(13)
复制代码
需要对每次 BULK IN 传输后检测状态,如果收到 NAK 则重新发起刚才的那次 BULK IN 传输,如图:
- k, R; J0 a" K. y+ Z
  1. <usbh_core.c>
    2 o' Y. O- k& S9 q% i0 D, `
  2. USBH_MSC_HandleBOTXfer()$ B2 C! H( G6 j3 |* X
  3. {$ L, |1 Y1 d+ e- s. Y
  4. case USBH_MSC_BOT_DATAIN_STATE:. o( O0 l; ?( }6 a' N: e: i
  5. if (URB_DONE)$ J+ M) X: a! j7 u4 z' m
  6. {6 Q! h4 C6 M% c$ D; z1 r4 a
  7. if (剩余数据大于端点的 MPZ) USBH_BulkReceiveData(MPZ)9 l; Z- Y# T$ V9 b& n
  8. if (剩余数据小于端点的 MPZ) USBH_BulkReceiveData(剩余数据量)
    4 a7 W$ C2 V- [. M4 v* i/ H
  9. }  d- A7 R. u+ i. n" V2 H: C
  10. If (URB_NOTREADY)
    ( ]" U7 X, D% K. V
  11. {重新发起刚才的 BULK IN 传输}
    ; m& ~7 e$ h* _3 ^  o: u& A
  12. case USBH_MSC_RECEIVE_CSW_STATE :
    . i3 h: L" H5 J" b4 k& h8 C$ Q
  13. USBH_BulkReceiveData(13)+ W6 x( C. x" v& v" ^3 V
  14. If (URB_NOTREADY)+ ^0 L) m9 t3 [: d2 I
  15. {重新发起刚才的 BULK IN 传输}
复制代码
经过以上修改,以 FS 和 HS 都能对 U 盘正确读取。
3 m# j$ r+ Y6 Z 修改后的固件代码,请参看附件压缩包。6 c6 J- \( N1 f2 K! Z0 h6 d: F

0 ~: w6 j, |9 c5 K, `7 G# X
$ K3 x9 H1 K! y8 E& \& E& F
赞 收藏 评论0 发布时间:2022-2-11 18:28

举报

0个回答

所属标签

相似技术帖

官网相关资源

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