我对PDIUSBD12、at91rm9200-usb的IN、OUT事务的硬件角度理解(gliethttp)
文章来源:http://gliethttp.cublog.cn[转载请声明出处]
<1>对于PDIUSBD12,对于OUT事务,只有当pc驱动程序把此次数据通过管道全部发送到usb设备端点 --PDIUSBD12的0或2的数据缓冲区和ACK之后,PDIUSBD12才会产生中断,通知cpu,处理接收到的OUT事务数据, 而不是在PDIUSBD12收到OUT令牌后就立即中断cpu,PDIUSBD12会等到OUT令牌之后的数据阶段 (也可能需要等到ACK握手阶段完成之后[gliethttp])完成之后,才触发中断通知cpu处理PDIUSBD12接收到的 数据缓冲区中的数据; 对于控制端点0、端点1和端点2的IN事务,只要IN令牌一收到,PDIUSBD12就会立即触发中断, 0xF4中断状态寄存器的bit1-控制输入端点状态位-置位, 以示cpu这次中断由于控制端点IN令牌包的收到而发生的, 固件驱动组织数据,之后发送给host主机.(gliethttp) 这样就比较麻烦,因为当固件驱动处理数据的时候,PDIUSBD12将主动返回NAK给host主机,host主机收到NAK 之后,会按固定时间间隔定时的发送IN事务令牌包,如果不将cpu的整个中断系统停掉的话,至少不把 PDIUSBD12的第14脚INT_N连接的cpu中断禁止的话,就会以很高的频繁对cpu进行INT_N中断, 当然也可以不使用中断,而是不停检测PDIUSBD12的第14脚INT_N是否为0. <2>对于at91rm9200来说,只有如下几种情况才会引发中断: (1.RXSETUP:当前端点收到了setup令牌包触发中断 (2.RX_DATA_BK0:当前端点收到了数据包并且已经安全放到了FIFO段0触发中断 (3.RX_DATA_BK1:当前端点收到了数据包并且已经安全放到了FIFO段1触发中断 (4.TXCOMP:当前端点上发的数据已经被host主机通过IN事务读取,同时PID_ACK也正常收到,触发TXCOMP中断 (5.STALLSENT:当前端点被挂起禁用触发中断 所以对于at91rm9200第1次收到"读取设备描述符"setup事务指令之后会引发cpu中断,在中断里边 usbEp0.DisptachSetup = AT91F_USB_DispatchRequest;回调函数中,得知是STD_GET_DESCRIPTOR-标准获取设备描述符, 固件驱动会立即把"设备描述符"送入控制端点的IN缓冲区,这个时候host主机可能还正在处理其他事情,没有时间来处理, 不怕,放到IN缓冲区中的数据at91rm9200的usb控制器不会在host主机没有发送PID_IN令牌之前,就把数据主动送到总线 上丢失掉,而是等待host主机对当前端点发送PID_IN令牌的时候,老早之前放到IN缓冲区的数据才会传输出去, 另外的那种情况就是,host主机速度快的惊人,刚刚发送完"读取设备描述符"setup事务指令,就立即又发送了PID_IN令牌, 这时at91rm9200的usb控制器还没有把"设备描述符"完全送到IN缓冲区,此时at91rm9200的usb控制器会自动向host主机 发送PID_NAK,作为PID_IN的握手回应.经过几次PID_NAK并且在没有超过50ms的前提下,at91rm9200固件驱动已经把数据放 到了IN缓冲区,并且使IN缓冲区生效,那么host定时再次发送过来的PID_IN令牌将能正常收到PID_DATA令牌下的数据了. 这种方式比较好,在OUT事务中,固件驱动得知是否有上传数据,然后直接在OUT中断中,把上传数据送到IN数据缓冲区, 当host正常读取IN缓冲区的数据之后,会触发IN中断,在IN中断中,固件驱动再去检查IN数据是否发送完毕,如果没有就 继续发送下去,这就好像"钟摆小球试验",当你轻轻给它一个"外力"--OUT事物中激活IN,之后,"小球"--IN事物中断,就开始 永远的"摆动"起来--IN事物中断,又有点类似自激震荡(gliethttp). <3>usb通信时,每一次数据的传送都严格遵守3个阶段 [1]令牌PID阶段 [2]数据PID阶段 [3]握手PID阶段
PID域 ----------------------- 令牌有4种: PID_setup令牌--PID域值0xB4,用来标示数据阶段的数据为setup事务数据 PID_out令牌 --PID域值0x87,用来标示数据阶段的数据为out事务数据 PID_in令牌 --PID域值0x96,用来标示数据阶段的数据为in事务数据 PID_sof令牌 --PID域值0xA5,用来标示帧标号开始 ----------------------- 数据阶段: PID_DATA0数据--PID域值0xC3,用来标示此数据为PID偶分组数据 PID_DATA1数据--PID域值0xD2,用来标示此数据为PID奇分组数据 ----------------------- 握手阶段有3种: PID_ACK --PID域值0x4B,用来标示usb接收器硬件收到无误的数据分组 PID_NAK --PID域值0x5A,用来标示接收端不能接收数据(可能正在处理上一次接收到的数据) 或者发送端不能发送数据(固件驱动程序正在把IN数据放到管道端点缓冲区中) PID_STALL --PID域值0x78,用来标示当前端点被禁用了.(gliethttp) <4>一个usb设备只能有1个设备描述符,可以有多个配置描述符, 每个配置描述符可以有多个接口描述符,每个接口描述符可以管理多个端点.
|