小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

如何使用STM32的USB庫(kù)支持控制端點(diǎn)0

 gastonfeng 2012-04-12
如何使用STM32的USB庫(kù)支持控制端點(diǎn)0  [單片機(jī)]發(fā)布時(shí)間:2008-08-25 15:07:49 

首先我們先回顧一下控制端點(diǎn)的傳輸方式:

控制端點(diǎn)的傳輸有三個(gè)階段,SETUP階段、數(shù)據(jù)階段和狀態(tài)階段;數(shù)據(jù)階段又分為數(shù)據(jù)入(DATA IN)和數(shù)據(jù)出(DATA OUT),控制端點(diǎn)傳輸可以沒有數(shù)據(jù)階段;狀態(tài)階段有狀態(tài)入(STATUS IN)和狀態(tài)出(STATUS OUT)。

總結(jié)起來(lái),控制端點(diǎn)有如下三種可能的傳輸過程(以下括號(hào)中的0或1表示DATA0或DATA1傳輸):
一、 SETUP  DATA_IN(0)  DATA_IN(1)  DATA_IN(0)  ......  STATUS_OUT(1)
二、 SETUP  DATA_OUT(0)  DATA_OUT(1)  DATA_OUT(0)  ...... STATUS_IN(1)
三、 SETUP  STATUS_IN(1)

這里做一個(gè)約定,把上述過程一定義為“數(shù)據(jù)入過程”,過程二定義為“數(shù)據(jù)出過程”,過程三定義為“無(wú)數(shù)據(jù)過程”。所有的USB控制端點(diǎn)的數(shù)據(jù)傳輸都可以而且只用這三種傳輸過程表示。HID的SET_REPORT是數(shù)據(jù)出過程,HID的GET_REPORT是數(shù)據(jù)入過程,USB的GET DEVICE DESCRIPTOR是數(shù)據(jù)入過程,USB的SET CONFIGURATION是無(wú)數(shù)據(jù)過程,等等。







接下來(lái),我們看看STM32的USB庫(kù)是如何處理控制端點(diǎn)0的傳輸。

根據(jù)USB協(xié)議,每個(gè)SETUP包都由8個(gè)字節(jié)構(gòu)成,用戶程序可以通過結(jié)構(gòu)體Device_Info(類型DEVICE_INFO)訪問SETUP包的數(shù)據(jù),因?yàn)樵谡麄€(gè)的USB處理中都要用到結(jié)構(gòu)體Device_Info的內(nèi)容,庫(kù)中定義了一個(gè)全局的指針pInformation指向這個(gè)結(jié)構(gòu)體,用戶可以通過這個(gè)指針訪問結(jié)構(gòu)體的內(nèi)容。

對(duì)應(yīng)SETUP包的8個(gè)字節(jié),用戶可以用下述方式訪問:
  pInformation->USBbmRequestType (字節(jié)類型)
  pInformation->USBbRequest  (字節(jié)類型)
  pInformation->USBwValue  (雙字節(jié)類型)
  pInformation->USBwIndex  (雙字節(jié)類型)
  pInformation->USBwLength (雙字節(jié)類型)
使用pInformation->USBwValue0訪問wValue的低字節(jié),pInformation->USBwValue1訪問wValue的高字節(jié)。
使用pInformation->USBwIndex0訪問USBwIndex的低字節(jié),pInformation->USBwIndex1訪問USBwIndex的高字節(jié)。
使用pInformation->USBwLength0訪問USBwLength的低字節(jié),pInformation->USBwLength1訪問USBwLength的高字節(jié)。

通過分析SETUP包的8個(gè)字節(jié),可以判斷出一個(gè)SETUP的傳輸過程是屬于數(shù)據(jù)入過程數(shù)據(jù)出過程還是無(wú)數(shù)據(jù)過程。STM32的USB庫(kù)中處理了所有的USB協(xié)議文本中定義的標(biāo)準(zhǔn)SETUP命令,對(duì)于USB協(xié)議文本中未定義的命令,USB庫(kù)按照數(shù)據(jù)入過程、數(shù)據(jù)出過程無(wú)數(shù)據(jù)過程通過回調(diào)函數(shù)交給用戶程序處理。

