新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > STM32--USB詳細使用說明

        STM32--USB詳細使用說明

        作者: 時間:2016-11-27 來源:網絡 收藏

        ***************(3)**************

        1.獲取設備描述符

        usb_int.c的文件里面

        低優先級中斷 在控制 中斷 批量傳輸下使用(在單緩沖模式下使用)
        當一次正確的OUT,SETUP,IN數據傳輸完成后,硬件會自動設置此位為NAK狀態,使應用程序有足夠的時間處理完當前傳輸的數據后,響應下一個數據分組

        void CTR_LP(void)
        {
        __IO uint16_t wEPVal = 0;

        while (((wIstr = _GetISTR()) & ISTR_CTR) != 0)
        {

        EPindex = (uint8_t)(wIstr & ISTR_EP_ID);//讀出端點ID
        if (EPindex == 0)//如果是端點0
        {





        SaveRState = _GetENDPOINT(ENDP0);//讀取端點0寄存器USB_EP0R
        SaveTState = SaveRState & EPTX_STAT;//保存發送狀態位
        SaveRState &= EPRX_STAT;//保存接受狀態位
        _SetEPRxTxStatus(ENDP0,EP_RX_NAK,EP_TX_NAK);//端點以NAK分組響應所有的發送和接受請求(解釋在上面)

        if ((wIstr & ISTR_DIR) == 0)//IN令牌,數據被取走

        {



        _ClearEP_CTR_TX(ENDP0);//清除正確發送標志位
        In0_Process();//處理INT事件

        _SetEPRxTxStatus(ENDP0,SaveRState,SaveTState);
        return;
        }
        else
        {


        wEPVal = _GetENDPOINT(ENDP0);//得到端點0寄存器的數據
        if ((wEPVal &EP_SETUP) != 0)//SETUP分組傳輸完成標志
        {
        _ClearEP_CTR_RX(ENDP0);
        Setup0_Process();//處理SETUP事件

        //程序會進入到這個函數里面

        _SetEPRxTxStatus(ENDP0,SaveRState,SaveTState);
        return;
        }

        else if ((wEPVal & EP_CTR_RX) != 0)
        {
        _ClearEP_CTR_RX(ENDP0);
        Out0_Process();//處理OUT事件

        _SetEPRxTxStatus(ENDP0,SaveRState,SaveTState);
        return;
        }
        }
        }
        else//如果是除端點0以外的端點
        {


        wEPVal = _GetENDPOINT(EPindex);//得到相應端點寄存器值
        if ((wEPVal & EP_CTR_RX) != 0)//檢測正確接收標志 PC-USB OUT int
        {

        _ClearEP_CTR_RX(EPindex);//清除相應的標志


        (*pEpInt_OUT[EPindex-1])();//調用OUT int服務功能

        }

        if ((wEPVal & EP_CTR_TX) != 0)//檢測正確發送標志 USB-PC IN int
        {

        _ClearEP_CTR_TX(EPindex);//清除相應的標志


        (*pEpInt_IN[EPindex-1])();//調用IN int服務功能
        }

        }

        }
        }

        usb_coer.c的文件里面,主要是得到主機發來的標準請求命令

        uint8_t Setup0_Process(void)
        {

        union
        {
        uint8_t* b;
        uint16_t* w;
        } pBuf;

        #ifdef STM32F10X_CL
        USB_OTG_EP *ep;
        uint16_t offset = 0;
        ep = PCD_GetOutEP(ENDP0);
        pBuf.b = ep->xfer_buff;
        #else
        uint16_t offset = 1;
        //得到接受緩沖區地址寄存器地址
        pBuf.b = PMAAddr + (uint8_t *)(_GetEPRxAddr(ENDP0) * 2);
        #endif

        if (pInformation->ControlState != PAUSE)
        {
        pInformation->USBbmRequestType = *pBuf.b++;

        pInformation->USBbRequest = *pBuf.b++;

        pBuf.w += offset;
        pInformation->USBwValue = ByteSwap(*pBuf.w++);

        pBuf.w += offset;
        pInformation->USBwIndex = ByteSwap(*pBuf.w++);

        pBuf.w += offset;
        pInformation->USBwLength = *pBuf.w;

        }

        pInformation->ControlState = SETTING_UP;
        if (pInformation->USBwLength == 0)
        {

        NoData_Setup0();
        }
        else
        {

        Data_Setup0();//由于是有數據的傳輸,所有要進入到這個函數
        }
        return Post0_Process();
        }

        usb_core.c的文件里面,這里只是選取了GET DESCRIPTOR

        的程序部分,其他的部分刪除了

        void Data_Setup0(void)
        {
        uint8_t *(*CopyRoutine)(uint16_t);
        RESULT Result;
        uint32_t Request_No = pInformation->USBbRequest;

        uint32_t Related_Endpoint, Reserved;
        uint32_t wOffset, Status;

        CopyRoutine = NULL;
        wOffset = 0;

        //看標準請求碼格式就知道了
        if (Request_No == GET_DESCRIPTOR)
        {
        //pInformation->USBbmRequestType是下面的兩種 標準請求或設備請求
        if (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT))
        {
        uint8_t wValue1 = pInformation->USBwValue1;//高一字節得到描述表種類 一共有5種
        if (wValue1 == DEVICE_DESCRIPTOR)//設備描述
        {
        CopyRoutine = pProperty->GetDeviceDescriptor;
        }
        else if (wValue1 == CONFIG_DESCRIPTOR)
        {
        CopyRoutine = pProperty->GetConfigDescriptor;//配置描述
        }
        else if (wValue1 == STRING_DESCRIPTOR)
        {
        CopyRoutine = pProperty->GetStringDescriptor;//字符串描述
        }
        }
        }

        if (CopyRoutine)
        {
        pInformation->Ctrl_Info.Usb_wOffset = wOffset;//本子程序的wOffset是0
        pInformation->Ctrl_Info.CopyData = CopyRoutine;//使指針pInformation->Ctrl_Info.CopyData指向CopyRoutine


        (*CopyRoutine)(0);//第一次執行時Length=0 返回的是有效數據的長度 存儲到pInformation->Ctrl_Info.Usb_wLength
        Result = USB_SUCCESS;
        }
        else
        {//如果標準請求不存在 看類 廠商請求中是否有
        Result = (*pProperty->Class_Data_Setup)(pInformation->USBbRequest);
        if (Result == USB_NOT_READY)
        {
        pInformation->ControlState = PAUSE;
        return;
        }
        }

        if (pInformation->Ctrl_Info.Usb_wLength == 0xFFFF)//如果字符的長度是0xffff
        {

        pInformation->ControlState = PAUSE;
        return;
        }
        if ((Result == USB_UNSUPPORT) || (pInformation->Ctrl_Info.Usb_wLength == 0))
        {

        pInformation->ControlState = STALLED;
        return;
        }

        if (ValBit(pInformation->USBbmRequestType, 7))//D7表示數據傳輸方向 1:設備向主機
        {

        __IO uint32_t wLength = pInformation->USBwLength;

        //設置使其為USB主機設置的長度 本程序HID 鼠標 pProperty->MaxPacketSize是0x40
        if (pInformation->Ctrl_Info.Usb_wLength > wLength)//字符的長度大于主機要求的長度

        {
        pInformation->Ctrl_Info.Usb_wLength = wLength;

        //將其設置為主機要求的
        }
        else if (pInformation->Ctrl_Info.Usb_wLength < pInformation->USBwLength)//字符的長度小于主機要求的
        {
        if (pInformation->Ctrl_Info.Usb_wLength < pProperty->MaxPacketSize) //如果字符的長度長度小于每包數據最大字節數
        {
        Data_Mul_MaxPacketSize = FALSE;
        }
        else if ((pInformation->Ctrl_Info.Usb_wLength % pProperty->MaxPacketSize) == 0)//如果是其整數倍
        {
        Data_Mul_MaxPacketSize = TRUE;
        }
        }

        pInformation->Ctrl_Info.PacketSize = pProperty->MaxPacketSize;
        DataStageIn();
        }
        else//主機向設備
        {
        pInformation->ControlState = OUT_DATA;
        vSetEPRxStatus(EP_RX_VALID);
        }

        return;
        }

        usb_coer.c的文件里面

        void DataStageIn(void)
        {
        ENDPOINT_INFO *pEPinfo = &pInformation->Ctrl_Info;//端點信息保存在指針變量中
        uint32_t save_wLength = pEPinfo->Usb_wLength;//得到字符的長度
        uint32_t ControlState = pInformation->ControlState;//得到當前的狀態

        uint8_t *DataBuffer;
        uint32_t Length;

        if ((save_wLength == 0) && (ControlState == LAST_IN_DATA))//如果字符長度為0 且控制狀態是最后輸入的數據
        {
        if(Data_Mul_MaxPacketSize == TRUE)//如果字符的長度是數據包的整數倍
        {

        Send0LengthData();
        ControlState = LAST_IN_DATA;
        Data_Mul_MaxPacketSize = FALSE;//這一次發送0字節 狀態轉為最后輸入階段
        }
        else//字符的長度比數據包要小
        {//數據已經發送完

        ControlState = WAIT_STATUS_OUT;

        #ifdef STM32F10X_CL
        PCD_EP_Read (ENDP0, 0, 0);
        #endif
        #ifndef STM32F10X_CL
        vSetEPTxStatus(EP_TX_STALL);//設置端點的發送狀態停止
        #endif
        }
        goto Expect_Status_Out;
        }

        Length = pEPinfo->PacketSize;//得到數據包大小 64字節
        ControlState = (save_wLength <= Length) ? LAST_IN_DATA : IN_DATA;//比較大小得到是LAST_IN_DATA還是IN_DATA 18字節<64字節 ControlState = LAST_IN_DATA

        if (Length > save_wLength)
        {
        Length = save_wLength;
        }

        DataBuffer = (*pEPinfo->CopyData)(Length);//DataBuffer指向要復制數據的地址 這個地址是隨Usb_wOffset變化的

        #ifdef STM32F10X_CL
        PCD_EP_Write (ENDP0, DataBuffer, Length);
        #else
        //GetEPTxAddr(ENDP0) 得到發送緩沖區相應端點的地址
        //將DataBuffer中的數據復制到相應的發送緩沖區中
        UserToPMABufferCopy(DataBuffer, GetEPTxAddr(ENDP0), Length);
        #endif

        SetEPTxCount(ENDP0, Length);//設置相應的端點要發送的字節數

        pEPinfo->Usb_wLength -= Length;//等于0
        pEPinfo->Usb_wOffset += Length;//偏移到18
        vSetEPTxStatus(EP_TX_VALID);//使能發送端點 只要主機的IN令牌包一來 SIE就會將描述符返回給主機

        USB_StatusOut();
        //設置接收端點有效 這個實際上使接受也有效,

        Expect_Status_Out:
        pInformation->ControlState = ControlState;//保存控制狀態
        }

        ***************(4)**************

        uint8_t In0_Process(void)
        {
        uint32_t ControlState = pInformation->ControlState;

        if ((ControlState == IN_DATA) || (ControlState ==LAST_IN_DATA))//進入到這里

        {
        DataStageIn();//第一次取設備描述符只取一次當前的狀態變為WAIT_STATUS_IN表明設備等待狀態過程 主機輸出0字節

        ControlState = pInformation->ControlState;
        }

        else if (ControlState == WAIT_STATUS_IN)//設置地址狀態階段進入這個程序
        {
        if ((pInformation->USBbRequest == SET_ADDRESS) &&
        (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT)))
        {
        SetDeviceAddress(pInformation->USBwValue0);//設置使用新的地址
        pUser_Standard_Requests->User_SetDeviceAddress();
        }
        (*pProperty->Process_Status_IN)();
        ControlState = STALLED;//變為這個狀態
        }

        else
        {
        ControlState = STALLED;
        }

        pInformation->ControlState = ControlState;

        return Post0_Process();
        }



        關鍵詞: STM32USB使用說

        評論


        技術專區

        關閉
        主站蜘蛛池模板: 孟津县| 惠东县| 龙岩市| 镇安县| 静宁县| 云南省| 湖口县| 蒙自县| 商河县| 荥阳市| 彩票| 上虞市| 井冈山市| 永州市| 永善县| 东源县| 昌宁县| 宜章县| 和静县| 山丹县| 平远县| 西峡县| 睢宁县| 阿瓦提县| 喀喇沁旗| 洮南市| 同仁县| 宝鸡市| 宜都市| 永登县| 梓潼县| 绥滨县| 哈密市| 桦甸市| 麦盖提县| 桓台县| 河源市| 平利县| 巴彦淖尔市| 安泽县| 郓城县|