CH569 USB3.0 BULK出现复位
UINT32 UVC_EP1_In(void *p)
{
    UINT8 nump = 0;
    UINT8 numWait = 0;
    UINT32 remaindNump = 0;     //最后一包数据的长度
    static UINT8 needTransfer = DEF_UVC_BURST_MAX;  //最大是4包数据

    nump = USB30_IN_Nump(ENDP_1);       //读出当前已经发出的数据包
    if (nump >= DEF_UVC_BURST_MAX)
    {
        printf("nump %d err\r\n", nump);
        numWait = 0;
        USB30_IN_ClearIT(ENDP_1);
        return 2;
    }
    else
    {
        numWait = DEF_UVC_BURST_MAX - nump; //计算当前需要发送的数据包
    }

    if (Iso_Flag_PackHasVideo)      //有有效数据包
    {
        remaindNump = 1024;

        if ((DEF_UVC_BURST_MAX == numWait) || (needTransfer == numWait))        //数据包接收完成
        {
            nump = DEF_UVC_BURST_MAX;
            Iso_PackSeqNum += DEF_UVC_BURST_MAX; /*计算当前USB微帧的发送包数量*/

            if (Iso_PackSeqNum >= Iso_PackTotalNum)     //全部数据包已经发完,一般是45K
            {
                UVC_BufInfo.isFull[isFullIndex] = 0;
                Iso_PackSeqNum = 0;
                Iso_Flag_PackHasVideo = 0;
                needTransfer = DEF_UVC_BURST_MAX;
                UVC_BufInfo.RemainCount--;
                isStop = 1;
            }
            else if (Iso_PackSeqNum + DEF_UVC_BURST_MAX >= Iso_PackTotalNum)
            {
                nump = Iso_PackTotalNum - Iso_PackSeqNum;
                remaindNump = Iso_LastPackLen;
            }

            if (Iso_PackSeqNum < Iso_PackTotalNum)
            {
                Iso_Tx_DataAddr += (DEF_UVC_BURST_MAX << 10); //地址每次递增4k
               
            }
            needTransfer = nump;
        }
        else
        {
            if (numWait < DEF_UVC_BURST_MAX)        //如果4包数据没有发完,则重新计算需要发送的包数
            {
                nump = DEF_UVC_BURST_MAX - numWait;
                needTransfer = nump;
            }
            else
            {
                nump = needTransfer;
            }
        }

        USBSS->UEP1_TX_DMA = Iso_Tx_DataAddr;
        USB30_IN_ClearIT(ENDP_1);
        if (isStop == 1)
        {
            USB30_IN_Set(ENDP_1, ENABLE, NRDY, 0, 0); //整包数据完成,发送NRDY
        }
        else
        {
            USB30_IN_Set(ENDP_1, ENABLE, ACK, nump, remaindNump);
            USB30_Send_ERDY(ENDP_1 | IN, nump);
        }
    }
    return 0;
}

//该函数在main中运行
void UVC_Start_transform(UINT8 idx)
{
    UINT32 packNum = DEF_UVC_BURST_MAX;
    UINT32 lastLen = 1024;

    if (isStop == 1)
    {
        Iso_Flag_PackHasVideo = 0x01;
        Iso_PackTotalNum = UVC_BufInfo.Length[idx] >> 10;   //计算包个数
        Iso_LastPackLen = UVC_BufInfo.Length[idx] & 0x3FF;  //计算最后一包数据的长度
        UVC_BufInfo.Length[idx] = 0;

        Iso_Tx_DataAddr = (UINT32)UVC_USBDMA_Addr[idx];     //切换地址

        if (Iso_LastPackLen)
        {
            Iso_PackTotalNum++;
        }
        else
        {
            Iso_LastPackLen = 1024;
        }

        if (Iso_PackTotalNum <= DEF_UVC_BURST_MAX)      //总共不足4包
        {
            packNum = Iso_PackTotalNum;
            lastLen = Iso_LastPackLen;
        }

        if ((packNum == 0) || (lastLen == 0))
        {
            printf("start err\r\n");
            isStop = 1;
            return;
        }

        HSPI_Signal_RxReady();      //拉GPIO

        isStop = 0;
        inEp1_IRQ = 0;
        USBSS->UEP1_TX_DMA = Iso_Tx_DataAddr;                //DMA地址偏移 需重重置
        USB30_IN_Set(ENDP_1, ENABLE, ACK, packNum, lastLen);
        USB30_Send_ERDY(ENDP_1 | IN, packNum);

        UVC_dotTick = UVC_dotTick / 2;
        if ((UVC_dotTick < 33) && (UVC_dotTick != 0))       //每帧图像间延迟
        {
            mDelaymS(33 - UVC_dotTick);
            UVC_dotTick = 0;
        }
    }
}



