UINT32?UVC_EP1_In(void?*p) { ????UINT8?nump?=?0; ????UINT8?numWait?=?0; ????UINT32?remaindNump?=?0;?????//最后一包數(shù)據(jù)的長度 ????static?UINT8?needTransfer?=?DEF_UVC_BURST_MAX;??//最大是4包數(shù)據(jù) ????nump?=?USB30_IN_Nump(ENDP_1);???????//讀出當前已經(jīng)發(fā)出的數(shù)據(jù)包 ????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;?//計算當前需要發(fā)送的數(shù)據(jù)包 ????} ????if?(Iso_Flag_PackHasVideo)??????//有有效數(shù)據(jù)包 ????{ ????????remaindNump?=?1024; ????????if?((DEF_UVC_BURST_MAX?==?numWait)?||?(needTransfer?==?numWait))????????//數(shù)據(jù)包接收完成 ????????{ ????????????nump?=?DEF_UVC_BURST_MAX; ????????????Iso_PackSeqNum?+=?DEF_UVC_BURST_MAX;?/*計算當前USB微幀的發(fā)送包數(shù)量*/ ????????????if?(Iso_PackSeqNum?>=?Iso_PackTotalNum)?????//全部數(shù)據(jù)包已經(jīng)發(fā)完,一般是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包數(shù)據(jù)沒有發(fā)完,則重新計算需要發(fā)送的包數(shù) ????????????{ ????????????????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);?//整包數(shù)據(jù)完成,發(fā)送NRDY ????????} ????????else ????????{ ????????????USB30_IN_Set(ENDP_1,?ENABLE,?ACK,?nump,?remaindNump); ????????????USB30_Send_ERDY(ENDP_1?|?IN,?nump); ????????} ????} ????return?0; } //該函數(shù)在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;???//計算包個數(shù) ????????Iso_LastPackLen?=?UVC_BufInfo.Length[idx]?&?0x3FF;??//計算最后一包數(shù)據(jù)的長度 ????????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; ????????} ????} }
可以在所有調(diào)用以下兩個函數(shù)的地方,在之前將包數(shù)量和長度打印出來監(jiān)控下,是否有意外的情況。
以及是否存在連續(xù)調(diào)用的情況,這是不被允許的。
或者調(diào)用之后,還沒有進入IN_Callback就意外調(diào)用IN_ClearIT,導(dǎo)致芯片狀態(tài)異常
其次,要注意數(shù)據(jù)本身是否復(fù)合相關(guān)協(xié)議對格式、收發(fā)數(shù)量和速度的要求,可能無法上傳是因為上位機主動停止了。
可以借助bus hound來看下是否有錯誤信息,可能可以根據(jù)bus hound顯示的信息在網(wǎng)上找到一些相關(guān)的信息。
測試該類問題的時候,應(yīng)當想辦法規(guī)避上位機問題,確保上位機一直在請求數(shù)據(jù),使用libusb直接加載該設(shè)備是比較合適的方法。
我這個是攝像頭設(shè)備,讀數(shù)據(jù)是從PC上直接打開攝像頭測試的,所以上位機應(yīng)該是沒問題。
在發(fā)送NRDY時包數(shù)和數(shù)據(jù)長度是0沒關(guān)系吧?其他的我再看看
攝像頭屬于UVC類,是比較復(fù)雜的class,數(shù)據(jù)流有一定的格式要求,存在時間戳、幀號等概念,都要保證不能出錯。
應(yīng)答狀態(tài)為NRDY時,包數(shù)量和長度不被關(guān)心。
需要注意當前端點配置,是被配置位同步傳輸端點還是批量傳輸端點:
void USB30_ISO_Setendp(UINT8 num,FunctionalState Status );
1、這個是我抓的log,程序連續(xù)運行到6406秒以后USB數(shù)據(jù)就沒有中斷觸發(fā)了,主機在請求RESET,在這以前沒有出現(xiàn)過重復(fù)調(diào)用IN_set、數(shù)據(jù)長度為0的情況。
2、IN_ClearIT只有在UVC_EP1_In函數(shù)中調(diào)用,這個是中斷的回調(diào)函數(shù),也只會在中斷觸發(fā)后運行。
3、初始化時沒有調(diào)用USB30_ISO_Setendp,這樣就是BULK傳輸端點了吧。而且在描述符里設(shè)置的也是BULK傳輸。
4、如果這個問題避免不了,有沒有什么接口可以自動恢復(fù)通訊?
根據(jù)USB3.0 SPEC,主機在某種情況下會出現(xiàn)放棄ERDY的情況,可以根據(jù)tERDYTimeout,超時后,通過重新發(fā)送ERDY來嘗試恢復(fù)通訊。
這個超時判斷和重發(fā)ERDY用什么接口呢?
可以自行設(shè)計,這個超時不是非常嚴格500毫秒。
1、我試了超時600ms重發(fā)ERDY,無法恢復(fù)通訊。然后試著在超時后加了RESET USB才能恢復(fù),這樣就類似于USB斷線重連,這樣實際使用中也不能這樣。是否有其他辦法呢?
2、我在用bushound抓數(shù)據(jù)時還發(fā)現(xiàn)偶爾數(shù)據(jù)會亂掉,但是很快自動就正常了,如下圖。出現(xiàn)USB無法發(fā)出數(shù)據(jù)和這個是否有關(guān)呢?
已解決
現(xiàn)在通訊中斷的問題解決了,但是還是會出現(xiàn)丟數(shù)據(jù)的情況,如25樓中貼出來的bushound抓到的數(shù)據(jù)。這個在部分PC上出現(xiàn)的概率更高。我通過測試(發(fā)送特定有規(guī)律的數(shù)據(jù)),出現(xiàn)這種情況是某次傳輸沒有將4k數(shù)據(jù)發(fā)完,這樣就造成數(shù)據(jù)錯亂。請問,這個要怎么規(guī)避
看截圖,似乎是多個長度460800byte的傳輸,怎么大數(shù)據(jù)量的傳輸多半還是代碼邏輯上的問題。重點監(jiān)控IN_CALLBACK進入次數(shù)吧