程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> STM32 USB 問題匯總

STM32 USB 問題匯總

編輯:C++入門知識

以下是筆者將ST的Custom_HID例程修改為“自定義USB設備”例程時總結出來的,因為筆者也是剛剛學USB開發不久,某些方面理解錯誤在所難免,請各位大蝦指正。

一、usb_desc.c文件

根據你程序使用的通信方式修改。usb_desc.h文件中定義要根據usb_desc.c文件中的數組的大小;ConfigDescriptor[SIZ_CONFIG_DESC]下添加需要處理的端點;根據需要添加或刪除報告描述符(主要用於HID)和CDC接口描述符(主要用於實現USB轉串口)等。具體方法可以下載個“電腦圈圈”使用D12編寫的例子。

二、Usb_conf.h文件:

1、修改需要處理那些中斷

CNTR_CTRM     處理數據正確傳輸後控制,比如說響應主機

CNTR_DOVRM   /* DMA OVeR/underrun Mask */

CNTR_ERRM     /* ERRor Mask */

CNTR_WKUPM 0  /* WaKe UP Mask */

CNTR_SUSPM    /* SUSPend Mask */

CNTR_RESETM   主要處理USB復位後進行一些初始化任務

CNTR_SOFM     /* Start Of Frame Mask */

CNTR_ESOFM    /* Expected Start Of Frame Mask */

如:

usb_conf.h中的#define IMR_MSK (CNTR_CTRM | CNTR_SOFM | CNTR_RESETM )是決定USB_CNTR寄存器中的那個USB相關中斷啟動還是屏蔽。

 

2、根據需要增加端點緩存地址,要根據緩存區的地址修改,防止數據重疊

如下為根據每個緩沖區的大小為64字節修改:

#define ENDP1_TXADDR        (0xC0)

#define ENDP1_RXADDR        (0xD0)

#define ENDP2_TXADDR        (0x100)

#define ENDP2_RXADDR        (0x140)

#define ENDP3_TXADDR        (0x180)

#define ENDP3_RXADDR        (0x1C0)

 

3、修改/* CTR service routines */下的EPX_IN_Callback和EPX_OUT_Callback。注釋掉需要處理的函數。NOP_Process表示不處理。

 

三usb_prop.c文件

1、修改void XX_Reset(void)(如:void Joystick_Reset(void))

一般/* Initialize Endpoint 0 */的不用修改,如下為舉例說明端點1的初始化,其他端口原理一樣。

SetEPType(ENDP1, EP_INTERRUPT);//設置端點1類型

/*EP_BULK  批量端點

EP_CONTROL 控制端點

EP_ISOCHRNOUS 同步端點

EP_INTERRUPT 中斷端點*/

SetEPTxAddr(ENDP1, ENDP1_TXADDR); //設置端點1緩沖區基地址

SetEPTxCount(ENDP1, 64);// 配置Tx 緩沖計數器

SetEPRxStatus(ENDP1, EP_RX_DIS);// //設置端點接收關閉

SetEPTxStatus(ENDP1, EP_TX_NAK);// //設置端點1發送不應答

/*

#define EP_RX_DIS      (0x0000) // EndPoint RX DISabled 端點接收關閉

#define EP_RX_STALL    (0x1000) // EndPoint RX STALLed 端點接收延遲

#define EP_RX_NAK      (0x2000) // EndPoint RX NAKed 端點接收不應答

#define EP_RX_VALID    (0x3000) // EndPoint RX VALID端點接收有效

#define EP_TX_DIS      (0x0000) //EndPoint TX DISabled

#define EP_TX_STALL    (0x0010) // EndPoint TX STALLed

#define EP_TX_NAK      (0x0020) // EndPoint TX NAKed

#define EP_TX_VALID    (0x0030) // EndPoint TX VALID */

 

2、刪除不相干的描述符等。

如自定義的USB設備就不需要以下結構體初始化:

ONE_DESCRIPTOR Joystick_Report_Descriptor

ONE_DESCRIPTOR Mouse_Hid_Descriptor

 

3、修改RESULT XX_Data_Setup(u8 RequestNo)的數據類請求處理。

如Custom_HID例程修改為“自定義USB設備”例程時可以將以下代碼刪除

if ((RequestNo == GET_DESCRIPTOR)

      && (Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT))

      && (pInformation->USBwIndex0 == 0))

  {

 

    if (pInformation->USBwValue1 == REPORT_DESCRIPTOR)

    {

      CopyRoutine = Joystick_GetReportDescriptor;

    }

    else if (pInformation->USBwValue1 == HID_DESCRIPTOR_TYPE)

    {

      CopyRoutine = Joystick_GetHIDDescriptor;

    }

 

  }

 

4、刪除不相干的獲得描述符返回函數

如自定義的USB設備就不需要以下函數:

Joystick_GetReportDescriptor

Joystick_GetHIDDescriptor

 

 

四、usb_endp.c文件

1、增加之前定義的中斷數據處理函數

如:

void EP1_OUT_Callback(void)

{

       這些寫接收代碼

}

 

五、數據發送和接收,舉例說明

1、數據接收

