图1 展示了一个典型的USB应用与USB-FS-Device library的关系图。我们可以看出图中由3个层构成分别是:外围硬件(hardware)、STM32_USB-FS_Device_Lib和用户层(User application)。我们从下到上来分析:
图1 典型的USB应用与USB-FS-Device library的关系图
1.外围硬件(hardware)
就是我们的购买的芯片STM32F10XXX和开发板
2 STM32_USB-FS_Device_Lib
就是STM提供给我们的The USB-FS-Device library固件库,它由STM32_USB FS_Device_ Driver和Application Interface layer两个部分组成。
其中STM32_USB-FS_Device_Driver这层管理USB的硬件设备和USB标准协议的直接交互,它又由Low Layer 和 Medium Layer两个层组成;Application Interface layer-High Layer这层又叫High Layer层,它在固件库核和应用提供给用户一个完整的接口。
图2 是我给出的STM32_USB-FS-Device_Lib_V3.1.0 结构图,下面我们将对这个整个结构的运行机理分析,然后结构逐层给出具体含义。
图2 STM32_USB-FS-Device_Lib_V3.1.0 结构图
和其他的接口一样,当受到USB的中断后,进入stm32f10x_it.c中的USB_LP_CAN1_RX0
_IRQHandler()和USB_HP_CAN1_TX_IRQHandler()中断服务子程序。其中优先级高的由USB_HP_CAN1_TX_IRQHandler处理,优先级低的由USB_LP_CAN1_RX0_ IRQHandler处理。
对于USB_HP_CAN1_TX_IRQHandler函数,它直接调用usb_int (.h , .c)中的CTR_HP(),然后根据发送和接受数据,它调用usb_endp(.c)中的EPX_IN_Callback()或EPX_OUT_ Callback()函数。对于EPX_IN_Callback和EPX_OUT_Callback()这14个函数(X=1,2...7)它们在usb_conf(.h)中通过
#define EPX_IN_Callback NOP_Process
#define EPX_OUT_Callback NOP_Process
的形式,来由用户决定是否提供具体的实现并调用。而将它们和CTR_HP联系在一起的操作,在usb_istr(.h,.c)中以下面的形式给出:
void (*pEpInt_IN[7])(void) ={
EP1_IN_Callback,
...
EP7_IN_Callback,};
void (*pEpInt_OUT[7])(void) ={
EP1_OUT_Callback,
...
EP7_OUT_Callback,};
对于USB_HP_CAN1_TX_IRQHandler函数,它直接调用usb_istr(.h,.c)中的USB_Istr(),USB_Istr()根据具体的请求决定是调用usb_istr(.h,.c)中下面函数
void CTR_Callback(void);
void DOVR_Callback(void);
void ERR_Callback(void);
void WKUP_Callback(void);
void SUSP_Callback(void);
void RESET_Callback(void);
void SOF_Callback(void);
void ESOF_Callback(void);
还是调用usb_int(.h,.c)中的void CTR_LP(void)。对于上面的这个函数是否给出定义,是由用户在usb_conf(.h)中,通过下面的宏决定的
/*#define CTR_CALLBACK*/
/*#define DOVR_CALLBACK*/
/*#define ERR_CALLBACK*/
/*#define WKUP_CALLBACK*/
/*#define SUSP_CALLBACK*/
/*#define RESET_CALLBACK*/
#define SOF_CALLBACK
/*#define ESOF_CALLBACK*/
如果调用了 CTR_LP()函数,CTR_LP()函数中如果不是端点0的请求,则和CTR_LP一样的顺序处理;如果是端点0,它调用usb_core(.h,.c)中的
uint8_t Setup0_Process(void);
uint8_t Post0_Process(void);
uint8_t Out0_Process(void);
uInt8_t In0_Process(void);
如果是标准的请求,便调用usb_core(.h,.c)中的下面的函数
RESULT Standard_SetEndPointFeature(void);
RESULT Standard_SetDeviceFeature(void);
uint8_t *Standard_GetConfiguration(uint16_t Length);
RESULT Standard_SetConfiguration(void);
uint8_t *Standard_GetInterface(uint16_t Length);
RESULT Standard_SetInterface(void);
Uint8_t *Standard_GetDescriptorData(uint16_t ...);
uint8_t *Standard_GetStatus(uint16_t Length);
RESULT Standard_ClearFeature(void);
void SetDeviceAddress(uint8_t);
这些函数,又调用USER_STANDARD_REQUESTS结构指定的中,用户在usb_prop(.h,.c)中定义的函数。如果不是标准请求,则调用DEVICE_PROP结构指定的中,用户在usb_prop(.h,.c)中定义的函数其他一些函数。
下面我再按文件分析一次:
usb_conf.h
usb_conf.h中的#define IMR_MSK (CNTR_CTRM | CNTR_SOFM | CNTR_RESETM )来决定USB_CNTR寄存器中的那个USB相关中断启动还是屏蔽。
usb_istr.c
进入USB_Istr()后,首先检测是否是CTR位中断,即完成一次数据的正处传输,如果是,并且相应IMR_MSK没有屏蔽,就调用usb_int,c中的CTR_LP()函数,如果定义了CTR_CALLBACK,则调用本文件中定义的CTR_Callback()函数。
然后检测是否是RESET位中断,如果是,并且相应的中断没有屏蔽,则首先清楚USB_ISTR寄存中相应的中断位,然后调用用户在usb_prop.c的Device_Property结构体中填充的相应的函数;如果定义了宏RESET_CALLBACK还将调用本文件中定义的RESET_Callback()函数。
其他的类似。
注意:值得我们注意的是如果缓冲区的数据溢出,则不会调用 CTR_LP()和CTR_Callback(),这样的话,我们也就没有机会来处理这些数据,所以,如果你想处理缓冲区溢出时的数据你必须定义DOVR_CALLBACK,并提供DOVR_Callback()函数。
usb_int.h
进入CTR_LP()函数后,首先检测发生中断断点的ID如果是端点0,则根据是输入还是输出调用。如果是IN,则调用usb_core(.h,.c)中的In0_Process()函数;否则检测是否是SETUP,是的话调用usb_core(.c)中的Setup0_Process()函数,不是的话调用usb_core(c)中的Out0_Process()函数。如果不是端点0则调用usb_endp(.c)中 EPX_IN_Callback()和EPX_OUT_Callback()。
进入CTR_HP()后,因为它只接受同步传输和双缓冲区的批量传输中的,所以它直接检测是IN还是OUT,并调用usb_endp(.c)中 EPX_IN_Callback()和EPX_OUT_Callback()。
usb_core(.h,.c)
Setup0_Process()
进入Setup0_Process()函数后,如果现在的CONTROL_STATE状态不是PAUSE则,填充pInformation指向的DEVICE_INFO结构体,然后设置CONTROL_STATE现在状态为SETTING_UP,然后根据数据的长度是否为0调用NoData_Setup0()或者 Data_Setup0()函数,最后调用Post0_Process()????????。
NoData_Setup0()
进入NoData_Setup0()后,首先判断是否接收者是设备并且是标准请求,如果是根据请求的类型SET_CONFIGURATION、SET_ADDRESS、SET_FEATURE和CLEAR_FEATURE来调用该文件中的相应函数;然后判断是否接收者是接口并且是标准请求,如果是根据是否是SET_INTERFACE来调用文件中相应的函数;其次判断是否接收者是端点并且是标准请求,如果是则根据CLEAR_FEATURE和SET_FEATURE来调用相应的本文件中函数。否则结果设置成USB_UNSUPPORT。
接下来,如果结果是USB_UNSUPPORT,则调用usb_prop(.h,.c)中DEVICE_PROP结构体中填充的RESULT (*Class_NoData_Setup)(uint8_t RequestNo)函数,我们就在该函数中处理不是类库中已经实现的请求。
Data_Setup0()
进入Data_Setup0()后,首先检测请求代码是否是GET_DESCRIPTOR,如果是根据描述符的请求,分别调用usb_prop(.h,.c)中DEVICE_PROP结构体中填充的设备描述符、配置描述符和字符串描述符的函数;然后检测请求代码是否是GET STATUS,如果是则调用Standard_GetStatus函数;其次检测是否是GET_CONFIGURATION和GET_INTERFACE,如果是调用相关函数。
如果不满足上面条件则调用调用usb_prop(.h,.c)中DEVICE_PROP结构体中填充的RESULT (*Class_Data_Setup)(uint8_t RequestNo)函数,我们就在该函数中处理不是类库中已经实现的请求。
最后根据请求设置相应状态,用于下次通信。
上一篇:USB通讯的执行过程 - STM32 USB设计
下一篇:SD卡升级——SDIO_IAP实验
推荐阅读最新更新时间:2024-11-10 20:20