USB中文名称是通用串行总线,因其具有传输速度快,使用方便,支持热插拔,连接灵活,独立供电等优点而得到广泛应用。但是USB协议非常的复杂,完整的协议就有厚厚的一本,还好ST公司很体贴的提供一整套USB库以及例程,用户只需对其例程稍微修改移植到自己的项目就好。Stm32的MCU有三种带USB功能的IP:
•USB IP
可作为全速或低速的USB设备
存在于STM32F102、STM32F103
•FS OTG IP
可作为全速和低速USB主机
可作为全速USB设备
存在于STM32F105、STM32F107、STM32F2、STM32F4
•HS OTG IP
可作为高速、全速和低速USB主机
可作为高速和全速USB设备
存在于STM32F2、STSM32F4
这里基于USB OTG库做介绍,stm32的usb_otg库可以从http://www.stmcu.org/document/detail/index/id-213011下载。
STM32_USB-Host-Device_Lib_V2.2.0\Project\USB_Host_Examples\MSC
里有我们需要的例程,移植该例程可以实现对U盘、SD卡读卡器等大容量存储进行识别,再配合使用fatfs文件系统就可以对U盘/SD卡进行读写。
要完成移植需要对usb_bsb.c、usbh_usr.c等文件进行修改。usb_bsb.c提供了几个USB库需要用到的底层初始化函数,包括:IO设置、中断设置、VBUS配置以及延时函数等,需要我们自己实现,来看看这里面的几个函数。
void USB_OTG_BSP_Init(USB_OTG_CORE_HANDLE *pdev)完成对USB所使用的IO口的初始化,包括初始化端口时钟、端口模式等。voidUSB_OTG_BSP_EnableInterrupt(USB_OTG_CORE_HANDLE *pdev)配置USB全局中断。
usbh_usr.c是应用程序软件,用户通过对这个文件进行修改来实现自己的应用,重点介绍USR_cb这个元素为回调函数的结构体和int USBH_USR_MSC_Application(void)这个函数。
USR_cb的定义如下:
USBH_Usr_cb_TypeDef USR_cb =
{
USBH_USR_Init,
USBH_USR_DeInit,
USBH_USR_DeviceAttached,
USBH_USR_ResetDevice,
USBH_USR_DeviceDisconnected,
USBH_USR_OverCurrentDetected,
USBH_USR_DeviceSpeedDetected,
USBH_USR_Device_DescAvailable,
USBH_USR_DeviceAddressAssigned,
USBH_USR_Configuration_DescAvailable,
USBH_USR_Manufacturer_String,
USBH_USR_Product_String,
USBH_USR_SerialNum_String,
USBH_USR_EnumerationDone,
USBH_USR_UserInput,
USBH_USR_MSC_Application,
USBH_USR_DeviceNotSupported,
USBH_USR_UnrecoveredError
};
这是一个USBH_Usr_cb_TypeDef USR类型的结构体,USBH_Usr_cb_TypeDef USR的定义是:
typedef struct _USBH_USR_PROP
{
void (*Init)(void); /* HostLibInitialized */
void (*DeInit)(void); /* HostLibInitialized */
void (*DeviceAttached)(void); /* DeviceAttached */
void (*ResetDevice)(void);
void (*DeviceDisconnected)(void);
void (*OverCurrentDetected)(void);
void (*DeviceSpeedDetected)(uint8_t DeviceSpeed); /* DeviceSpeed */
void (*DeviceDescAvailable)(void *); /* DeviceDescriptor is available */
void (*DeviceAddressAssigned)(void); /* Address is assigned to USB Device */
void (*ConfigurationDescAvailable)(USBH_CfgDesc_TypeDef *,
USBH_InterfaceDesc_TypeDef *,
USBH_EpDesc_TypeDef *);
/* Configuration Descriptor available */
void (*ManufacturerString)(void *); /* ManufacturerString*/
void (*ProductString)(void *); /* ProductString*/
void (*SerialNumString)(void *); /* SerialNubString*/
void (*EnumerationDone)(void); /* Enumeration finished */
USBH_USR_Status (*UserInput)(void);
int (*UserApplication) (void);
void (*DeviceNotSupported)(void); /* Device is not supported*/
void (*UnrecoveredError)(void);
}
USBH_Usr_cb_TypeDef;
用户编写USR_cb里面的回调函数可以实现在插入u盘、拔出u盘时打印相关的提示信息,比如是否连接上了?是否枚举成功了?是否断开了?等等。int USBH_USR_MSC_Application(void)用来实现用户的具体应用,比如配合fatfs文件系统对u盘进行读写等。
以上就是移植过程中需要注意的地方,下面介绍具体怎么实现对u盘的识别。
Stm32usb功能的具体工作都是中断做的,用户要做的只有初始化usb和调用usb进程函数。
void USBH_Init(USB_OTG_CORE_HANDLE *pdev,
USB_OTG_CORE_ID_TypeDef coreID,
USBH_HOST *phost,
USBH_Class_cb_TypeDef *class_cb,
USBH_Usr_cb_TypeDef *usr_cb)
USBH_Init()中调用了上文所说的usb_bsb.c中USB_OTG_BSP_Init()、 USB_OTG_BSP_EnableInterrupt()等函数实现对USB硬件和中断的初始化,并登记用户定义的回调函数。
USBH_Process(&USB_OTG_Core, &USB_Host)这个函数以状态机的方式实现对u盘的识别并分配通道和u盘状态的转换。这个进程函数需要快速不停地调用,以便快速的对usb口状态的改变做出响应。下面是mian函数的一个demo:
int main(void)
{
USBH_Init(&USB_OTG_Core, USB_OTG_FS_CORE_ID,
&USB_Host, &USBH_MSC_cb, &USR_cb);
While(1)
{
USBH_Process(&USB_OTG_Core, &USB_Host);
Delay();
}
}
实现起来是不是很简单?主要工作集中在移植阶段。