加载中
加载中
表情图片
评为精选
鼓励
加载中...
分享
加载中...
文件下载
加载中...
修改排序
加载中...
STM32 USB设备库使用/移植
phpskycn2016/04/01软件综合 IP:浙江
本文适用于STM32F105xx, STM32F107xx, STM32F2xx and STM32F4xx MCU,不适用于很流行的STM32F103/102/101/100以及STM32F0/L0系列。对于在STM32F7的适用情况未知。

涉及到的lib:

STM32F105/7xx, STM32F2xx and STM32F4xx USB On-The-Go Host and Device library V2.2.0 STM32F4xx DSP and Standard Peripherals Library V1.6.1

测试环境:STM32F4Discovery/MB997B(STM32F407ZG)


ST USB LIB的用户手册:

《STM32F105xx, STM32F107xx, STM32F2xx and STM32F4xx USB On-The-Go host and device library》(UM1021User manual)


ST提供了一个官方的USB LIB,通过这个库可以比较方便地使用STM32 MCU的硬件USB功能。用户可以通过参考LIB中的例子,在无需纠结于USB协议细节的情况下使用库中的Device class编写USB设备驱动。


一、USB LIB结构
1.jpg

直接引用手册里的图(P9)
位于最底层的是USB OTG low-level driver(USB OTG底层驱动),并依赖于标准外设库,其最底部是Core Interface Layer(核心界面层),上部则是HCD/DCD开头的接口和结构体。底层驱动实现了和硬件、外围电路相关的功能,并提供相关的数据结构和接口。如果需要开发自己的USB驱动而非使用ST提供的Device/Host Class,需要使用这些接口。
2.jpg

(底层驱动的结构和上层的关系)


3.jpg



在底层驱动之上的是USB device library/USB host library(USB设备驱动/USB主机驱动),实现了和设备/主机相关的功能,向用户提供接口配置设备信息、按照封装好的结构传送/发送信息,并提供了一组回调使得用户可以处理各种请求。其顶层是Class layer(类层),提供具体的设备类供用户使用。
本文主要讨论关于包含Class layer的Device lib的使用,对于Host lib可以参考相关过程,而需要实现自己的class或者自己的协议标准的用户则需要熟悉“下层”的接口并自己编写代码替换掉相关的层。

设备库的使用(移植)的主要过程如下:
1.明确需求和目的
2.修改project配置
3.复制相关文件,并修改配置/代码
4.调用相关接口

STM32 MCU支持使用USB Fullspeed Core 和USB Highspeed Core,使用USB HS需要外置的PHY(并不是所有的MCU都支持USB HS),本文只讨论使用USB-FS的情况。

二、USB OTG low-level driver(USB OTG底层驱动)的配置
4.jpg
底层驱动的文件位于/STM32_USB-Host-Device_Lib_V2.2.0/Libraries/STM32_USB_OTG_Driver下,首先需要将头文件所在的目录添加到project的include paths中,并将需要编译的文件添加到编译列表中。对于USB设备驱动,需要添加的文件是:
usb_core.c
usb_dcd.c
usb_dcd_int.c
并且将usb_bsp_template.c和usb_conf_template.h改名(去掉_template)后复制到工程目录中(usb_bsp.c需要添加到编译列表),并进行修改。
usb_bsp.c
USB Board Support Packag(USB板级支持包)
这里主要实现bord support,简单点说就是配置好USB相关的硬件操作(IO、中断等)。
其中有两个函数必须配置
JavaScript
/**   * @brief  USB_OTG_BSP_Init   *         Initializes BSP configurations   * @param  None   * @retval None   */            void USB_OTG_BSP_Init(void) {            } /**   * @brief  USB_OTG_BSP_EnableInterrupt   *         Enable USB Global interrupt   * @param  None   * @retval None   */ void USB_OTG_BSP_EnableInterrupt(void) {            }
首先是void USB_OTG_BSP_Init(void),在这里需要:
1.配置VBUS ID DM DP引脚
Other
GPIO_InitTypeDef GPIO_InitStructure;            RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOA , ENABLE);              /* Configure SOF VBUS ID DM DP Pins */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8  |   GPIO_Pin_9  |     GPIO_Pin_11 |       GPIO_Pin_12;            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; GPIO_Init(GPIOA, &GPIO_InitStructure);              GPIO_PinAFConfig(GPIOA,GPIO_PinSource8,GPIO_AF_OTG1_FS) ; GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_OTG1_FS) ; GPIO_PinAFConfig(GPIOA,GPIO_PinSource11,GPIO_AF_OTG1_FS) ; GPIO_PinAFConfig(GPIOA,GPIO_PinSource12,GPIO_AF_OTG1_FS) ;            /* this for ID line debug */                       GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_10; GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_Init(GPIOA, &GPIO_InitStructure);   GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_OTG1_FS) ;
2.之后打开时钟
Other
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_OTG_FS, ENABLE) ;
之后是void USB_OTG_BSP_EnableInterrupt(void),在这里配置USB相关的中断
Other
NVIC_InitTypeDef NVIC_InitStructure;                NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);   NVIC_InitStructure.NVIC_IRQChannel = OTG_FS_IRQn;     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;   NVIC_Init(&NVIC_InitStructure);
usb_conf.h
USB配置
该文件主要配置一些参数,具体可以参考手册的5.3节,或者lib中对应类型的例子。


