如何使用STM32的USB非控制端點(diǎn)發(fā)送多個(gè)數據包

發(fā)布時(shí)間:2009-11-25 18:06    發(fā)布者:STM32
關(guān)鍵詞: USB , 端點(diǎn) , 數據
以下是網(wǎng)友提出的問(wèn)題和我對這個(gè)問(wèn)題的說(shuō)明。

SMT32F103,根據例程Custom_HID修改,利用EP1 以EP_INTERRUPT 的方式發(fā)送包,原來(lái)的例程每次發(fā)送2個(gè)字節,現在修改后包的長(cháng)度不超過(guò)64字節時(shí)發(fā)送是正常的,但當一個(gè)包長(cháng)超過(guò)64字節時(shí)就發(fā)送失敗,沒(méi)有數據出來(lái)(程序沒(méi)有死機),該改的地方都已經(jīng)修改了,不知道哪個(gè)地方還沒(méi)有改到位,謝謝!

現象就是 超過(guò)63字節的包死活也發(fā)不出去,而且發(fā)送包的大小 還與 CustomHID_ConfigDescriptor里面的 EP1 IN endpoint 描述里包大小有關(guān) ,沒(méi)道理啊,其他的MCU 這地方設置為8 照樣發(fā)送256B 以上的包。

在Custom_HID例程上修改了如下代碼:
1.usb_proc.c 的CustomHID_Reset()里  SetEPTxCount(ENDP1, 64);
2.關(guān)閉 DMA中斷,不讓ADC采樣后發(fā)送EP1包
3.在main.c里 重復發(fā)送一個(gè)128B的包,
   while(1){
    for(i=0;i<2;i++)
       { SetEPTxAddr(ENDP1, ENDP1_TXADDR+i*64);
      SetEPTxValid(ENDP1);   
       Delay(10000);      
        }
     }      
4. 由于一個(gè)包是128B,最大包長(cháng)是64B,所以分兩次發(fā)送出來(lái),奇怪的是所有例程發(fā)送包時(shí)都沒(méi)有查發(fā)送狀態(tài)的處理,也沒(méi)有找到相應的狀態(tài)等待函數,這樣的話(huà),是不是出現第一個(gè)包還沒(méi)有發(fā)送完,第二個(gè)包就沖掉了第一個(gè)包的數據?
5. 所以問(wèn)題很簡(jiǎn)單,就是如何發(fā)送一個(gè)多數據包,發(fā)送函數要如何寫(xiě)?

以下是關(guān)于這個(gè)問(wèn)題的解答:
分兩次發(fā)送是對的,但關(guān)鍵是每次發(fā)送前需要檢查上次發(fā)送是否完成。

檢查一個(gè)端點(diǎn)的發(fā)送是否結束有2種方法,第一種方法是當發(fā)送結束(設備收到ACK)時(shí),有一個(gè)發(fā)送結束中斷,這個(gè)中斷由USB庫處理,并通過(guò)EP1_IN_Callback這個(gè)回調函數交由用戶(hù)程序確認,你可以搜索一下,例子中把EP1_IN_Callback定義為NOP_Process,沒(méi)有處理這個(gè)回調事件。如果要用這種方法檢測端點(diǎn)發(fā)送結束,你需要自己定義回調函數并做相應處理。

檢測端點(diǎn)發(fā)送結束的另一個(gè)方法是查詢(xún)這個(gè)端點(diǎn)的狀態(tài),如果端點(diǎn)狀態(tài)處于EP_TX_VALID,說(shuō)明發(fā)送未結束,如果端點(diǎn)狀態(tài)處于EP_TX_NAK,說(shuō)明發(fā)送結束。使用下述調用可以得到端點(diǎn)1的發(fā)送狀態(tài):
   GetEPTxStatus(ENDP1)

按照你的思路,可以使用第二種方法實(shí)現發(fā)送多個(gè)數據包的功能。

假定要發(fā)送150個(gè)字節的MyBuffer,EP1的最大包長(cháng)設為64字節。

u8 MyBuffer[150];
int packetN;
packetN = 3;
while (1) {
   if (packetN < 3) { // 有數據需要發(fā)送時(shí)置packetN為'0'
     if (GetEPTxStatus(ENDP1) == EP_TX_NAK) {
       if (packetN == 0) { // 拷貝頭64字節到發(fā)送緩沖區
         UserToPMABufferCopy(MyBuffer, ENDP1_TXADDR, 64);
         SetEPTxCount(ENDP1, 64);
       }
       else if (packetN == 1) { // 拷貝第2個(gè)64字節到發(fā)送緩沖區
         UserToPMABufferCopy(MyBuffer+64, ENDP1_TXADDR, 64);
         SetEPTxCount(ENDP1, 64);
       }
       else if (packetN == 2) { // 拷貝最后22字節到發(fā)送緩沖區
         UserToPMABufferCopy(MyBuffer+128, ENDP1_TXADDR, 22);
         SetEPTxCount(ENDP1, 22);
       }
       packetN++;
       SetEPTxStatus(ENDP1, EP_TX_VALID);
     }
   }
   ...... // 其它操作
}

這里使用了一個(gè)變量記錄應該發(fā)送第幾個(gè)數據包,當程序的其它部分準備好數據后只要設置這個(gè)變量packetN=0,上述發(fā)送操作就會(huì )啟動(dòng),程序的其它部分只需檢測packetN==3即可知道MyBuffer是否已經(jīng)騰空,程序的其它部分可以使用MyBuffer繼續其它操作,注意這時(shí)數據不一定已經(jīng)全部發(fā)送完畢。

你的另一個(gè)問(wèn)題在于這一行:SetEPTxAddr(ENDP1, ENDP1_TXADDR+i*64);

ENDP1_TXADDR是專(zhuān)門(mén)的發(fā)送緩沖區,它的長(cháng)度是有限的,而且是每32位編址中只有低16位有效;所以需要使用函數UserToPMABufferCopy()操作這個(gè)發(fā)送緩沖區,這個(gè)函數已經(jīng)在USB庫的手冊中說(shuō)明。

最后一個(gè)問(wèn)題是:如果你的程序中使用了ENDP1_RXADDR,因為你改變了ENDP1包的長(cháng)度,即改變了發(fā)送緩沖區的長(cháng)度,需要在usb_conf.h中重新定義以下ENDP1_RXADDR的地址。

最初發(fā)表日期:2008-8-29
本文地址:http://selenalain.com/thread-5775-1-1.html     【打印本頁(yè)】

本站部分文章為轉載或網(wǎng)友發(fā)布,目的在于傳遞和分享信息,并不代表本網(wǎng)贊同其觀(guān)點(diǎn)和對其真實(shí)性負責;文章版權歸原作者及原出處所有,如涉及作品內容、版權和其它問(wèn)題,我們將根據著(zhù)作權人的要求,第一時(shí)間更正或刪除。
您需要登錄后才可以發(fā)表評論 登錄 | 立即注冊

相關(guān)在線(xiàn)工具

相關(guān)視頻

關(guān)于我們  -  服務(wù)條款  -  使用指南  -  站點(diǎn)地圖  -  友情鏈接  -  聯(lián)系我們
電子工程網(wǎng) © 版權所有   京ICP備16069177號 | 京公網(wǎng)安備11010502021702
快速回復 返回頂部 返回列表
午夜高清国产拍精品福利|亚洲色精品88色婷婷七月丁香|91久久精品无码一区|99久久国语露脸精品|动漫卡通亚洲综合专区48页