目录
2.2 USB-FS_Device peripheral interface
2.3 USB-FS-Device_Driver medium layer
链接快速定位
前沿
本小节主要讲述STM32F103USB设备模式下的标准库驱动程序结构,代码比较复杂,需要读者对USB协议有一个全面的了解,这里只讲述一下比较浅显的东西。
1 STM32-FS-USB驱动程序下载
每个芯片厂商都会提供一套属于自己的外设驱动及应用程序,这也是我们所说的生态的一部分,可以通过顶部置顶资源下载。
2 STM32-USB-FS设备固件库
2.1 USB应用程序层次结构
下图显示了典型USB的不同组件之间的交互应用程序和USB FS设备库。
从上图可知,USB设备固件库被分为两层:
- STM32_USB-FS_Device_Driver:该层管理与USB-FS_ Device外围设备和USB标准协议的直接通信。STM32_USBFS_ Device_Driver符合USB 2.0规范,与标准STM32标准外设库分离。
- Application Interface layer:该层为用户提供了库核心和最终应用程序之间的完整接口。
下图显示了USB FS设备库的程序包组织以及所有演示和子文件夹。
2.2 USB-FS_Device peripheral interface
USB全速设备外设接口层主要由以下部分组成:
- 硬件抽象层
- 正确传输中断服务例程
- 数据传输管理
2.3 USB-FS-Device_Driver medium layer
USB全速设备驱动中间层主要由以下部分组成:
- USB设备全局变量初始化
- USB协议管理
- 简化了对端点的读写访问功能(USB-FS_Device外围设备的抽象层)
- 库中使用的USB定义和类型
- 根据使用的评估板定义硬件
2.3 Application interface
应用接口主要由以下部分组成:
- USB全速设备配置文件
- USB设备描述符
- USB设备应用程序特定属性
- 不带控制端点的正确传输中断例程
- USB设备中断处理函数
- USB设备电源和连接管理函数
3 代码讲解
代码讲解主要涉及以下几个方面:
- 初始化
- 描述符
- 中断处理函数
- 复位函数
- 正确传输完成函数
这里以“VirtualComport_Loopback”工程为例进行讲解。
3.1 初始化代码讲解
- GPIO初始化
GPIO初始化程序主要是初始化通信所使用的DM和DP引脚以及USB全速设备的DP上拉引脚。
void Set_System(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/********************************************/
/* Configure USB DM/DP pins */
/********************************************/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* USB_DISCONNECT used as USB pull-up */
GPIO_InitStructure.GPIO_Pin = USB_DISCONNECT_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_Init(USB_DISCONNECT, &GPIO_InitStructure);
/* Enable the USB disconnect GPIO clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIO_DISCONNECT, ENABLE);
}
- USB时钟配置
USB时钟配置主要是配置USB的PHY时钟,运行在48MHz的时钟下(系统时钟72M),并使能USB时钟。
void Set_USBClock(void)
{
/* Select USBCLK source */
RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5);
/* Enable the USB clock */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE);
}
- USB中断初始化
USB中断初始化,主要是使能USB的中断,并且使能中断屏蔽位。
void USB_Interrupts_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* 2 bit for pre-emption priority, 2 bits for subpriority */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
/* Enable the USB interrupt */
NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* Enable the USB Wake-up interrupt */
NVIC_InitStructure.NVIC_IRQChannel = USBWakeUp_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_Init(&NVIC_InitStructure);
}
RESULT PowerOn(void)
{
uint16_t wRegVal;
#if !defined (USE_NUCLEO)
/*** cable plugged-in ? ***/
USB_Cable_Config(ENABLE);
#endif
/*** CNTR_PWDN = 0 ***/
wRegVal = CNTR_FRES;
_SetCNTR(wRegVal);
/* The following sequence is recommended:
1- FRES = 0
2- Wait until RESET flag = 1 (polling)
3- clear ISTR register */
/*** CNTR_FRES = 0 ***/
wInterrupt_Mask = 0;
_SetCNTR(wInterrupt_Mask);
/* Wait until RESET flag = 1 (polling) */
while((_GetISTR()&ISTR_RESET) == 1);
/*** Clear pending interrupts ***/
SetISTR(0);
/*** Set interrupt mask ***/
wInterrupt_Mask = CNTR_RESETM | CNTR_SUSPM | CNTR_WKUPM;
_SetCNTR(wInterrupt_Mask);
return USB_SUCCESS;
}
uint32_t USB_SIL_Init(void)
{
/* USB interrupts initialization */
/* clear pending interrupts */
_SetISTR(0);
wInterrupt_Mask = IMR_MSK;
/* set interrupts mask */
_SetCNTR(wInterrupt_Mask);
return 0;
}
void Virtual_Com_Port_init(void)
{
/* Update the serial number string descriptor with the data from the unique
ID*/
Get_SerialNum();
pInformation->Current_Configuration = 0;
/* Connect the device */
PowerOn();
/* Perform basic device initialization operations */
USB_SIL_Init();
bDeviceState = UNCONNECTED;
}
经过上面的配置,当USB设备端接入主机的时候,设备端的中断处理函数就能响应相应的中断请求,开始建立通信。
3.2 描述符讲解
描述符放在“usb_desc.c”和“usb_desc.h”文件中,更多细节参见