可以在所有调用以下两个函数的地方,在之前将包数量和长度打印出来监控下,是否有意外的情况。

以及是否存在连续调用的情况,这是不被允许的。

或者调用之后,还没有进入IN_Callback就意外调用IN_ClearIT,导致芯片状态异常

image.png

其次,要注意数据本身是否复合相关协议对格式、收发数量和速度的要求,可能无法上传是因为上位机主动停止了。

可以借助bus hound来看下是否有错误信息,可能可以根据bus hound显示的信息在网上找到一些相关的信息。

测试该类问题的时候,应当想办法规避上位机问题,确保上位机一直在请求数据,使用libusb直接加载该设备是比较合适的方法。


我这个是摄像头设备,读数据是从PC上直接打开摄像头测试的,所以上位机应该是没问题。


在发送NRDY时包数和数据长度是0没关系吧?其他的我再看看

image.png



摄像头属于UVC类,是比较复杂的class,数据流有一定的格式要求,存在时间戳、帧号等概念,都要保证不能出错。

应答状态为NRDY时,包数量和长度不被关心。
需要注意当前端点配置,是被配置位同步传输端点还是批量传输端点:

void USB30_ISO_Setendp(UINT8 num,FunctionalState Status );


image.png

1、这个是我抓的log,程序连续运行到6406秒以后USB数据就没有中断触发了,主机在请求RESET,在这以前没有出现过重复调用IN_set、数据长度为0的情况。

2、IN_ClearIT只有在UVC_EP1_In函数中调用,这个是中断的回调函数,也只会在中断触发后运行。

3、初始化时没有调USB30_ISO_Setendp,这样就是BULK传输端点了吧。而且在描述符里设置的也是BULK传输

4、如果这个问题避免不了,有没有什么接口可以自动恢复通讯?


根据USB3.0 SPEC,主机在某种情况下会出现放弃ERDY的情况,可以根据tERDYTimeout,超时后,通过重新发送ERDY来尝试恢复通讯。

image.png


这个超时判断和重发ERDY用什么接口呢?


可以自行设计,这个超时不是非常严格500毫秒。


1、我试了超时600ms重发ERDY,无法恢复通讯。然后试着在超时后加了RESET USB才能恢复,这样就类似于USB断线重连,这样实际使用中也不能这样。是否有其他办法呢?

2、我在用bushound抓数据时还发现偶尔数据会乱掉,但是很快自动就正常了,如下图。出现USB无法发出数据和这个是否有关呢?

image.png



已解决


现在通讯中断的问题解决了,但是还是会出现丢数据的情况,如25楼中贴出来的bushound抓到的数据。这个在部分PC上出现的概率更高。我通过测试(发送特定有规律的数据),出现这种情况是某次传输没有将4k数据发完,这样就造成数据错乱。请问,这个要怎么规避


看截图,似乎是多个长度460800byte的传输,怎么大数据量的传输多半还是代码逻辑上的问题。重点监控IN_CALLBACK进入次数吧


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