再开一贴,USB卡死找到原因,求解决思路

原帖:

https://www.wch.cn/bbs/thread-113014-1.html


微软的RNDIS USB虚拟网卡协议和微软一样臃肿,用到4个端点,恨不得把device累死,nnd

1:SETUP 端点0  OUT 0x21 00 00 00 00 00 xx xx 发送数据到device,device通过SETUP 0xA1 01 ..... 返回到host

windows每隔 3秒 就会poll一次,交换一次数据,保持网络连接,就是这个3秒的保持连接造成的USB卡死,但真正原因是OUT3大批量数据占的时间过长,SETUP无法响应造成的


2:IN1中断传输,一有变化就需要发1次8byte消息,既然用到中断上传消息,为什么还用SETUP 发消息保持连接,多此一举,nnd,微软家有钱,就这样豪横,左手一个洛基亚,右手一个摩托罗拉,爱怎么玩就怎么玩


3:IN2 bulk传输,device数据加RNDIS头 批量上传到windows

4:OUT3 bulk传输,host网络数据加RNDIS头 批量下发到device


这样一套组合拳下来,device的OUT3最忙,频繁中断,有可能没有退出中断,Windows下发SETUP OUT 0x21 00 ...,得不到响应,造成USB卡死

以上原因只是猜测,因为测试过,如果OUT3只是copy数据,出错的机会大大减小,如果多加几行判断代码,出错机会增加。数据量小,基本不会出错,比如ping,ping几小时都正常


CH579的RB_UC_INT_BUSY初始化已加入,在中断期间中断标志未清除前自动返回NAK,搞不懂SETUP 0x21会暂停几秒钟,再怎么样OUT3中断里面也达不到秒级别,OUT3中断里面最多26ms,一般1.2ms左右


帮忙分析分析原因

有什么思路可以解决OUT3怎样和SETUP OUT冲突问题


 

您好,提供代码逻辑的修改建议。

根据https://www.wch.cn/bbs/thread-113014-1.html中提供的代码。

image.png

①如图修改点1,是针对控制传输的修改。

进了中断服务函数的端点0的OUTcase下,一般是表示主机在控制传输的数据阶段下发的数据,579成功收到了,接下来579根据情况判断是否需要在状态阶段中返回0长度包。

以主机下发指令为例:

控制传输的状态阶段,579回复0长度的包,表示控制传输的数据阶段,USB主机下发的数据,579可以识别处理,是代码可以正常运行的情况。

如果说控制传输的数据阶段,USB主机下发的指令数据,579识别不了或者找不到对应的处理代码,需要直接返回STALL包,而非回复0长度数据包。

②如图修改点2,针对批量传输数据量大的情况,可以做如下代码逻辑修改。

Ⅰ.快进快出中断服务函数,Ⅱ.创建软件队列,令牌包信息和待处理数据排列进队列,在主函数中处理数据。

在USB传输完成中断中,仅做memcpy和关键变量的拷贝,数据处理的代码不要放在中断服务函数中执行,快进快出,具体处理放在主函数中执行。主函数中用队列的方式,依次处理缓存队列,这样能避免中断服务函数的长时间占用。

您可以发送邮件到zhaiyw@wch.cn,给您提供CH571的做了队列处理的例程。


最终发现是IN无法上传造成的问题,不是OUT3频繁下发造成的

我最终没有用队列,基本解决了,还不完美, 不完美得地方:1小时内,偶尔会SUSPEND,但usb会立刻恢复正常,时间是ms级。不再堵塞

打算换ECM协议重新来过,放弃恶心的RNDIS


解决方法:

我后来仔细想了一下,即使OUT3超出1ms处理时间,但是USB核会自动NAK,host会暂停下发数据,按道理不应该OUT0会出问题,于是我打开了SOF,然后把串口打印调到1Mbps,呵呵,速度咱们得跟上  :)

在SOF里面打印一些消息,R8_USB_INT_ST=2A,R8_USB_INT_FG=12 频繁出现,01是SOF,2是端点2,端点2是IN Bulk,但很明显我的端点2使用很少,百思不得其解,为什么端点2会这么频繁,只要一卡死,SOF出现10,端点0出现,因此判断是端点2堵塞的,可是我怎么关IN2,都关不掉端点IN2,SOF里面一直频繁出现,万般无奈只能main loop面和进入OUT3立马关闭端点2IN, 端点2 OUT没有用到,顺带也关闭它 ,于是满世界就是下面这行代码:

R8_UEP2_CTRL = UEP_R_RES_NAK | UEP_T_RES_NAK

但SOF里面还是频繁出现12,让我百思不得其解, 除了OUT3上传0包,然后ARP,ping,udp回复host,我其他地方并没有类似下面ACK的代码

R8_UEP2_CTRL = UEP_R_RES_NAK | UEP_T_RES_ACK

即使上传后,在IN2中断里面也会关闭(见下),而且很少有数据IN2到host, 按道理SOF里面不太可能频繁出现12. 但事实就是这样, 知道原因了, 就是想办法规避IN2.  只要上传的地方就关闭IN2,只要SETUP关闭IN2,  "大面积"关闭IN2. 就这样好了.

不要问我为什么, 我也不知道, 也许天知道, 要说就是带bug的可以正常跑起来的程序...


初始化:
R8_UEP2_CTRL = UEP_R_RES_NAK | UEP_T_RES_NAK | RB_UEP_AUTO_TOG;	//NAK


中断:
//-----------------IN2 数据上传----------------------------------------
case UIS_TOKEN_IN | 2:	//端点2 In / RNDIS 64byte USB->PC
    R8_UEP2_T_LEN = 0;	
    R8_UEP2_CTRL = (R8_UEP2_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_NAK;	//默认应答NAK			
    usb_in_busy = 0;	//清除发送忙标志
break;
//--------------------end IN2-------------------------------------------





只有登录才能回复,可以选择微信账号登录