全局變量Device_Property(DEVICE_PROP類型)封裝了所有的回調(diào)函數(shù),DEVICE_PROP定義如下:
typedef struct _DEVICE_PROP
{
  void (*Init)(void);        // 設(shè)備初始化回調(diào)函數(shù)
  void (*Reset)(void);       // USB復(fù)位回調(diào)函數(shù)

  void (*Process_Status_IN)(void);  // STATUS_IN階段處理回調(diào)函數(shù)
  void (*Process_Status_OUT)(void); // STATUS_OUT階段處理回調(diào)函數(shù)

  RESULT (*Class_Data_Setup)(u8 RequestNo);   // 數(shù)據(jù)入/出過程處理回調(diào)函數(shù)
  RESULT (*Class_NoData_Setup)(u8 RequestNo); // 無(wú)數(shù)據(jù)過程處理回調(diào)函數(shù)

  RESULT  (*Class_Get_Interface_Setting)(u8 Interface, u8 AlternateSetting); // GET_INTERFACE 回調(diào)函數(shù)

  u8* (*GetDeviceDescriptor)(u16 Length); // GET_DEVICE_DESCRIPTION回調(diào)函數(shù)
  u8* (*GetConfigDescriptor)(u16 Length); // GET_CONFIGURATION_DESCRIPTION回調(diào)函數(shù)
  u8* (*GetStringDescriptor)(u16 Length); // GET_STRING_DESCRIPTION回調(diào)函數(shù)
  u8 MaxPacketSize; // 最大包長(zhǎng)度
} DEVICE_PROP;

結(jié)合SETUP的三種傳輸過程,用戶通過實(shí)現(xiàn)不同的回調(diào)函數(shù)即可完成對(duì)各種USB類命令的處理,下面以HID的SET REPORT為例說明。







在介紹具體實(shí)現(xiàn)之前,先介紹一下另一個(gè)回調(diào)函數(shù)CopyRoutine的概念,這個(gè)函數(shù)的原型是:
   u8 *CopyRoutine(u16 length);    // 返回一個(gè)緩沖區(qū)指針

USB庫(kù)通過這個(gè)函數(shù)獲得用戶的數(shù)據(jù)緩沖區(qū)地址,從而可以在數(shù)據(jù)出過程中把收到的數(shù)據(jù)拷貝到用戶緩沖區(qū),或在數(shù)據(jù)入過程中把用戶緩沖區(qū)的數(shù)據(jù)拷貝到USB發(fā)送緩沖區(qū)。每個(gè)數(shù)據(jù)出過程可能有若干次DATA_OUT傳輸,USB庫(kù)每完成一次這樣的傳輸都會(huì)調(diào)用一次回調(diào)函數(shù)CopyRoutine,參數(shù)length是本次傳輸所收到的數(shù)據(jù)字節(jié)數(shù)目,CopyRoutine必須返回一個(gè)緩沖區(qū)指針,這個(gè)緩沖區(qū)必須能夠容納length字節(jié)的數(shù)據(jù),CopyRoutine返回到USB庫(kù)之后,USB庫(kù)將把收到的數(shù)據(jù)拷貝到用戶指定的緩沖區(qū)。同樣每個(gè)數(shù)據(jù)入過程也可能有若干次DATA_IN傳輸,每次需要向主機(jī)傳輸數(shù)據(jù)時(shí),USB庫(kù)都會(huì)調(diào)用一次回調(diào)函數(shù)CopyRoutine,參數(shù)length是本次傳輸所要發(fā)送的數(shù)據(jù)字節(jié)數(shù)目,CopyRoutine必須返回一個(gè)緩沖區(qū)指針,這個(gè)緩沖區(qū)中必須包含要求的數(shù)據(jù)字節(jié),USB庫(kù)將把用戶緩沖區(qū)的數(shù)據(jù)拷貝到USB緩沖區(qū)并擇機(jī)發(fā)送出去。

當(dāng)以length=0調(diào)用CopyRoutine時(shí),CopyRoutine需要返回用戶緩沖區(qū)的長(zhǎng)度,因?yàn)镃opyRoutine的返回類型是一個(gè)指針,所以需要通過類型的強(qiáng)制轉(zhuǎn)換返回緩沖區(qū)長(zhǎng)度。這個(gè)功能是為了處理用戶緩沖區(qū)的長(zhǎng)度與主機(jī)SETUP數(shù)據(jù)請(qǐng)求長(zhǎng)度不符的情況,而不至于造成用戶緩沖區(qū)的溢出。







