本文转自公众号系列文章,欢迎关注
基于DWC2的USB驱动开发-USB包详解 (qq.com)
https://www.elecfans.com/outside?redirect=https://mp.weixin.qq.com/s/gm5OAutfnYv6H_5Ce8GEqA一文中我们介绍了控制传输,中断相关寄存器,尤其是DOEPINTn.XferCompl,DOEPINTn.SetUp,DOEPINTn.StsPhseRcvd几个状态的组合非常重要,因为由他们可以确定当前控制传输处于什么阶段。前文我们对此进行了介绍,但是个人觉得讲的还不够透彻,原理还没有讲清楚,知其然知其所以然是我们一开始就强调的,所以针对这个几个标志位我们再次更详细的介绍,先来介绍最关键的DOEPINTn.SetUp。
Setup是DOEPINTn寄存器中的一个标志,用于表示Setup阶段是否完成。
我们这里可能要问DIEPINTn为什么没有SetUp标志,因为Setup总是HOST->DEV的,所以总是OUT传输,所以总是对应OUT端点的,IN端点的寄存器不可能有。这里强调一下我们一定要多问为什么,先思考猜测,然后再从手册规格书中查找答案,只有这样才能加深理解,USB开发中这是很重要的,当然任何技术性的工作这一点都重要。
我们从寄存器的描述中也可以看到,该位表示SetUP阶段完成,并且只有控制OUT端点有。
还有个信息是本次控制传输没有连续的SETUP,意味着软件可以开始解析SETUP的8字节的内容以决定下一步要干嘛了。如果有连续的SETUP则是最后一个SETUP完成才能进行。
那么究竟SETUP完成对应的一个什么状态呢? 硬件是怎么知道SETUP阶段完成的呢? 主机和设备判断SETUP完成有什么区别吗? 我们会抛出一连串问题,如果能抛出这些问题说明你很适合做底层和驱动开发!
后面我们会抽丝剥茧,从原理到实践,从猜测到手册中求证,一层层剖析。
这里我们要回顾下控制传输,
我们从规格书中的拓扑图可以看到,控制传输的SETUP阶段过程如下
或者换个表达方式如下
或者从USB分析仪抓包数据来看,更形象。
SETUP阶段对应3个包:SETUP令牌包;DATA0的数据包,始终是HOST->DEV;设备的响应ACK。
这里顺便提一下,SETUP的数据始终使用DATA0;而设备要么正常接收并接受ACK,要么接收错误或者没接收到不响应,只有这两种情况,不能接收了不接受而NAK或者STALL等。
这里还顺便提一下接收和接受的概念区别。接收通常指的物理层数据正确接收到了,而接受则指的软件能够处理,或者说愿意处理。 接收了也可能不接受。
这里协议层面我们可以看到SETUP阶段完成的标志是,设备ACK响应了。
如下所示
仔细思考下,这里只是协议上的定义,也就是对应的总线上的数据,至于SETUP完不完成是要由参与者HOST和DEV去确定的,换句话说总线上的状态并不意味参与者就是这个状态了,因为参与者还要正确接收到总线上的数据才算。
对于主机接收到了设备发送的ACK那么主机认为SETUP阶段完成,如果设备发了ACK但是主机没收到呢?那么主机认为SETUP没完成,会认为本次失败,从头发SETUP包重来。
同样的对于设备来说将ACK发送到总线上去后,设备并不知道HOST接收没接收到,设备并不知道主机的状态。所以主机和设备对SETUP完成的状态确认存在不同步。
那怎么办呢? 设备并不知道主机认为SETUP完成了没有,因为设备并不知道主机收没收到ACK。就好比子非鱼安知鱼之乐,有点绕了。
其实也没什么办法,设备确实现在不知道主机是不是认为SETUP完成了,但是设备可以根据主机下一步的行动来确定。因为主机如果接收到了ACK,认为SETUP完成了那么主机下一步就会发IN或者OUT令牌进入数据阶段(或者状态阶段),否则则会重发SETUP重新进入SETUP阶段。
设备可以据此来进行判断,如果收到了主机的IN或者OUT令牌,则确认主机认为SETUP已经完成了,于是设备也知道SETUP完成了,这里设备和主机判断SETUP完成的时间点是不一样的,这就是协议定义和实际判定存在的区别。所以对于协议设计一定要考虑这种区别,协议设计了要考虑如何实现,也就一直强调的理论要结合实践,对于驱动编写更需要考虑从这些细节。
以上恭喜你从头开始推导出了设备判断SETUP完成的原理,那么回到上面的标志位DOEPINTn.SetUp即表示SETUP阶段完成,DWC2控制也是这么判断的吗?所谓英雄所见略同,DWC2控制器还真是这么判断的。
上面寄存器的描述中只提了该标志的含义,并没提其具体置位的原理和时机,实际编程指导手册中是有说明的。
如下位置,手册就进行了说明当,SETUP令牌之后,接收到了IN或OUT令牌则置位DOEPINTn.SetU,和我们推导的完全一致。
为什么是IN或OUT呢,因为控制传输可能是控制写,控制读,还可能无数据阶段的控制传输,所以后面要不就是IN数据或者OUT数据或者IN状态,如下所示
控制写
控制读
无数据阶段的控制传输
从上面可以看到设备是延迟才能确认SETUP完成的,也就是在SETUP后设备收到了主机发的IN和OUT之后才确认,中断也是在此时产生。
对于控制写,上面设备确认SETUP完成产生中断,中断服务函数开始去解析8字节的SETUP内容,来确定数据阶段要干嘛,后面数据阶段是IN还是OUT或者还是没有数据阶段直接状态阶段,其实是数据阶段(状态阶段)已经启动,设备延迟了。
此时中断服务函数还未执行,软件还没根据解析准备IN或者OUT描述符,所以此时对于这个IN或者OUT,硬件只能自动NAK,如下所描述:
所以这种情况下,中断服务函数中进行了解析,并知道要准备OUT描述进行接收时,设置EPEna=1时还要同时设置CNAK=1,清除硬件的自动NAK状态,让硬件根据OUT描述符去接收数据。
对于控制读后面是IN数据阶段,或者无数据阶段的控制传输后面是IN状态,也是类似的。
以上对DOEPINTn.SetUp进行了详细的解析,因为它太重要了,SETUP阶段是控制传输的核心,因为只有SETUP完成才能去解析8字节的内容,才能决定后续干嘛,对于驱动编写接收到8字节的SETUP数据是第一个关键步。以上也可以看出一定要从原理上去理解,这也是驱动编写的重要原则,必须知其然知其所以然,精确的知道各个时间点的各个时间,以及其条件等,注意精确两个字。
审核编辑:汤梓红
全部0条评论
快来发表一下你的评论吧 !