C++
#ifdef USB_OTG_FS_CORE #define RX_FIFO_FS_SIZE                          128 #define TX0_FIFO_FS_SIZE                          64 #define TX1_FIFO_FS_SIZE                         128 #define TX2_FIFO_FS_SIZE                          0 #define TX3_FIFO_FS_SIZE                          0 #define TXH_NP_HS_FIFOSIZ                         96 #define TXH_P_HS_FIFOSIZ                          96          // #define USB_OTG_FS_LOW_PWR_MGMT_SUPPORT // #define USB_OTG_FS_SOF_OUTPUT_ENABLED #endif



三、USB device library 的配置
5.jpg
首先是core部分,/STM32_USB-Host-Device_Lib_V2.2.0/Libraries/STM32_USB_Device_Library/Core下,首先需要将头文件所在的目录添加到project的include paths中,并将需要编译的文件添加到编译列表中,然后再处理两个配置文件:
1.usbd_conf_template.h

将其改成usbd_conf.h并移到project目录下,这里主要配置Device使用的EndPoint/Packet,请参考手册的6.3.4节或者example。

C++
#define USBD_CFG_MAX_NUM 1 #define USB_MAX_STR_DESC_SIZ 64 /**** USB_MSC_Class_Layer_Parameter *********/ #define MSC_IN_EP 0x81 #define MSC_OUT_EP 0x01 #define MSC_MAX_PACKET 512 #define MSC_MEDIA_PACKET 4096 /**** USB_HID Class_Layer_Parameter *********/ #define HID_IN_EP 0x81 #define HID_OUT_EP 0x01 #define HID_IN_PACKET 4 #define HID_OUT_PACKE 4
2.usbd_desc.c



