您的位置 首页 测评

怎么运用STM32的USB库支撑操控端点0

首先我们先回顾一下控制端点的传输方式:控制端点的传输有三个阶段,SETUP阶段、数据阶段和状态阶段;数据阶段又分为数据入(DATAIN)和数

首要咱们先回忆一下操控端点的传输方法:

操控端点的传输有三个阶段,SETUP阶段、数据阶段和状况阶段;数据阶段又分为数据入(DATA IN)和数据出(DATA OUT),操控端点传输可以没有数据阶段;状况阶段有状况入(STATUS IN)和状况出(STATUS OUT)。
总结起来,操控端点有如下三种或许的传输进程(以下括号中的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)
这儿做一个约好,把上述进程一界说为“数据入进程”,进程二界说为“数据出进程”,进程三界说为“无数据进程”。一切的USB操控端点的数据传输都可以并且只用这三种传输进程表明。HID的SET_REPORT是数据出进程,HID的GET_REPORT是数据入进程,USB的GET DEVICE DESCRIPTOR是数据入进程,USB的SET CONFIGURATION是无数据进程,等等。
接下来,咱们看看STM32USB库是怎么处理操控端点0的传输。
依据USB协议,每个SETUP包都由8个字节构成,用户程序可以经过结构体Device_Info(类型DEVICE_INFO)拜访SETUP包的数据,由于在整个的USB处理中都要用到结构体Device_Info的内容,库中界说了一个大局的指针pInformation指向这个结构体,用户可以经过这个指针拜访结构体的内容。
对应SETUP包的8个字节,用户可以用下述方法拜访:
pInformation->USBbmRequestType (字节类型)
pInformation->USBbRequest (字节类型)
pInformation->USBwValue (双字节类型)
pInformation->USBwIndex (双字节类型)
pInformation->USBwLength (双字节类型)
运用pInformation->USBwValue0拜访wValue的低字节,pInformation->USBwValue1拜访wValue的高字节。
运用pInformation->USBwIndex0拜访USBwIndex的低字节,pInformation->USBwIndex1拜访USBwIndex的高字节。
运用pInformation->USBwLength0拜访USBwLength的低字节,pInformation->USBwLength1拜访USBwLength的高字节。
经过剖析SETUP包的8个字节,可以判别出一个SETUP的传输进程是归于数据入进程、数据出进程仍是无数据进程。STM32的USB库中处理了一切的USB协议文本中界说的规范SETUP指令,关于USB协议文本中未界说的指令,USB库依照数据入进程、数据出进程或无数据进程经过回调函数交给用户程序处理。
大局变量Device_Property(DEVICE_PROP类型)封装了一切的回调函数,DEVICE_PROP界说如下:
typedef struct _DEVICE_PROP
{
void (*Init)(void); // 设备初始化回调函数
void (*Reset)(void); // USB复位回调函数
void (*Process_Status_IN)(void); // STATUS_IN阶段处理回调函数
void (*Process_Status_OUT)(void); // STATUS_OUT阶段处理回调函数
RESULT (*Class_Data_Setup)(u8 RequestNo); // 数据入/出进程处理回调函数
RESULT (*Class_NoData_Setup)(u8 RequestNo); // 无数据进程处理回调函数
RESULT (*Class_Get_Interface_Setting)(u8 Interface, u8 AlternateSetting); // GET_INTERFACE 回调函数
u8* (*GetDeviceDescriptor)(u16 Length); // GET_DEVICE_DESCRIPTION回调函数
u8* (*GetConfigDescriptor)(u16 Length); // GET_CONFIGURATION_DESCRIPTION回调函数
u8* (*GetStringDescriptor)(u16 Length); // GET_STRING_DESCRIPTION回调函数
u8 MaxPacketSize; // 最大包长度
} DEVICE_PROP;
结合SETUP的三种传输进程,用户经过完结不同的回调函数即可完结对各种USB类指令的处理,下面以HID的SET REPORT为例阐明。
在介绍详细完结之前,先介绍一下另一个回调函数CopyRoutine的概念,这个函数的原型是:
u8 *CopyRoutine(u16 length); // 回来一个缓冲区指针
USB库经过这个函数取得用户的数据缓冲区地址,然后可以在数据出进程中把收到的数据拷贝到用户缓冲区,或在数据入进程中把用户缓冲区的数据拷贝到USB发送缓冲区。每个数据出进程或许有若干次DATA_OUT传输,USB库每完结一次这样的传输都会调用一次回调函数CopyRoutine,参数length是本次传输所收到的数据字节数目,CopyRoutine有必要回来一个缓冲区指针,这个缓冲区有必要可以包容length字节的数据,CopyRoutine回来到USB库之后,USB库将把收到的数据拷贝到用户指定的缓冲区。相同每个数据入进程也或许有若干次DATA_IN传输,每次需求向主机传输数据时,USB库都会调用一次回调函数CopyRoutine,参数length是本次传输所要发送的数据字节数目,CopyRoutine有必要回来一个缓冲区指针,这个缓冲区中有必要包括要求的数据字节,USB库将把用户缓冲区的数据拷贝到USB缓冲区并择机发送出去。
当以length=0调用CopyRoutine时,CopyRoutine需求回来用户缓冲区的长度,由于CopyRoutine的回来类型是一个指针,所以需求经过类型的强制转化回来缓冲区长度。这个功用是为了处理用户缓冲区的长度与主机SETUP数据恳求长度不符的状况,而不至于形成用户缓冲区的溢出。
介绍完上述若干概念和回调函数,再看SET_REPORT的完结就很简单了。
SET_REPORT是一个数据出进程,因而需求完结一个Class_Data_Setup回调函数,示例如下:
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长度和Buffer长度为10
return My_Buffer;
}
上面介绍的CopyRoutine用于把屡次传输的数据包合并到一个完好的缓冲区中,因而只要到STATUS阶段才可以知道一次SETUP传输是否完毕,所以用户程序需求在回调函数 Process_Status_IN中处理从SET_REPORT接收到的数据。由于一切的回调函数都是USB中止处理的一部分,所以更好的方法是在 Process_Status_IN中设置一个符号,然后在用户主程序中判别这个符号并做处理。
上述暗示代码是以My_Buffer长度为10字节为例,而USB库的默许包长度为16字节,因而My_Data_Request并没有多包的处理。
关于多包的缓冲区处理的暗示代码可所以这样的:
u8 *My_Data_Request(u16 length)
{
if (length == 0)
return (u8*)100; // 假定你的REPORT长度和Buffer长度为100
return &My_Buffer[pInformation->Ctrl_Info.Usb_wOffset];
}
这儿有一个库中运用的变量pInformation->Ctrl_Info.Usb_wOffset,这个变量会在传输每个数据包时分由库中的程序按数据包长度添加,如最大包长为16字节时,第一次调用My_Data_Request时Usb_wOffset=0,第2次调用 My_Data_Request时Usb_wOffset=16,第三次调用My_Data_Request时Usb_wOffset=32,依此类推。这样就可以运用Usb_wOffset作为My_Buffer的下标从My_Data_Request回来相应的缓冲区地址。
前面现已阐明,参数length是用于检测缓冲区长度是否满足,假如你有满足长的缓冲区,可以不用检测,上述示例中运用了一个固定的缓冲区,所以不用运用参数length检测缓冲区长度。
留意,STM32的USB库规划成以回调函数处理用户指令恳求,包括类指令恳求,是为了可以明晰区域分库程序和用户程序,使这两者不会混在一同,这样的优点是十分显着的,当USB库需求更新晋级时,只需替换掉相应的程序模块,而不用修正用户现已完结的程序。
以上的介绍都可以在STM32 USB库的阐明手册中找到。

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/ceping/254520.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部