STM32 usb_core.c分析

2023-05-16

usb_core.c这个c文件是个庞大的文件,主要是定义了usb2.0的标注协议处理函数。
下面是这个文件的所有函数:

  

/******************************************************************************* * Function Name : Standard_GetConfiguration. * Description : 返回当前配置变量的地址 * Input : Length -需要的字节 How many bytes are needed. * Output : None. * Return : 如果'Length'值为0时,请求无效,返回1。长度不为0时,返回配置变量的地址 * Readme : 当配置值与摸个配置描述符中的配置编号一致时,表示选中该配置 *******************************************************************************/ uint8_t *Standard_GetConfiguration(uint16_t Length);

/******************************************************************************* * Function Name : Standard_SetConfiguration. * Description : 该函数用于设置配置值,主机发送该请求后,usb设备要配置自己的设备值 * Input : None. * Output : None. * Return : 当该请求被执行了,返回USB_SUCCESS * 当请求无效时,然会USB_UNSUPPORT *******************************************************************************/ RESULT Standard_SetConfiguration(void);

/******************************************************************************* * Function Name : Standard_GetInterface. * Description : 返回当前接口的备用接口 * Input : Length -需要的字节数 * Output : None. * Return : 当'Length'的值为0,请求无效,返回0,当长度不为0,返回备用接口的地址 *******************************************************************************/ uint8_t *Standard_GetInterface(uint16_t Length);

/******************************************************************************* * Function Name : Standard_GetStatus. * Description : 拷贝设备请求数据到"StatusInfo buffer". * Input : - Length -需要的字节数 * Output : None. * Return : 如果请求在数据块的末端,或则当'Length'为0是,请求无效,则返回0 *******************************************************************************/ uint8_t *Standard_GetStatus(uint16_t Length);

/******************************************************************************* * Function Name : Standard_ClearFeature. * Description : 清除或禁止某个指定的特性 * Input : None. * Output : None. * Return : 当请求被执行,返回Return USB_SUCCESS,如果请求无效,返回USB_UNSUPPORT *******************************************************************************/ RESULT Standard_ClearFeature(void);

/******************************************************************************* * Function Name : Standard_SetEndPointFeature * Description : 设置或使能端点的指定的特性 * Input : None. * Output : None. * Return : 如果请求被执行,返回USB_SUCCESS,如果请求无效,则返回USB_UNSUPPORT *******************************************************************************/ RESULT Standard_SetEndPointFeature(void);

/******************************************************************************* * Function Name : Standard_SetDeviceFeature. * Description : 设置或使能设备指定的特性 * Input : None. * Output : None. * Return : 如果请求被执行,返回USB_SUCCESS,如果请求无效,则返回USB_UNSUPPORT *******************************************************************************/ RESULT Standard_SetDeviceFeature(void);

/******************************************************************************* * Function Name : Standard_GetDescriptorData. * Description : Standard_GetDescriptorData用于描述符的传输. * : 这个函数用于驻留在flash或RAM里的描述符pDesc可以自相Flash或RAM * 这个函数的目的是具有不同的方式去响应描述符请求。 * 它允许用户通过软件生成的某些描述符或则读取外部存储设备的描述符部分. * Input : Length - 这次传输的的数据长度 * pDesc - 指向描述符结构体的指针 * Output : None. * Return : 返回usb_wOffset指向的描述符部分的地址。这个地址指向的缓冲包含最起码Length个字节 *******************************************************************************/ uint8_t *Standard_GetDescriptorData(uint16_t Length, ONE_DESCRIPTOR *pDesc);

/******************************************************************************* * Function Name : DataStageOut. * Description : 数据阶段的控制写传输 * Input : None. * Output : None. * Return : None. *******************************************************************************/ void DataStageOut(void);

/******************************************************************************* * Function Name : DataStageIn. * Description : 数据阶段的控制读传输 * Input : None. * Output : None. * Return : None. *******************************************************************************/ void DataStageIn(void);

/******************************************************************************* * Function Name : NoData_Setup0. * Description : 处理没有数据阶段的建立请求 * Input : None. * Output : None. * Return : None. *******************************************************************************/ void NoData_Setup0(void);

/******************************************************************************* * Function Name : Data_Setup0. * Description : 处理有数据阶段的建立请求 * Input : None. * Output : None. * Return : None. *******************************************************************************/ void Data_Setup0(void);

/******************************************************************************* * Function Name : Setup0_Process * Description : 建立阶段的数据处理Get the device request data and dispatch to individual process. * Input : None. * Output : None. * Return : Post0_Process. *******************************************************************************/ uint8_t Setup0_Process(void);

/******************************************************************************* * Function Name : In0_Process * Description : 处理默认端点的所有IN令牌包 * Input : None. * Output : None. * Return : Post0_Process. *******************************************************************************/ uint8_t In0_Process(void);

/******************************************************************************* * Function Name : Out0_Process * Description : 处理默认端点上的所有OUT令牌包 * Input : None. * Output : None. * Return : Post0_Process. *******************************************************************************/ uint8_t Out0_Process(void);

/******************************************************************************* * Function Name : Post0_Process * Description : 为防止错误,停止端点0Stall the Endpoint 0 in case of error. * Input : None. * Output : None. * Return : 如果控制状态是PAUSE,返回0;如果不是返回1 *******************************************************************************/ uint8_t Post0_Process(void);

/******************************************************************************* * Function Name : SetDeviceAddress. * Description : 设置设备和所有使用过的端点地址 * Input : Val:设备地址 * Output : None. * Return : None. *******************************************************************************/ void SetDeviceAddress(uint8_t Val);

/******************************************************************************* * Function Name : NOP_Process * Description : 没有处理函数 * Input : None. * Output : None. * Return : None. *******************************************************************************/ void NOP_Process(void);

这里简单地介绍几类函数。
首先要将的是关于USB特性(Feature)和状态的函数,这些函数包括:Standard_SetEndPointFeature();Standard_SetDeviceFeature;Standard_ClearFeature();Standard_GetStatus();这四个函数。
先讲讲 USB的Feature。对于USB的设备来说,特性就是否支持远程唤醒;如果是 对于USb的端点来说,端点是否有效(打开)就是端点的特性。
Standard_SetDeviceFeature函数中就是设置usb支持远程唤醒。