介紹完上述若干概念和回調(diào)函數(shù),再看SET_REPORT的實(shí)現(xiàn)就很容易了。

SET_REPORT是一個(gè)數(shù)據(jù)出過程,因此需要實(shí)現(xiàn)一個(gè)Class_Data_Setup回調(diào)函數(shù),示例如下:

RESULT HID_Data_Setup(u8 RequestNo)
{
    u8 *(*CopyRoutine)(u16 length);
    CopyRoutine = NULL;
    if (pInformation->USBbmRequestType == CLASS_REQUEST|INTERFACE_RECIPIENT
            && RequestNo == SET_REPORT)
        CopyRoutine = My_Data_Request;

    if (CopyRoutine == NULL)
        return USB_UNSUPPORT;

    pInformation->Ctrl_Info.CopyData = CopyRoutine;
    pInformation->Ctrl_Info.Usb_wOffset = 0;
    pInformation->Usb_wLength = (*CopyRoutine)(0);

    return USB_SUCCESS;
} // End of HID_Data_Setup()

u8 My_Buffer[10];
u8 *My_Data_Request(u16 length)
{
    if (length == 0)
        return (u8*)10;    // 假定你的REPORT長(zhǎng)度和Buffer長(zhǎng)度為10

    return My_Buffer;
}







上面介紹的CopyRoutine用于把多次傳輸?shù)臄?shù)據(jù)包合并到一個(gè)完整的緩沖區(qū)中,因此只有到STATUS階段才能夠知道一次SETUP傳輸是否結(jié)束,所以用戶程序需要在回調(diào)函數(shù)Process_Status_IN中處理從SET_REPORT接收到的數(shù)據(jù)。因?yàn)樗械幕卣{(diào)函數(shù)都是USB中斷處理的一部分,所以更好的辦法是在Process_Status_IN中設(shè)置一個(gè)標(biāo)記,然后在用戶主程序中判斷這個(gè)標(biāo)記并做處理。





上述示意代碼是以My_Buffer長(zhǎng)度為10字節(jié)為例,而USB庫(kù)的默認(rèn)包長(zhǎng)度為16字節(jié),因此My_Data_Request并沒有多包的處理。

關(guān)于多包的緩沖區(qū)處理的示意代碼可以是這樣的:

u8 *My_Data_Request(u16 length)
{
    if (length == 0)
        return (u8*)100;    // 假定你的REPORT長(zhǎng)度和Buffer長(zhǎng)度為100

    return &My_Buffer[pInformation->Ctrl_Info.Usb_wOffset];
}

這里有一個(gè)庫(kù)中使用的變量pInformation->Ctrl_Info.Usb_wOffset,這個(gè)變量會(huì)在傳輸每個(gè)數(shù)據(jù)包時(shí)候由庫(kù)中的程序按數(shù)據(jù)包長(zhǎng)度增加,如最大包長(zhǎng)為16字節(jié)時(shí),第一次調(diào)用My_Data_Request時(shí)Usb_wOffset=0,第二次調(diào)用My_Data_Request時(shí)Usb_wOffset=16,第三次調(diào)用My_Data_Request時(shí)Usb_wOffset=32,依此類推。這樣就可以使用Usb_wOffset作為My_Buffer的下標(biāo)從My_Data_Request返回相應(yīng)的緩沖區(qū)地址。





前面已經(jīng)說明,參數(shù)length是用于檢測(cè)緩沖區(qū)長(zhǎng)度是否足夠,如果你有足夠長(zhǎng)的緩沖區(qū),可以不必檢測(cè),上述示例中使用了一個(gè)固定的緩沖區(qū),所以不必使用參數(shù)length檢測(cè)緩沖區(qū)長(zhǎng)度。







注意,STM32的USB庫(kù)設(shè)計(jì)成以回調(diào)函數(shù)處理用戶命令請(qǐng)求,包含類命令請(qǐng)求,是為了能夠清晰地區(qū)分庫(kù)程序和用戶程序,使這兩者不會(huì)混在一起,這樣的好處是非常明顯的,當(dāng)USB庫(kù)需要更新升級(jí)時(shí),只需替換掉相應(yīng)的程序模塊,而不必修改用戶已經(jīng)完成的程序。

以上的介紹都可以在STM32 USB庫(kù)的說明手冊(cè)中找到。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多