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

STM32 OTG主机库U盘应用中的NAK处理

[复制链接]
STMCU小助手 发布时间:2021-1-26 11:00
STM32 OTG主机库U盘应用中的NAK处理
2.1.jpg
   经常碰到有人在利用USB OTG做U盘的应用过程中遇到一些识别或读取问题。这里分享一篇STM32芯片的OTG模块做U盘应用过程中关于NAK处理的解析过程供参考。文章源于ST官方FAE技术应用文档,本文底部有网站地址介绍,可供原文及参考代码下载。
问题:
某客户使用STM32F4的OTG库做USB主机控制Wifi网卡。使用BULK传输时,从设备读取数据时,如果设备需要返回把设备返回的NAK状态告知上层应用,该如何修改OTG库。
调研:
先来看看OTG库当前对BULK类型传输,IN和OUT方向上的NAK的处理方式:
  1. @BULK IN 通道
    : c7 G8 \/ g6 e1 S6 x# w3 A% \
  2. 0 R* y' X) W1 w8 f- j, g6 r3 t
  3. If(nak)6 ~0 k) g' ~; G" x5 D. D" A
  4. 重新使能该通道: CHENA=1, CHDIS=0
    " I2 W0 x; c' ?5 b% m4 M
  5. 记录通道状态: Pdev->hostHC_Status[num]= HC_NAK
    , A  j  r- g1 ]5 C# H+ W
  6. 清零NAK位
    / z  m% Y4 C0 M& s
  7. 退出该中断处理程序(ISR)
复制代码
一旦重新使能该通道,主机硬件又自动发送IN令牌企图从设备获取数据,直到设备准备好数据不再回复NAK,而回复主机要获取的数据,然后主机硬件回复ACK结束本次transfer。
BULK IN通道对NAK的处理和CTRLIN通道对NAK的处理,在ISR中是一样的;但是在驱动库里,对CTRL IN有超时限制,而对BULK IN没有。就是说对于常用来做枚举传输的CTRL传输,当启动从设备获取信息,但是久久未得的情况下,会走到Timeout的处理分支。从代码里我们可以看到:
  1. <usbh_core.c>
    * M9 `9 G( p6 H0 |
  2. USBH_HandleControl()
    0 p, j( L: C3 ~/ ~- t' C1 U
  3. {0 \6 {" m6 \9 `5 k! m" d. D: J& l9 N
  4. case CTRL_DATA_IN : 发出IN令牌
    & @) Q2 O" W7 y7 P0 j
  5. caseCTRL_DATA_IN_WAIT :get_urb_state
    9 E& C; ?1 l& N5 ?0 `( z  y- |
  6. if(done)* q' a; l% E! K& C& m  y
  7. if(stall)% @4 q3 i- o$ ?- E- o
  8. if(error)
    * x+ z4 ~. [8 X3 C0 A
  9. if (超时) USBH Fail .......
复制代码
1 Z' t/ E% F6 p( ]
但是BULK IN通道对NAK的接收没有超时控制,因为BULK传输本身的性质就是不保证带宽的,即如果主机上有很多其他优先级更高的周期类型的传输(同步ISO传输和中断INT传输),则在BULK传输有可能无限延迟。
CTRL IN对NAK有超时处理,那么CTRL OUT对NAK是如何处理的呢?
从代码里可以看到CTRL OUT收到NAK后会把该状态上传APP。
  1. @CTRL OUT 通道
    ' ^; m1 S) H* I
  2. If(nak)
    & d+ Z! v% T- i5 g8 j
  3. 打开通道halt中断: CHMM @ OTG_FS_HCINTMSK
    8 P9 H- l( d( @8 I* Z
  4. Halt该通道: CHENA=0,CHDIS=17 j4 _1 y7 l% _; j. |
  5. 记录通道状态:Pdev->hostHC_Status[num] = HC_NAK
    ' N6 J8 _  Q2 }! E' j
  6. 错误计数清零& D' D, K$ _* I; e8 [
  7. 清零NAK标志:@HCINTx
    " O/ {: I% ^- w" [5 Z
  8. 退出该中断处理程序(ISR),又进入通道halt中断1 }! G' R3 L  _: p
  9. If(halt)
    . X, _! W6 F8 |- o4 z: p
  10. 关闭通道halt中断2 p: v& T+ L* E; v. I* A. T
  11. 记录通道状态以上传APP:Pdev->host.URB_State[num]= URB_NOTREADY
复制代码
. r8 b0 ~# w; L: W4 ?
然后在库代码处理控制传输时,如果检测到这个状态,就会重新发送OUT令牌和数据包。
  1. <usbh_core.c>
    : b& M" m2 W9 a# y$ ]5 k* K2 F
  2. USBH_HandleControl()
    - j# |0 G! Y' j
  3. {
    9 w  \" a) U* a7 q" L0 T
  4. case CTRL_DATA_OUT : 发出OUT令牌和数据包
    : _  v4 Q6 _8 l5 J6 D
  5. caseCTRL_DATA_OUT_WAIT :
    ; v3 i6 j# t3 h* T3 U
  6. get_urb_state
    7 V' X0 v0 Q/ E* p9 z+ W
  7. if(done)
    1 Q: a4 H' Q8 ]
  8. if(stall)! h" y6 u' m9 P, e  ?$ F
  9. if(error)/ d. m3 T2 s, R& a8 l! D4 C
  10. if (URB_NOTREADY)回到之前的case CTRL_DATA_OUT
复制代码

$ X/ H7 T4 g5 z
因此,当CTRL IN收到NAK后,如果想把状态上传给App,则可以模仿CTRL OUT对NAK的处理。首先, ISR中的处理可以模仿CTRL OUT,在BULK传输的处理中,对每次发送IN令牌的地方(USBH_BulkReceiveData)查询传输状态,如果URB_NOTREADY就由App来决定如何处理。
处理:
基于U盘读写的例程,在每次USBH_BulkReceiveData之后检查状态,如果是URB_NOTREADY就重新发送IN令牌。全项目USBH_BulkReceiveData有三个地方,且都在USBH_HandleBOTXfer()中调用,即在BOT传输中若干次读数据阶段(多次数据包整数长度读取和最后一次的尾巴数据读取)和CSW阶段的读取。
  1. <usbh_core.c>: m$ Z& E; n7 \- |) ^
  2. USBH_MSC_HandleBOTXfer()
    0 k3 ^* O( Y" W2 u, `
  3. {
    0 s4 i1 s0 J" f
  4. caseUSBH_MSC_BOT_DATAIN_STATE:  d& L3 K' d* P: A* w4 R8 S
  5. if (URB_DONE)8 U0 R! T+ N! ^3 w
  6. {
    0 ^+ V- Z7 i1 o. G9 a
  7. if (剩余数据大于端点的MPZ)USBH_BulkReceiveData(MPZ)
    ; I* k- h% S3 T% ^$ q6 |
  8. if(剩余数据小于端点的MPZ) USBH_BulkReceiveData(剩余数据量)
    ' i4 z$ ~! Q3 m- h( V; J
  9. }& z$ a# V/ s0 ^0 @
  10. caseUSBH_MSC_RECEIVE_CSW_STATE :0 S0 r/ D& k  V2 @# P- g
  11. USBH_BulkReceiveData(13)
复制代码
" K$ L& f6 A; p$ l; A& H# o
需要对每次BULK IN传输后检测状态,如果收到NAK则重新发起刚才的那次BULK IN传输:
  1. <usbh_core.c>
    - q2 y2 m6 Y+ Z
  2. USBH_MSC_HandleBOTXfer()
    9 `, K: I% \0 X! C
  3. {
    6 e# F3 a- `& k3 M7 j: b1 h
  4. caseUSBH_MSC_BOT_DATAIN_STATE:3 ?' E/ W6 b, T: J
  5. if (URB_DONE)
      @$ e% r% z/ K' _
  6. {
    - N, }8 w  z4 {7 H' f  J
  7. if (剩余数据大于端点的MPZ)USBH_BulkReceiveData(MPZ)
    3 v7 E4 M% r8 W
  8. if(剩余数据小于端点的MPZ) USBH_BulkReceiveData(剩余数据量)
    . m' ?  S$ k( D* F+ {, m
  9. }
    " f7 _. T# ?! \3 ?1 `7 |2 q! S
  10. If(URB_NOTREADY)) M( _6 M6 `( N4 }
  11. {重新发起刚才的BULKIN传输}
    + ^- D+ O. B' T) |9 [+ U" Z3 U9 w
  12. caseUSBH_MSC_RECEIVE_CSW_STATE :
    8 B2 Q2 V% L5 s) X& b) ]: s
  13. USBH_BulkReceiveData(13): G( \6 ]) D1 b& E! G; F
  14. If(URB_NOTREADY)2 m8 u, L* V; d7 K0 B
  15. {重新发起刚才的BULK IN传输}
复制代码

: v8 Q' p$ n: y2 U, J0 f  R% W8 O! z
经过以上修改,以FS和HS都能对U盘正确读取。
修改后的参考固件代码,请去WWW.STMCU.COM.CN官网实战经验处下载。
2.2.jpg
文章出处: 茶话MCU

! Z' ?; S8 |7 K6 G
赞 收藏 评论0 发布时间:2021-1-26 11:00

举报

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