这个文件有里有一个结构体提供了一组回调函数允许用户在程序运行时管理设备和描述符字符串。
C++
typedef struct _Device_TypeDef { uint8_t *(*GetDeviceDescriptor)( uint8_t speed , uint16_t *length); uint8_t *(*GetLangIDStrDescriptor)( uint8_t speed , uint16_t *length); uint8_t *(*GetManufacturerStrDescriptor)( uint8_t speed , uint16_t *length); uint8_t *(*GetProductStrDescriptor)( uint8_t speed , uint16_t *length); uint8_t *(*GetSerialStrDescriptor)( uint8_t speed , uint16_t *length); uint8_t *(*GetConfigurationStrDescriptor)( uint8_t speed , uint16_t *length); uint8_t *(*GetInterfaceStrDescriptor)( uint8_t speed , uint16_t *length); #ifdef USB_SUPPORT_USER_STRING_DESC uint8_t* (*Get_USRStringDesc) (uint8_t speed, uint8_t idx , uint16_t *length); #endif /* USB_SUPPORT_USER_STRING_DESC */ } USBD_DEVICE, *pUSBD_DEVICE;
这些回调的具体定义请参考手册6.6章 USB device user interface
ST在库中封装了好了一个数组作为设备描述符
Other
__ALIGN_BEGIN uint8_t USBD_DeviceDesc[USB_SIZ_DEVICE_DESC] __ALIGN_END = {   0x12,                       /*bLength */   USB_DEVICE_DESCRIPTOR_TYPE, /*bDescriptorType*/   0x00,                       /*bcdUSB */   0x02,   0x00,                       /*bDeviceClass*/   0x00,                       /*bDeviceSubClass*/   0x00,                       /*bDeviceProtocol*/   USB_OTG_MAX_EP0_SIZE,      /*bMaxPacketSize*/   LOBYTE(USBD_VID),           /*idVendor*/   HIBYTE(USBD_VID),           /*idVendor*/   LOBYTE(USBD_PID),           /*idVendor*/   HIBYTE(USBD_PID),           /*idVendor*/   0x00,                       /*bcdDevice rel. 2.00*/   0x02,   USBD_IDX_MFC_STR,           /*Index of manufacturer  string*/   USBD_IDX_PRODUCT_STR,       /*Index of product string*/   USBD_IDX_SERIAL_STR,        /*Index of serial number string*/   USBD_CFG_MAX_NUM            /*bNumConfigurations*/ } ; /* USB_DeviceDescriptor */
并把其中涉及的设备信息定位成了宏
C++
#define USBD_VID                   0x0483 #define USBD_PID                   0x5720        #define USBD_LANGID_STRING         0x409 #define USBD_MANUFACTURER_STRING   "STMicroelectronics" #define USBD_PRODUCT_HS_STRING        "Mass Storage in HS Mode" #define USBD_PRODUCT_FS_STRING        "Mass Storage in FS Mode" #define USBD_CONFIGURATION_HS_STRING  "MSC Config" #define USBD_INTERFACE_HS_STRING      "MSC Interface" #define USBD_CONFIGURATION_FS_STRING  "MSC Config" #define USBD_INTERFACE_FS_STRING      "MSC Interface"

到目前为止,core部分已经结束,接下来是class部分。
ST的库中提供了几个常见的USB Device Class,如果要使用某个Class则需要将相关的文件添加到编译列表并添加相关的引用目录。
6.jpg
每个Class的具体情况请参考手册的6.7节 USB device classes


四、开始使用USB库
本章内容部分引述手册6.8章  Application layer description和6.9章Starting the USB device library。
7.jpg
目录结构
在ST的每一个例子中,源码目录被分为src(源码)和inc(头文件)两个字文件夹
源码目录包含下列文件:

● app.c: 包含main函数
● stm32fxxx_it.c: 包含系统中断响应函数
● system_stm32fxxx.c: 系统时钟配置
● usb_bsp.c:包含在usb_bsp.h中声明的USB OTG底层函数的实现,用于初始化底层相关的GPIO\中断处理\延时等
● usbd_usr:包含在usbd_usr.h中声明的函数的实现,用于处理来自用户层的事件/消息
● usbd_desc.c: 这个文件在USB设备例子中提供,实现了一些回调函数。这个文件提供了一套函数被用于改变设备描述符。



头文件目录包含下列文件


● stm32fxxx_it.h:stm32fxxx_it.c的头文件● usb_conf.h: USB OTG low level driver的配置文件
● usbd_conf.h: USB device library的配置文件


USB库被设计成基于中断模型,用户层应用程序只需要调用USBD_Init()函数并处理user/class层的回调函数。USB内部处理过程由USB库管理并由来自USB库的中断触发。
Other
void USBD_Init(USB_OTG_CORE_HANDLE *pdev,                USB_OTG_CORE_ID_TypeDef coreID,                USBD_DEVICE *pDevice,                                  USBD_Class_cb_TypeDef *class_cb,                USBD_Usr_cb_TypeDef *usr_cb);

[修改于 9年3个月前 - 2016/04/05 12:05:51]

来自:计算机科学 / 软件综合
3
新版本公告
~~空空如也
phpskycn 作者
9年3个月前 修改于 9年3个月前 IP:浙江
814431
接下来将是两个例子:USB RamDisk(一个使用MCU内RAM的U盘)和USH HID(模拟鼠标),供懒得看/看不懂手册的童鞋了解相关过程
仍未完成,明天继续
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
phpskycn作者
9年3个月前 IP:浙江
814568
相关的附件:

手册
STM32F105xx, STM32F107xx, STM32F2xx and STM32F4xx USB
On-The-Go host and device library

attachment icon CD00289278.pdf 1.35MB PDF 280次下载 预览
USB库
STM32F105/7, STM32F2 and STM32F4 USB on-the-go Host and device library (UM1021) (体积过大,只给出来自ST官网的链接)
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论

想参与大家的讨论?现在就 登录 或者 注册

所属专业
上级专业
同级专业
phpskycn
专家 老干部 学者 机友 笔友
文章
403
回复
4591
学术分
8
2009/03/15注册,1天18时前活动

CV

主体类型:个人
所属领域:无
认证方式:手机号
IP归属地:未同步
插入公式
评论控制
加载中...
文号:{{pid}}
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

笔记
{{note.content}}
{{n.user.username}}
{{fromNow(n.toc)}} {{n.status === noteStatus.disabled ? "已屏蔽" : ""}} {{n.status === noteStatus.unknown ? "正在审核" : ""}} {{n.status === noteStatus.deleted ? '已删除' : ''}}
  • 编辑
  • 删除
  • {{n.status === 'disabled' ? "解除屏蔽" : "屏蔽" }}
我也是有底线的