/******************************************************************************* * Function Name : Standard_SetDeviceFeature. * Description : 设置或使能设备指定的特性 * Input : None. * Output : None. * Return : 如果请求被执行,返回USB_SUCCESS,如果请求无效,则返回USB_UNSUPPORT *******************************************************************************/ RESULT Standard_SetDeviceFeature(void) { SetBit(pInformation->Current_Feature, 5); //置位Current_Feature的D5,即支持远程唤醒 pUser_Standard_Requests->User_SetDeviceFeature(); //调用User_SetDeviceFeature(),该函数在usb_prop.c中注册 return USB_SUCCESS; }


Standard_SetEndPointFeature()函数中就是停止(STALL)输入端点或则输出端点。

RESULT Standard_SetEndPointFeature(void) { uint32_t wIndex0; uint32_t Related_Endpoint; uint32_t rEP; uint32_t Status; wIndex0 = pInformation->USBwIndex0; //获取端点的地址 rEP = wIndex0 & ~0x80; //提取端点号 Related_Endpoint = ENDP0 + rEP; //端点号 if (ValBit(pInformation->USBwIndex0, 7)) //输入端口 { /* get Status of endpoint & stall the request if the related_ENdpoint is Disabled*/ Status = _GetEPTxStatus(Related_Endpoint); //获取端点的发送状态 } else //输出端口 { Status = _GetEPRxStatus(Related_Endpoint); //获取端点的接收状态 } if (Related_Endpoint >= Device_Table.Total_Endpoint //端点号小于总的已用端点数 || pInformation->USBwValue != 0 || Status == 0 //USBwValue域不为0(规定为0),端点的状态为0(端点关闭) || pInformation->Current_Configuration == 0) //当前的配置值为0 { return USB_UNSUPPORT; //返回USB_UNSUPPORT } else { if (wIndex0 & 0x80) //输入端口 { /* IN endpoint */ _SetEPTxStatus(Related_Endpoint, EP_TX_STALL); //设置端口的发送状态为停止 } else //输出端口 { /* OUT endpoint */ _SetEPRxStatus(Related_Endpoint, EP_RX_STALL); //设置端口的接收地址为停止 } } pUser_Standard_Requests->User_SetEndPointFeature(); //调用User_SetEndPointFeature()函数,该函数在usb_prop.c中注册 return USB_SUCCESS; }

至于 Standard_ClearFeature()函数就是清楚USB特性。对于设备来说,设置不支持远程唤醒;对于端点来说是设置输入端点或则输出端点有效(VALID)。

/******************************************************************************* * Function Name : Standard_ClearFeature. * Description : 清除或禁止某个指定的特性 * Input : None. * Output : None. * Return : 当请求被执行,返回Return USB_SUCCESS,如果请求无效,返回USB_UNSUPPORT *******************************************************************************/ RESULT Standard_ClearFeature(void) { uint32_t Type_Rec = Type_Recipient; uint32_t Status; if (Type_Rec == (STANDARD_REQUEST | DEVICE_RECIPIENT)) //标准请求,请求的接收者是设备 {/*Device Clear Feature*/ ClrBit(pInformation->Current_Feature, 5); //清除Current_Feature的D5,表示不支持远程唤醒 return USB_SUCCESS; //返回USB_SUCCESS } else if (Type_Rec == (STANDARD_REQUEST | ENDPOINT_RECIPIENT)) //标准请求,请求的接收者是端点 {/*EndPoint Clear Feature*/ DEVICE* pDev; uint32_t Related_Endpoint; uint32_t wIndex0; uint32_t rEP; if ((pInformation->USBwValue != ENDPOINT_STALL) //端点没有挂起 || (pInformation->USBwIndex1 != 0)) //USBwIndex1不为0(USBwIndex1必须为0) { return USB_UNSUPPORT; //返回USB_UNSUPPORT } pDev = &Device_Table; wIndex0 = pInformation->USBwIndex0; //wIndex获取端点地址 rEP = wIndex0 & ~0x80; //rEP存放端点号 Related_Endpoint = ENDP0 + rEP; //端点号 if (ValBit(pInformation->USBwIndex0, 7)) //输入端点 { /*Get Status of endpoint & stall the request if the related_ENdpoint is Disabled*/ Status = _GetEPTxStatus(Related_Endpoint); //获取端点的发送状态 } else //输出端点 { Status = _GetEPRxStatus(Related_Endpoint); //获取端点的接收状态 } if ((rEP >= pDev->Total_Endpoint) || (Status == 0) //端点号大于总的已使用的端点数,状态为0(端点关闭) || (pInformation->Current_Configuration == 0)) //或则当前的配置子为0 { return USB_UNSUPPORT; //返回USB_UNSUPPORT } if (wIndex0 & 0x80) //输入端点 { /* IN endpoint */ if (_GetTxStallStatus(Related_Endpoint )) //如果端点发送状态为停止(STALL) { #ifndef STM32F10X_CL ClearDTOG_TX(Related_Endpoint); #endif /* STM32F10X_CL */ SetEPTxStatus(Related_Endpoint, EP_TX_VALID); //设置端点发送状态有效(VALID) } } else //输出端点 { /* OUT endpoint */ if (_GetRxStallStatus(Related_Endpoint)) //如果端点接收状态为停止(STALl) { if (Related_Endpoint == ENDP0) //如果端点号为端点0 { /* After clear the STALL, enable the default endpoint receiver */ SetEPRxCount(Related_Endpoint, Device_Property.MaxPacketSize);//设置端点的接收数据包长度 _SetEPRxStatus(Related_Endpoint, EP_RX_VALID); //设置端点有效 } else //如果不是端点0 { #ifndef STM32F10X_CL ClearDTOG_RX(Related_Endpoint); #endif /* STM32F10X_CL */ _SetEPRxStatus(Related_Endpoint, EP_RX_VALID); //直接设置端点有效 } } } pUser_Standard_Requests->User_ClearFeature(); //调用User_ClearFeature()函数,该函数在usb_prop.c中定义 return USB_SUCCESS; } return USB_UNSUPPORT; }

使用Standard_GetStatus()这个函数来获得USB的状态,对于设备来说,获取状态就是要查看是否支持远程唤醒和是否自供电这两个状态。对于端点来说当让就是端点的状态了,收VALID,STALl还是其他状态。

/******************************************************************************* * Function Name : Standard_GetStatus. * Description : 拷贝设备请求数据到"StatusInfo buffer". * Input : - Length -需要的字节数 * Output : None. * Return : 如果请求在数据块的末端,或则当'Length'为0是,请求无效,则返回0 *******************************************************************************/ uint8_t *Standard_GetStatus(uint16_t Length) { if (Length == 0) //Length为0 { pInformation->Ctrl_Info.Usb_wLength = 2; //设置需要传输的字节数为2,因为状态信息为2个字节 return 0; } /* Reset Status Information */ //清空状态信息值 StatusInfo.w = 0; if (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT))//标准请求,请求的接收者是设备 { /*Get Device Status */ uint8_t Feature = pInformation->Current_Feature;//获取设备的特性值 if (ValBit(Feature, 5)) //如果特性Feature的D5为1,即特性支持远程唤醒 { SetBit(StatusInfo0, 1); //置位StatusInfo0状态信息的D1,表示支持远程唤醒 } else //如果特性Feature的D5为0,及表示不支持远程唤醒 { ClrBit(StatusInfo0, 1); //复位StatusInfo0状态信息的D1,表示不支持远程唤醒 } if (ValBit(Feature, 6)) //如果特性Feature的D6为1,表示是自供电的 { SetBit(StatusInfo0, 0); //置为StatusInfo0状态信息的D0,表示自供电 } else //如果特性Feature的D6为0,表示是总线供电的 { ClrBit(StatusInfo0, 0); //复位StatusInfo0状态信息的D0,表示总线供电 } } else if (Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT))//标准请求,请求的接收者是接口 { return (uint8_t *)&StatusInfo; //直接返回状态信息数据 } else if (Type_Recipient == (STANDARD_REQUEST | ENDPOINT_RECIPIENT))//标准请求,请求的接受者是端点 { uint8_t Related_Endpoint; uint8_t wIndex0 = pInformation->USBwIndex0; //获取端点的地址 Related_Endpoint = (wIndex0 & 0x0f); //获取wIndex0的低4位D0~D3,这4位为端点号,D7表示传输方向 if (ValBit(wIndex0, 7)) //如果wIndex0的最高位D7为1,表示是输入端点,这里的输入是相对于主机而言的 { if (_GetTxStallStatus(Related_Endpoint)) //如果端点的发送状态为停止(STALL) { SetBit(StatusInfo0, 0); //设置StatusInfo0状态信息的D0为1,表示发送停止状态 } } else //如果wIndex0的最高位D7为0,表示是输出端点 { if (_GetRxStallStatus(Related_Endpoint)) //如果端点接收状态为停止 { SetBit(StatusInfo0, 0); //设置StatusInfo0状态信息的D0为1,表示接收停止状态 } } } //其他情况,返回NULL else { return NULL; } pUser_Standard_Requests->User_GetStatus(); //调用User_GetStatus函数,该函数在usb_prop.c中注册 return (uint8_t *)&StatusInfo; //返回状态信息 }


接下去的一类函数是设置/获取配置值和接口值等,这些函数包括:Standard_GetConfiguration();Standard_SetConfiguration();Standard_GetInterface();Standard_SetInterface();Standard_GetDescriptorData();
先将Get的相关函数分析下:

/******************************************************************************* * Function Name : Standard_GetConfiguration. * Description : 返回当前配置变量的地址 * Input : Length -需要的字节 How many bytes are needed. * Output : None. * Return : 如果'Length'值为0时,请求无效,返回1。长度不为0时,返回配置变量的地址 * Readme : 当配置值与摸个配置描述符中的配置编号一致时,表示选中该配置 *******************************************************************************/ uint8_t *Standard_GetConfiguration(uint16_t Length) { if (Length == 0) //长度为0 { pInformation->Ctrl_Info.Usb_wLength = sizeof(pInformation->Current_Configuration); //端点通讯的数据长度为1个字节,因为Current_Configuration为1字节 return 0; //返回0,表示请求无效 } pUser_Standard_Requests->User_GetConfiguration(); //调用User_GetConfiguration函数,该函数在usb_prop.c中注册 return (uint8_t *)&pInformation->Current_Configuration;//返回当前的配置是的地址 }

/******************************************************************************* * Function Name : Standard_GetInterface. * Description : 返回当前接口的备用接口 * Input : Length -需要的字节数 * Output : None. * Return : 当'Length'的值为0,请求无效,返回0,当长度不为0,返回备用接口的地址 *******************************************************************************/ uint8_t *Standard_GetInterface(uint16_t Length) { if (Length == 0) //长度为0 { pInformation->Ctrl_Info.Usb_wLength = //设置端点通讯的长度为1字节 sizeof(pInformation->Current_AlternateSetting); return 0; } pUser_Standard_Requests->User_GetInterface(); //调用User_GetInterface函数,该函数在usb_prop.c中注册 return (uint8_t *)&pInformation->Current_AlternateSetting; //返回备用接口值的地址 }

我们可以对比下上面两个get函数,函数结构上都类似,起始获取配置或接口值都只要返回DEVICE_INFO *pInformation里的对应的值就可以了。
接下去是两个Set函数:

/******************************************************************************* * Function Name : Standard_SetConfiguration. * Description : 该函数用于设置配置值,主机发送该请求后,usb设备要配置自己的设备值 * Input : None. * Output : None. * Return : 当该请求被执行了,返回USB_SUCCESS * 当请求无效时,然会USB_UNSUPPORT *******************************************************************************/ RESULT Standard_SetConfiguration(void) { if ((pInformation->USBwValue0 <= //当配置值(即设备的编号)小于已使用的端点编号 Device_Table.Total_Configuration) && (pInformation->USBwValue1 == 0)//USBwValue是16bit,低8字节表示配置值,高8bit为0 && (pInformation->USBwIndex == 0)) /*call Back usb spec 2.0*/ //USBwIndex域用不到,固定为0 { pInformation->Current_Configuration = pInformation->USBwValue0; //Current_Configuration设置成要设置的配置值 pUser_Standard_Requests->User_SetConfiguration(); //调用User_SetConfiguration函数,该函数在usb_prop.c中注册 return USB_SUCCESS; } else { return USB_UNSUPPORT; } }

/******************************************************************************* * Function Name : Standard_SetInterface. * Description : 该函数用于设置接口值,主机该请求后,usn设备设置自己的接口值 * Input : None. * Output : None. * Return : 当请求被执行,返回USB_SUCCESS,当请求无效,返回USB_UNSUPPORT *******************************************************************************/ RESULT Standard_SetInterface(void) { RESULT Re; /*测试应用程序是否支持被选中的接口和备用接口,成功返回SUCCESS*/ Re = (*pProperty->Class_Get_Interface_Setting)(pInformation->USBwIndex0, pInformation->USBwValue0); if (pInformation->Current_Configuration != 0) //有不为0的配置值,如果配置值为0.则会让设备进入设置地址状态 { if ((Re != USB_SUCCESS) || (pInformation->USBwIndex1 != 0) //应用程序不支持,或16bit接口号的高8位不为0,或wValue的值不为0 || (pInformation->USBwValue1 != 0)) { return USB_UNSUPPORT; //返回USB_UNSUPPORT } //如果应用程序支持接口 else if (Re == USB_SUCCESS) { //调用User_SetInterface(),该函数在usb_prop.c里定义 pUser_Standard_Requests->User_SetInterface(); pInformation->Current_Interface = pInformation->USBwIndex0;//设置当前的接口值 pInformation->Current_AlternateSetting = pInformation->USBwValue0; //设置当前的备用接口,一般情况下设置为0 return USB_SUCCESS; } } return USB_UNSUPPORT; }

设置配置值或接口值的函数解析USB主机发送过来的标准请求数据,对于设置配置请求 USBwValue0存放着配置值;对于设置接口请求 USBwIndex0 就存放着接口值。
还有Standard_GetDescriptorData();是获取描述符的函数;

/******************************************************************************* * Function Name : DataStageOut. * Description : 数据阶段的控制写传输 * Input : None. * Output : None. * Return : None. *******************************************************************************/ void DataStageOut(void) { ENDPOINT_INFO *pEPinfo = &pInformation->Ctrl_Info; uint32_t save_rLength; save_rLength = pEPinfo->Usb_rLength; //获取要传输的长度 if (pEPinfo->CopyData && save_rLength) //缓冲区中有数据,且要传输的数据长度大于0 { uint8_t *Buffer; uint32_t Length; Length = pEPinfo->PacketSize; //端点缓冲区总的数据长度 if (Length > save_rLength) //要发送的数据长度小于总的数据长度 { Length = save_rLength; //Length等于要传输的数据长度 } Buffer = (*pEPinfo->CopyData)(Length); //获取数据缓冲的地址 pEPinfo->Usb_rLength -= Length; //计算剩余的长度 pEPinfo->Usb_rOffset += Length; //调整偏移量 #ifdef STM32F10X_CL PCD_EP_Read(ENDP0, Buffer, Length); #else PMAToUserBufferCopy(Buffer, GetEPRxAddr(ENDP0), Length);//从要发送的数据缓冲区Buffer拷贝Length数据到PMA缓冲区中 #endif /* STM32F10X_CL */ } if (pEPinfo->Usb_rLength != 0) //如果还有剩余的数据 { vSetEPRxStatus(EP_RX_VALID); //重新设置端点接收(相对主机而言)状态有效 SetEPTxCount(ENDP0, 0); //设置端点发送状态计数为0 vSetEPTxStatus(EP_TX_VALID); //设置发送状态有效,好让主机可以中断数据输出阶段 } /* Set the next State*/ if (pEPinfo->Usb_rLength >= pEPinfo->PacketSize) //如果要传输的长度大于端点的缓冲大小 { pInformation->ControlState = OUT_DATA; //说明还处于OUT_DATA数据阶段 } else //如果要传输的长度小于端点的缓冲大小 { if (pEPinfo->Usb_rLength > 0) //且还有剩余数据 { pInformation->ControlState = LAST_OUT_DATA; //说明这是最后要传输的数据了。 } else if (pEPinfo->Usb_rLength == 0) //如果已经没哟要传输的数据了 { pInformation->ControlState = WAIT_STATUS_IN; //进入WAIT_STATUS_IN状态 USB_StatusIn(); } } } /******************************************************************************* * Function Name : DataStageIn. * Description : 数据阶段的控制读传输 * Input : None. * Output : None. * Return : None. *******************************************************************************/ void DataStageIn(void) { ENDPOINT_INFO *pEPinfo = &pInformation->Ctrl_Info; //pEPinfo获取端点信息 uint32_t save_wLength = pEPinfo->Usb_wLength; //save_wLength为要接收的数据长度 uint32_t ControlState = pInformation->ControlState; //ControlState获取当前设备的控制状态 uint8_t *DataBuffer; uint32_t Length; if ((save_wLength == 0) && (ControlState == LAST_IN_DATA))//如果没有要接收的数据,且控制状态为LAST_IN_DATA最后数据状态 { if(Data_Mul_MaxPacketSize == TRUE) //如果要接收的数据长度是最大数据长度的整数倍,且小于数据缓冲区的大小 { Send0LengthData(); //说明没有数据可以接收了,重新使能TX ControlState = LAST_IN_DATA; //此时控制的状态为LAST_IN_DATA Data_Mul_MaxPacketSize = FALSE; //Data_Mul_MaxPacketSize标志为FALSE } else { ControlState = WAIT_STATUS_OUT; //没有可接收的的数据了,此时进入WAIT_STATUS_OUT状态 #ifdef STM32F10X_CL PCD_EP_Read (ENDP0, 0, 0); #endif /* STM32F10X_CL */ #ifndef STM32F10X_CL vSetEPTxStatus(EP_TX_STALL); //设置端点发送(相对于主机而言)状态为停止状态 #endif /* STM32F10X_CL */ } goto Expect_Status_Out; //程序跳转到Expect_Status_Out处 } Length = pEPinfo->PacketSize; //获取整个数据包的长度 ControlState = (save_wLength <= Length) ? LAST_IN_DATA : IN_DATA; //要接收的数据长度小于等于数据包长度,则是LAST_IN_DATA状态,否则是IN_DATA状态 if (Length > save_wLength) //总的数据包的长度大于要接收的数据长度 { Length = save_wLength; //Length等于要接收的数据长度 } DataBuffer = (*pEPinfo->CopyData)(Length); //获取数据缓冲区的地址 #ifdef STM32F10X_CL PCD_EP_Write (ENDP0, DataBuffer, Length); #else UserToPMABufferCopy(DataBuffer, GetEPTxAddr(ENDP0), Length);//从PMA缓冲区中拷贝Length个字节到DataBuffer地址去 #endif /* STM32F10X_CL */ SetEPTxCount(ENDP0, Length); //设置端点的发送(相对主机而言)状态计数值为Length,即接收到Length个数据 pEPinfo->Usb_wLength -= Length; //剩下的数据 pEPinfo->Usb_wOffset += Length; //调整偏移量 vSetEPTxStatus(EP_TX_VALID); //设置端点的发送状态有效,即可以继续接收数据 USB_StatusOut(); //设置端点接收(对主机而言)状态有效,好让主机可以中断的数据读阶段 Expect_Status_Out: pInformation->ControlState = ControlState; } /******************************************************************************* * Function Name : NoData_Setup0. * Description : 处理没有数据阶段的建立请求 * Input : None. * Output : None. * Return : None. *******************************************************************************/ void NoData_Setup0(void) { RESULT Result = USB_UNSUPPORT; uint32_t RequestNo = pInformation->USBbRequest; //获取请求代码 uint32_t ControlState; if (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT)) //标准请求,请求的接收者是设备 { /* Device Request*/ /* SET_CONFIGURATION*/ if (RequestNo == SET_CONFIGURATION) //收到设置配置请求 { Result = Standard_SetConfiguration(); //设置配置值 } /*SET ADDRESS*/ else if (RequestNo == SET_ADDRESS) //收到设置地址请求,wValue存放地址,wIndex必须为0,wLength必须为0 { if ((pInformation->USBwValue0 > 127) || (pInformation->USBwValue1 != 0)//设备地址没有在0~127 || (pInformation->USBwIndex != 0) //wValue没有为0 || (pInformation->Current_Configuration != 0)) //当前的配置值不为0,说明usb已经枚举过了 /* Device Address should be 127 or less*/ { ControlState = STALLED; //有如上不正确情况,设置控制状态为停止状态 goto exit_NoData_Setup0; } else { Result = USB_SUCCESS; //Result赋予USB_SUCCESS #ifdef STM32F10X_CL SetDeviceAddress(pInformation->USBwValue0); //设置设备的地址 #endif /* STM32F10X_CL */ } } /*SET FEATURE for Device*/ else if (RequestNo == SET_FEATURE) //如果是设置特性请求 { if ((pInformation->USBwValue0 == DEVICE_REMOTE_WAKEUP) \ && (pInformation->USBwIndex == 0)) //如要设置的是使能远程唤醒并且wIndex域为0 { Result = Standard_SetDeviceFeature(); //设置设备的特性 } else { Result = USB_UNSUPPORT; //否则Result赋予USB_UNSUPPORT } } /*Clear FEATURE for Device */ else if (RequestNo == CLEAR_FEATURE) //如果是清除特性请求 { if (pInformation->USBwValue0 == DEVICE_REMOTE_WAKEUP //如过要清除的是远程唤醒特性 && pInformation->USBwIndex == 0 //且wIndex域为0 && ValBit(pInformation->Current_Feature, 5)) //且当前设备的特性有远程唤醒特性 { Result = Standard_ClearFeature(); //则清除远程唤醒特性 } else { Result = USB_UNSUPPORT; //否则Result赋予USB_UNSUPPORT } } } /* Interface Request*/ else if (Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT))//标准请求,且请求的接收者是接口 { /*SET INTERFACE*/ if (RequestNo == SET_INTERFACE) //如果是设置接口请求 { Result = Standard_SetInterface(); //设置接口值 } } /* EndPoint Request*/ else if (Type_Recipient == (STANDARD_REQUEST | ENDPOINT_RECIPIENT))//标准请求,且请求的接收者是端点 { /*CLEAR FEATURE for EndPoint*/ if (RequestNo == CLEAR_FEATURE) //如果是清除特性请求 { Result = Standard_ClearFeature(); //清除端点的特性 } /* SET FEATURE for EndPoint*/ else if (RequestNo == SET_FEATURE) //如果是设置特性请求 { Result = Standard_SetEndPointFeature(); //设置端点的特性 } } else //不是标准请求或其他USB协议之外的一些请求 { Result = USB_UNSUPPORT; } if (Result != USB_SUCCESS) //如果处理请求不成功 { Result = (*pProperty->Class_NoData_Setup)(RequestNo); //看看是不是特殊类请求 if (Result == USB_NOT_READY) //如果USB忙,即上个请求还没有处理完 { ControlState = PAUSE; //设置状态为暂停 goto exit_NoData_Setup0; //程序跳到exit_NoData_Setup0处 } } if (Result != USB_SUCCESS) //如果不是特殊类请求 { ControlState = STALLED; //设置状态为停止状态 goto exit_NoData_Setup0; //程序跳到exit_NoData_Setup0处 } ControlState = WAIT_STATUS_IN; //进入WAIT_STATUS_IN状态 USB_StatusIn(); //这里其实是设置端点发送(相对于主机来说)状态有效,好接收状态阶段的数据 exit_NoData_Setup0: pInformation->ControlState = ControlState; //设置当前的状态 return; } /******************************************************************************* * Function Name : Data_Setup0. * Description : 处理有数据阶段的建立请求 * Input : None. * Output : None. * Return : None. *******************************************************************************/ 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; /*GET DESCRIPTOR*/ if (Request_No == GET_DESCRIPTOR) //如果是获取描述符的请求,获取描述符的接收者只能是设备 { if (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT))//标准请求,且请求的接收者是设备 { uint8_t wValue1 = pInformation->USBwValue1; //USBwValue0表示索引号,USBwValue1表示描述符的类型编号 if (wValue1 == DEVICE_DESCRIPTOR) //如果是设别描述符 { CopyRoutine = pProperty->GetDeviceDescriptor; //获取设备描述符 } else if (wValue1 == CONFIG_DESCRIPTOR) //如果是配置描述符 { CopyRoutine = pProperty->GetConfigDescriptor; //获取配置描述符 } else if (wValue1 == STRING_DESCRIPTOR) //如果是字符串描述符 { CopyRoutine = pProperty->GetStringDescriptor; //获取字符串描述符 } /* End of GET_DESCRIPTOR */ } } /*GET STATUS*/ else if ((Request_No == GET_STATUS) && (pInformation->USBwValue == 0)//如果是获取状态请求,且wValue域为0 && (pInformation->USBwLength == 0x0002) && (pInformation->USBwIndex1 == 0)) { /* GET STATUS for Device*/ if ((Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT))//标准请求,请求的接受者是设备 && (pInformation->USBwIndex == 0)) //且wIndex域为0 { CopyRoutine = Standard_GetStatus; //函数指针指向Standard_GetStatus函数 } /* GET STATUS for Interface*/ else if (Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT))//标准请求,且请求的接收者是接口 { if (((*pProperty->Class_Get_Interface_Setting)(pInformation->USBwIndex0, 0) == USB_SUCCESS)//测试接口和备用接口是否支持 && (pInformation->Current_Configuration != 0)) //且当前的配置值不为0 { CopyRoutine = Standard_GetStatus; //函数指针指向Standard_GetStatus函数 } } /* GET STATUS for EndPoint*/ else if (Type_Recipient == (STANDARD_REQUEST | ENDPOINT_RECIPIENT))//标准请求,且请求的接收者是端点 { Related_Endpoint = (pInformation->USBwIndex0 & 0x0f); //获取端点号,D0~D3表示端点号 Reserved = pInformation->USBwIndex0 & 0x70; //获取保留值,D4~D6是保留值,必须为0 if (ValBit(pInformation->USBwIndex0, 7)) //如果D7为1,表示是输入 { /*Get Status of endpoint & stall the request if the related_ENdpoint is Disabled*/ Status = _GetEPTxStatus(Related_Endpoint); //获取该端点的发送状态 } else { Status = _GetEPRxStatus(Related_Endpoint); //获取该端点的接收状态 } if ((Related_Endpoint < Device_Table.Total_Endpoint) && (Reserved == 0)//端点号小于总端点数,保留值正确 && (Status != 0)) //且端点有效 { CopyRoutine = Standard_GetStatus; //函数指针指向Standard_GetStatus函数 } } } /*GET CONFIGURATION*/ else if (Request_No == GET_CONFIGURATION) //如果是获取配置请求 { if (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT))//标准请求,且请求的接收者是设备 { CopyRoutine = Standard_GetConfiguration; //函数指针指向Standard_GetConfiguration函数 } } /*GET INTERFACE*/ else if (Request_No == GET_INTERFACE) //如果是获取接口请求 { if ((Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT))//标准请求,且请求的接收者是接口 && (pInformation->Current_Configuration != 0) && (pInformation->USBwValue == 0)//当前的配置值不为0,wValue域的值为0 && (pInformation->USBwIndex1 == 0) && (pInformation->USBwLength == 0x0001) //wIndex1域的值为0,并且数据长度为1 && ((*pProperty->Class_Get_Interface_Setting)(pInformation->USBwIndex0, 0) == USB_SUCCESS))//支持接口和备用接口 { CopyRoutine = Standard_GetInterface; //函数指针指向Standard_GetInterface函数 } } if (CopyRoutine) //该函数指针不为空 { pInformation->Ctrl_Info.Usb_wOffset = wOffset; //设置偏移量 pInformation->Ctrl_Info.CopyData = CopyRoutine; //注册处理函数 /* sb in the original the cast to word was directly */ /* now the cast is made step by step */ (*CopyRoutine)(0); //执行该函数 Result = USB_SUCCESS; } else //该函数指针为空 { Result = (*pProperty->Class_Data_Setup)(pInformation->USBbRequest);//说明不是标准请求,则是特殊类请求,调用Class_Data_Setup函数 if (Result == USB_NOT_READY) //如果USB忙,表示处理上一次请求 { pInformation->ControlState = PAUSE; //设置状态为暂停 return; } } if (pInformation->Ctrl_Info.Usb_wLength == 0xFFFF) //如果要发送的数据长度为0xffff { /* Data is not ready, wait it */ pInformation->ControlState = PAUSE; //设置状态为暂停 return; } if ((Result == USB_UNSUPPORT) || (pInformation->Ctrl_Info.Usb_wLength == 0))//如果没有检测到USB或没有要传输的数据 { /* Unsupported request */ pInformation->ControlState = STALLED; //设置控制状态为停止 return; } if (ValBit(pInformation->USBbmRequestType, 7)) //如果是输入状态,即设备到主机 { /* Device ==> Host */ __IO uint32_t wLength = pInformation->USBwLength; //获取数据过程要传输的字节数 /* Restrict the data length to be the one host asks for */ 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赋0 Data_Mul_MaxPacketSize = FALSE; } else if ((pInformation->Ctrl_Info.Usb_wLength % pProperty->MaxPacketSize) == 0)//如果要发送的数据包是最大数据包的整数倍 { Data_Mul_MaxPacketSize = TRUE; //Data_Mul_MaxPacketSize置1 } } pInformation->Ctrl_Info.PacketSize = pProperty->MaxPacketSize;//端点数据包的长度设置为最大数据包长度 DataStageIn(); //调用数据阶段控制写函数 } else //如果是输出状态,即主机到设备 { pInformation->ControlState = OUT_DATA; //设置控制的状态为OUT_DATA vSetEPRxStatus(EP_RX_VALID); //设置端点接收装塔斯有效以下次接收数据 } return; } /******************************************************************************* * Function Name : Setup0_Process * Description : 建立阶段的数据处理Get the device request data and dispatch to individual process. * Input : None. * Output : None. * Return : Post0_Process. *******************************************************************************/ 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 /* STM32F10X_CL */ if (pInformation->ControlState != PAUSE) //控制状态不是暂停 { /*为什么USBbmRequestType和USBbRequest两个域在一个32位的地址中?*/ pInformation->USBbmRequestType = *pBuf.b++; //获取一个字节的bmRequestType pInformation->USBbRequest = *pBuf.b++; //获取一个字节的bRequest */ pBuf.w += offset; //因为STM32是32位处理器,所以地址也是32位的,所以跳过后16位 pInformation->USBwValue = ByteSwap(*pBuf.w++); //获取2字节的wValue值并该成小端模式 pBuf.w += offset; //因为STM32是32位处理器,所以地址也是32位的,所以跳过后16位 pInformation->USBwIndex = ByteSwap(*pBuf.w++); //获取2字节的wIndex值并修改成小端模式 pBuf.w += offset; //因为STM32是32位处理器,所以地址也是32位的,所以跳过后16位 pInformation->USBwLength = *pBuf.w; //获取2字节的wLength } pInformation->ControlState = SETTING_UP; //设置控制的状态为建立状态SETTING_UP if (pInformation->USBwLength == 0) { /* Setup with no data stage */ NoData_Setup0(); //处理没有数据阶段的建立请求 } else { /* Setup with data stage */ Data_Setup0(); //处理有数据阶段的建立请求 } return Post0_Process(); } /******************************************************************************* * Function Name : In0_Process * Description : 处理默认端点的所有IN令牌包 * Input : None. * Output : None. * Return : Post0_Process. *******************************************************************************/ uint8_t In0_Process(void) { uint32_t ControlState = pInformation->ControlState; if ((ControlState == IN_DATA) || (ControlState == LAST_IN_DATA)) //状态在IN_DATA或LAST_IN_DATA { DataStageIn(); //处理控制写传输 /* ControlState may be changed outside the function */ ControlState = pInformation->ControlState; //获取处理后的状态 } else if (ControlState == WAIT_STATUS_IN) //状态在WAIT_STATUS_IN { if ((pInformation->USBbRequest == SET_ADDRESS) && //设置地址请求 (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT))) //标准请求,请求的接收者是设备 { SetDeviceAddress(pInformation->USBwValue0); //设置USB设备地址 pUser_Standard_Requests->User_SetDeviceAddress(); //调用User_SetDeviceAddress函数,注册地址信息 } (*pProperty->Process_Status_IN)(); //调用Process_Status_IN()处理IN令牌包 ControlState = STALLED; //设置状态为停止 } else //状态不是WAIT_STATUS_IN { ControlState = STALLED; //设置状态为停止 } pInformation->ControlState = ControlState; //获取处理后的控制状态 return Post0_Process(); } /******************************************************************************* * Function Name : Out0_Process * Description : 处理默认端点上的所有OUT令牌包 * Input : None. * Output : None. * Return : Post0_Process. *******************************************************************************/ uint8_t Out0_Process(void) { uint32_t ControlState = pInformation->ControlState; //获取控制状态 if ((ControlState == IN_DATA) || (ControlState == LAST_IN_DATA)) //如果是IN_DATA或LAST_IN_DATA状态 { /* host aborts the transfer before finish */ ControlState = STALLED; //设置状态为停止 } else if ((ControlState == OUT_DATA) || (ControlState == LAST_OUT_DATA))//如果是OUT_DATA或LAST_OUT_DATA { DataStageOut(); //处理控制写传输 ControlState = pInformation->ControlState; //获取处理后的控制状态 } else if (ControlState == WAIT_STATUS_OUT) //如果控制状态是WAIT_STATUS_OUT { (*pProperty->Process_Status_OUT)(); //调用Process_Status_OUT()处理OUT令牌包 #ifndef STM32F10X_CL ControlState = STALLED; //然后设置状态为停止状态 #endif /* STM32F10X_CL */ } /* Unexpect state, STALL the endpoint */ else { ControlState = STALLED; } pInformation->ControlState = ControlState; //获取处理后的控制状态 return Post0_Process(); } /******************************************************************************* * Function Name : Post0_Process * Description : 为防止错误,停止端点0Stall the Endpoint 0 in case of error. * Input : None. * Output : None. * Return : 如果控制状态是PAUSE,返回0;如果不是返回1 *******************************************************************************/ uint8_t Post0_Process(void) { #ifdef STM32F10X_CL USB_OTG_EP *ep; #endif /* STM32F10X_CL */ SetEPRxCount(ENDP0, Device_Property.MaxPacketSize); //设置端点0的接收计数值为最大包长度 if (pInformation->ControlState == STALLED) //如果当前控制状态是停止状态 { vSetEPRxStatus(EP_RX_STALL); //设置端点接收状态为停止 vSetEPTxStatus(EP_TX_STALL); //设置端点发送状态为停止 } #ifdef STM32F10X_CL else if ((pInformation->ControlState == OUT_DATA) || //如果控制是OUT_DATA或WAIT_STATUS_OUT (pInformation->ControlState == WAIT_STATUS_OUT)) { ep = PCD_GetInEP(0); ep->is_in = 0; OTGD_FS_EP0StartXfer(ep); vSetEPTxStatus(EP_TX_VALID); } else if ((pInformation->ControlState == IN_DATA) || //如果控制是OUT_DATA或WAIT_STATUS_OUT (pInformation->ControlState == WAIT_STATUS_IN)) { ep = PCD_GetInEP(0); ep->is_in = 1; OTGD_FS_EP0StartXfer(ep); } #endif /* STM32F10X_CL */ return (pInformation->ControlState == PAUSE); } /******************************************************************************* * Function Name : SetDeviceAddress. * Description : 设置设备和所有使用过的端点地址 * Input : Val:设备地址 * Output : None. * Return : None. *******************************************************************************/ void SetDeviceAddress(uint8_t Val) { #ifdef STM32F10X_CL PCD_EP_SetAddress ((uint8_t)Val); #else uint32_t i; uint32_t nEP = Device_Table.Total_Endpoint; //获取所有已使用的端点数 /* set address in every used endpoint */ for (i = 0; i < nEP; i++) { _SetEPAddress((uint8_t)i, (uint8_t)i); //设置这些端点的地址 } /* for */ _SetDADDR(Val | DADDR_EF); //设置设备的地址,并且将EF位置位,使能USB模块位 #endif /* STM32F10X_CL */ } /******************************************************************************* * Function Name : NOP_Process * Description : 没有处理函数 * Input : None. * Output : None. * Return : None. *******************************************************************************/ void NOP_Process(void) { }

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32 usb_core.c分析 的相关文章

  • 查找带有 USB 设备 VID/PID 的 /dev 条目

    我想制作一个程序来检测哪些 dev sd 条目链接到已知的 USB VID PID 对 你知道我如何获得 USB 记忆棒的 VID PID 吗 dev sd 您可以使用udevadm为了这 在输出中udevadm info q proper
  • 无法使用 OpenCV 从辅助网络摄像头的 VideoCapture 读取帧

    Code 与主网络摄像头 设备 0 完美配合的简单示例 VideoCapture cap 0 if cap isOpened std cout lt lt Unable to read stream from specified devic
  • 如何禁用 Android 设备 USB 端口

    我正在尝试搜索是否有一种方法可以禁用 Android 设备 USB 端口 主要是软件级别 因此用户仍然可以为 Android 设备充电 但无法再与 PC 通信 我得到了一些线索link1 https groups google com fo
  • 为什么我可以访问另一个包的其他子类中的 Finalize() 方法?

    我是 Java 新手 第一次尝试学习 Java 我的简单问题是关于java lang Object 中的finalize 方法 为什么我可以访问其他类中唯一的受保护方法 而不是其他受保护方法 我的导师告诉我 受保护仅在其类 同一包及其子类中
  • 如何阻止 Linux 初始化 USB HID 设备

    我有一个 USB HID 设备 可以在两种不同的模式下工作 模式的选择基于发送给它的 USB 枚举 初始化数据包的顺序 我使用的是运行 Raspbian 的 Raspberry Pi 3 但是如果我为桌面 Ubuntu 发行版编译代码 我也
  • 如何拦截并翻译USB事件

    我想使用飞利浦 LFH 2330 查看图像 使用 Windows Image Viewer 或其他查看器 如 IrfanView 等 LFH 2330 是一款带有四个踏板的脚踏控制器 参见here http www aaaaudio net
  • 使用“设备过滤器”解决方案时如何处理 Android 上的 USB 权限对话框事件?

    当我将 已知 USB 设备连接到 Android 手机时出现的自动权限对话框中 用户按下 确定 或 取消 时 我试图处理该事件 我正在使用 android usb host 库 可以在 Android 手机和设备之间发送和接收 此外 我使用
  • 通过 USB 模拟 UART

    有谁知道是否可以通过 USB 模拟 UART 简单串行发送和接收 这将如何实现 我在 Microchip 网站上找到了这个链接 但不是很容易找到 http www microchip com forums m522571 print asp
  • STM32 上的 ADC 单次转换

    我正在研究 STM32 F103x 上的 ADC 编程 并从最简单的情况 单次转换开始 测量内部温度传感器 连接到 ADC1 的值 并使用 USART 将其发送到 COM 端口 目标似乎很明确 但是当我尝试将源代码下载到闪存时 它不会向 C
  • 使用 python 检测 Windows 10 上的 USB 设备插入

    我无法获取以下代码检测USB设备插入 http timgolden me uk python win32 how do i detect device insertion html在我的 Windows 10 64 位 计算机上使用 Pyt
  • 如何在 C# 中获取每个核心的 CPU 负载?

    如何在 C 中获取每个核心 四核 cpu 的 CPU 负载 谢谢 您可以使用 WMI 或 System Diagnostics 命名空间 从那里您可以获取任何您想要的性能计数器 但是需要一秒钟 1 1 5秒 来初始化这些计数器 读取值是可以
  • 是否有可通过 USB 密钥在 Mac OS X 10.6 上运行的便携式 python 解释器?

    我一直在努力寻找一个可以通过工作计算机上的 USB 密钥运行的便携式解释器 Work comp 运行的是 Mac OS X 10 6 环境相当受限 无法访问终端 无法安装应用程序 但我知道便携式应用程序可以从 USB 驱动器运行 我一直在使
  • 在 Mac 上通过 USB 访问 iOS 设备

    我有一个移动应用程序需要将文件传输到数据库 然而 其规范之一是 如果用户没有设置无线网络 则应该能够将其插入 Mac 并将文件传输到数据库 然而 我遇到的问题是如何将上述文件从 iPad 上通过 USB 传输到计算机上 上周我研究了各种解决
  • OSX:如何从 IOUSBDeviceInterface 或位置 id 获取卷名称(或 bsd 名称)

    我正在尝试编写一个应用程序 将特定的 USB 字符串描述符 USB 大容量存储设备 与其卷或 bsd 名称相关联 因此 代码会遍历所有连接的 USB 设备 获取字符串描述符并从其中之一提取信息 我想获取这些 USB 设备的卷名 我找不到合适
  • 使用 adb 连接到 LG 手机时出现问题 (Mac OS X 10.7.5)

    当我跑步时adb devices没有设备显示为已连接 我的设备是运行 4 4 2 的 LG Optimus Exceed 2 周围有很多这样的帖子 所以这就是我所做的 我正在使用电话附带的数据线 它会充电并尝试同步照片 因此这不是问题 切换
  • Windows 8.1 上的 Pyusb - 没有可用的后端 - 如何安装 libusb?

    使用 pyinstaller 3 1 python 2 7 9 和 tkinter 尝试使用 pyusb 而不是 pyserial 但没有可用的后端 调查Windows 上的 Pyusb 没有可用的后端 https stackoverflo
  • STM32F0、ST-link v2、OpenOCD 0.9.0:打开失败

    我在用着发射台 http www ti com ww en launchpad about htmlgcc arm none eabi 4 9 2015q2 为 STM32F0 进行编译 现在我想使用该集合中的 arm none eabi
  • USBInterfaceOpen总是报kIOReturnExclusiveAccess错误

    最近我遇到了这个问题 很头疼 我已经在这个问题上花了一个星期了 但仍然失败 希望您能帮我把这块石头踢开 非常感谢 我的问题 我们公司为iPhone生产USB存储设备 实际上这个存储设备中有一个SDCard 现在 我们想要开发一个 Mac 应
  • 如何在 C# 中从 USB 令牌读取证书

    我有一个 USB 令牌 其中包含一个加密证书 该证书具有公钥和私钥 现在我想用 C 创建一个应用程序 通过它我可以找到可访问的证书信息 当我插入 USB 令牌时 它会被检测到 但计算机部分上没有显示任何驱动器 就像闪存驱动器一样 如何从 U
  • USB 端口速度 Linux [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 如何以编程方式确定运行 Linux 内核的嵌入式设备中的 USB 端口速度 你可以阅读 sys bus usb devices usb s

随机推荐