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、中断等)。
其中有两个函数必须配置
<code class="lang-cpp">/**
  * @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)
{
          
}</code>
首先是void USB_OTG_BSP_Init(void),在这里需要:
1.配置VBUS ID DM DP引脚
<code class="lang-cpp">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) ;</code>
2.之后打开时钟
<code class="lang-cpp">RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_OTG_FS, ENABLE) ;</code>
之后是void USB_OTG_BSP_EnableInterrupt(void),在这里配置USB相关的中断
<code class="lang-cpp">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);</code>
usb_conf.h
USB配置
该文件主要配置一些参数,具体可以参考手册的5.3节,或者lib中对应类型的例子。


<code class="lang-cpp">#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</code>



三、USB device library 的配置
5.jpg
首先是core部分,/STM32_USB-Host-Device_Lib_V2.2.0/Libraries/STM32_USB_Device_Library/Core下,首先需要将头文件所在的目录添加到project的include paths中,并将需要编译的文件添加到编译列表中,然后再处理两个配置文件:
XXXXbd_conf_template.h
将其改成usbd_conf.h并移到project目录下,这里主要配置Device使用的EndPoint/Packet,请参考手册的6.3.4节或者example。

<code class="lang-cpp">#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</code>
XXXXbd_desc.c


这个文件有里有一个结构体提供了一组回调函数允许用户在程序运行时管理设备和描述符字符串。
<code class="lang-cpp">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;</code>
这些回调的具体定义请参考手册6.6章 USB device user interface
ST在库中封装了好了一个数组作为设备描述符
<code class="lang-cpp">__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 */</code>
并把其中涉及的设备信息定位成了宏
<code class="lang-cpp">#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"</code>

到目前为止,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库的中断触发。
<code class="lang-cpp">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);</code>

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

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

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

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

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

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

CV

主体类型:个人
所属领域:无
认证方式:手机号
IP归属地:未同步
文件下载
加载中...
{{errorInfo}}
{{downloadWarning}}
你在 {{downloadTime}} 下载过当前文件。
文件名称:{{resource.defaultFile.name}}
下载次数:{{resource.hits}}
上传用户:{{uploader.username}}
所需积分:{{costScores}},{{holdScores}}下载当前附件免费{{description}}
积分不足,去充值
文件已丢失

当前账号的附件下载数量限制如下:
时段 个数
{{f.startingTime}}点 - {{f.endTime}}点 {{f.fileCount}}
视频暂不能访问,请登录试试
仅供内部学术交流或培训使用,请先保存到本地。本内容不代表科创观点,未经原作者同意,请勿转载。
音频暂不能访问,请登录试试
支持的图片格式:jpg, jpeg, png
插入公式
评论控制
加载中...
文号:{{pid}}
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

加载中...
详情
详情
推送到专栏从专栏移除
设为匿名取消匿名
查看作者
回复
只看作者
加入收藏取消收藏
收藏
取消收藏
折叠回复
置顶取消置顶
评学术分
鼓励
设为精选取消精选
管理提醒
编辑
通过审核
评论控制
退修或删除
历史版本
违规记录
投诉或举报
加入黑名单移除黑名单
查看IP
{{format('YYYY/MM/DD HH:mm:ss', toc)}}