u8 DataLen;

  DataLen = GetEPRxCount(ENDP1);

  PMAToUserBufferCopy(TX1_buffer, ENDP1_RXADDR, DataLen);

  SetEPRxValid(ENDP1);

  USART1_Send(DataLen);

  count_out = 1;

 

2、數據發送

UserToPMABufferCopy(InBuffer, GetEPTxAddr(ENDP1), 64);

SetEPTxCount(ENDP1, 64);                    

SetEPTxValid(ENDP1);

===========================================================================


匯總2:STM32 USB 程序將BULK EP改成雙緩沖機制後,一直狂飚到了1MB/S!來自:http://www.powermcu.com/bbs/viewthread.php?tid=693


前天測試自己編寫的USB驅動程序時候發現從主機到STM32的OUT傳輸(主機到設備)速率竟然只有最高33KB/S,實在是暈死了。經過研究後發現是驅動程序中設置的PIPE MaxTransferSize參數的關系,原先設置64只能33KB/S,後參考其他USB設備驅動程序的值,設置成了65535,再測試USB OUT的速度,達到了500KB/S,終於解決了驅動程序的瓶頸。不過算下USB 2.0全速的通訊速率是12Mb/S,排除掉CRC、令牌、SOF等等開銷怎麼也應該不止最大500KB/S啊。到網上看了看,基本上應該能達到600KB/S~700KB/S以上,我現在的速度應該還有很大的提升才是。
    看看程序,發現
void EP3_OUT_Callback(void)//EP3 OUT的回調函數,當EP3接收到數據時候中斷調用該函數
{
  count_out = GetEPRxCount(ENDP3);//獲得接收到的數據長度
  PMAToUserBufferCopy(buffer_out, ENDP3_RXADDR, count_out);//將數據從USB EP3 RX的緩沖區拷貝到用戶指定的數組中
  SetEPRxValid(ENDP3); //完成拷貝後置有效狀態,從而EP3發送ACK主機可以進行下一個數據包的發送
}
    試著將PMAToUserBufferCopy這句注釋掉(這樣STM32就不處理接收到的數據了)後再測試速度,驚奇地發現速度竟然達到了997KB/S!晚上仔細想了想,數據肯定是要使用的,這個數據拷貝的過程的時間消費總是少不了的;由於通常情況下USB設備BULK數據接收的步驟就是:接收到數據,置NAK->將緩沖區數據拷貝到用戶區(用戶處理過程)->發ACK通知主機完成了完整的接收可以發送下一個->主機發送下一個,按照以上的步驟USB接收一步步的進行,只要STM32不完成數據處理,狀態就一直是NAK,主機就會不停地發送該數據包,浪費了帶寬,因此就會導致我上面最大速度500KB/S難以再增加的情況!不甘心啊~~
    昨天晚上又仔細研究了STM32的技術參考手冊的USB章節內容,裡面提到BULK可以采用雙緩沖機制(PING-PONG)進行處理,正好可以解決上面的情況。雙緩沖機制的原理就是分配2塊接收緩沖,STM32的用戶處理和USB接口可以分別交替占用2個緩沖區,當USB端點接收數據寫其中一個緩沖區的時候,用戶的應用程序可以同時處理另一個緩沖區,這樣緩沖區依次交換占有者,只要用戶處理程序在USB端點接收的時間片段內完成處理,就能夠完全不影響USB的通訊速度!
    程序部分修改
一、EP3_OUT的設置修改,
//ZYP:修改EP3為BULK雙緩沖方式-------------------------
  SetEPType(ENDP3, EP_BULK);
  SetEPDoubleBuff(ENDP3);
  SetEPDblBuffAddr(ENDP3, ENDP3_BUF0Addr, ENDP3_BUF1Addr);
  SetEPDblBuffCount(ENDP3, EP_DBUF_OUT, VIRTUAL_COM_PORT_DATA_SIZE);
  ClearDTOG_RX(ENDP3);
  ClearDTOG_TX(ENDP3);
  ToggleDTOG_TX(ENDP3);
  SetEPRxStatus(ENDP3, EP_RX_VALID);
  SetEPTxStatus(ENDP3, EP_TX_DIS);
//------------------------------------------------------
二、EP3_OUT回調函數的修改
void EP3_OUT_Callback(void)
{
//ZYP:以下是修改成EP3雙緩沖OUT後的處理函數
  if (GetENDPOINT(ENDP3) & EP_DTOG_TX)//先判斷本次接收到的數據是放在哪塊緩沖區的
  {
    FreeUserBuffer(ENDP3, EP_DBUF_OUT); //先釋放用戶對緩沖區的占有,這樣的話USB的下一個接收過程可以立刻進行,同時用戶並行進行下面處理
    count_out = GetEPDblBuf0Count(ENDP3);//讀取接收到的字節數
    PMAToUserBufferCopy(buffer_out, ENDP3_BUF0Addr, count_out);
  }
  else
  {
    FreeUserBuffer(ENDP3, EP_DBUF_OUT); 
    count_out = GetEPDblBuf1Count(ENDP3);
    PMAToUserBufferCopy(buffer_out, ENDP3_BUF1Addr, count_out);
  }
}

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved