历史上的今天
今天是:2024年11月10日(星期日)
2020年11月10日 | 深入解析STM32_USB-FS-Device_Lib库V0.2
2020-11-10 来源:eefocus
图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)函数,我们就在该函数中处理不是类库中已经实现的请求。
最后根据请求设置相应状态,用于下次通信。
史海拾趣
|
Processing Rule: Broken-Net Constraint ( ( On the board) ) Violation Net netc17_1 is broken into 2 sub-nets. Routed To 0.00% &n ...… 查看全部问答> |
|
在Activesync同步时,无法用USB连接PC,当插入USB时,PC机上提示发现新硬件,硬件可以使用,这说明我的驱动没有问题,选了组件ActiveSync 和usb serial ,系统时间日期设置好了,拔下USB口再插上无数次,Pc机子和目标机重启无数次,每次目标机上显 ...… 查看全部问答> |
|
我想使用vxworks的WDB来进行调试,可是网口怎么挂也挂不上,所以没办法改用串口 现在串口可以挂上了,但是报了一个错:Error: Cannot get target toolname (symbol error) 不晓得该如何解决,希望前辈指点! 具体信息如下: Targ ...… 查看全部问答> |
|
紧急求助:pxa270下SDIO wifi模组的驱动 Marvell 8686 请问谁能发给我一份在PXA270下可以使用的SDIO WIFI模组的驱动,模组型号是USI的WM-G-MR-09,模组使用的芯片是Marvell 8686. 我手里有厂商给的驱动,名称是:SD-8686-WM60-ARMV4I-9.70.3.p23-38.p44.CAB,但是这份是基于PXA310和wince6.0的驱动,我 ...… 查看全部问答> |
|
代码如下: #define SVC_STACK_LENGTH 0 StackSvc DCD SvcStackSpace+(SVC_STACK_LENGTH-1)*4 AREA MyStack,DATA,NOINIT,ALIGN=2 SvcStackSpace SPACE SVC_STACK_LENGTH*4 --------------------------------------- 请问各位大侠,DCD,SPACE ...… 查看全部问答> |
|
板子是自己画的,芯片用的是STM32F103ZDTB,复位用一个按键加10K的电阻加101的电容,低电平复位,晶振是用12M晶振加30P的电容,VBAT接了一个101的电容再接到VDD,板子再接了一个USART1. 量了一下,晶振是不 ...… 查看全部问答> |
|
有啥画PCB的群、或者画pcb的QQ,高手的,本人是个新手,刚接触设计PCB,学习过程可能会遇到一些问题,想加一些大侠的Q来指导下,被人q:1729217470.。… 查看全部问答> |
|
找FPGA固件设计兼职人员,出差去上海1到2个月,Verilog语言 用Verilog实现一个通信协议的状态机,协议有40多条,固件框架已经写好,用Verilog写的。因其中的RS232、LVDS、千兆网等IP CORE在上海合作单位那边,需要去那边联合开发调试一到两个月。需要您熟练应用Verilog,XILINX FPGA开工工具,对spartan-6内 ...… 查看全部问答> |




