STM32F4的USB Host驱动移植详细步骤及问题解决

1、库文件准备

在这里插入图片描述
这三个从上到下分别为USB从机驱动库,USB主机驱动库,USB_OTG内核驱动代码,本次使用HOST和OTG进行移植

2、工程准备

FATFS实验工程,并将LCD改为printf,因为没有用到LCD,调试信息就只有通过printf进行查看

3、移植

3.1、新建USB相关文件夹

打开工程,新建USB文件夹并拷贝USB驱动库,在拷贝的目录下并新建一个USB_APP文件夹
在这里插入图片描述
MSC相关代码到USB_APP文件夹内相关代码,即:en.stm32_f105-07_f2_f4_usb-host-device_lib\Project\USB_Host_Examples\MSC\src下的部分代码:usb_bsp.c 、usbd_usr.c 2个.c 文件,
同时拷贝 en.stm32_f105-07_f2_f4_usb-host-device_lib\Project\USB_Host_Examples\MSC\inc下面的:usb_conf.h、usbd_conf.h 和 usbd_usr.h 等三个文件,添加完成后如下图所示:
在这里插入图片描述

3.2、加USB相关代码

工程添加USB相关代码,如下图所示:
根据ST官方的MSC例程,新建USB_OTG组,存放USB_OTG内核驱动代码,新建USB_DEVICE组,存放USB从机与MSC相关代码,新建USB_APP存放用户配置相关驱动代码
在这里插入图片描述
USB_OTG组代码路径为USB\STM32_USB_OTG_Driver\src
USB_DEVICE组代码路径为USB\STM32_USB_Device_Library\Core\src以及USB\STM32_USB_Device_Library\Class\msc\src
USB_APP组代码路径为USB\USB_APP内

3.3、添加头文件路径

在这里插入图片描述

4、修改相关代码

1、修改usbh_usr.c

编译代码,根据报错提示,修改相关内容。先从第一个错误开始修改

①,usb_conf.h,include部分,

使用如下代码替代:
#include "stm32f4xx.h"

在这里插入图片描述

②,定义全局宏

在C/C++选项卡,定义全局宏:USE_USB_OTG_FS,选择使用USB OTG FS,如图所示:
在这里插入图片描述

③,修改usbh_usr.c

3.1,删除lcd_log.h等头文件,并添加usart.h等头文件
如下所示:

#include "usbh_usr.h" 
#include "led.h"
#include "ff.h" 
#include "usart.h" 

在这里插入图片描述
3.2,修改为AppState变量
用AppState变量,替换原来的USBH_USR_ApplicationState,用于记录执行状态。然后,删除一些用不到的变量(头文件至USBH_Usr_cb_TypeDef USR_cb以及USBH_Usr_cb_TypeDef USR_cb至USBH_USR_Init之间的申明和变量),并添加USB中断处理函数(官方例程在stm32fxxx_it.c里面处理)到本.c文件,如下所示:

static u8 AppState;
extern USB_OTG_CORE_HANDLE  USB_OTG_Core;//在main函数定义!!

//USB OTG 中断服务函数
//处理所有USB中断
void OTG_FS_IRQHandler(void)
{
  	USBH_OTG_ISR_Handler(&USB_OTG_Core);
} 

在这里插入图片描述
3.3,修改USBH_USR_Init函数为:

void USBH_USR_Init(void)
{
	printf("USB OTG HS MSC Host\r\n");
	printf("> USB Host library started.\r\n");
	printf("  USB Host Library v2.1.0\r\n\r\n");
}

3.4,修改USBH_USR_DeviceAttached函数为:

void USBH_USR_DeviceAttached(void)//U盘插入
{
	LED1=1;
	printf("检测到USB设备插入!\r\n");
}

3.5,修改USBH_USR_UnrecoveredError函数为:

void USBH_USR_UnrecoveredError (void)
{
	printf("无法恢复的错误!!!\r\n\r\n");	
}

3.6,修改USBH_USR_DeviceDisconnected函数为:

void USBH_USR_DeviceDisconnected (void)//U盘移除
{
	LED1=0;
	printf("USB设备拔出!\r\n");
} 

3.7,修改USBH_USR_ResetDevice函数为:

void USBH_USR_ResetDevice(void)
{
	printf("复位设备...\r\n");
}

3.8,修改USBH_USR_DeviceSpeedDetected函数为:

void USBH_USR_DeviceSpeedDetected(uint8_t DeviceSpeed)
{
	if(DeviceSpeed==HPRT0_PRTSPD_HIGH_SPEED)
	{
		printf("高速(HS)USB设备!\r\n");
 	}  
	else if(DeviceSpeed==HPRT0_PRTSPD_FULL_SPEED)
	{
		printf("全速(FS)USB设备!\r\n"); 
	}
	else if(DeviceSpeed==HPRT0_PRTSPD_LOW_SPEED)
	{
		printf("低速(LS)USB设备!\r\n");  
	}
	else
	{
		printf("设备错误!\r\n");  
	}
}

3.9,修改USBH_USR_Device_DescAvailable函数为:

void USBH_USR_Device_DescAvailable(void *DeviceDesc)
{ 
	USBH_DevDesc_TypeDef *hs;
	hs=DeviceDesc;   
	printf("VID: %04Xh\r\n" , (uint32_t)(*hs).idVendor); 
	printf("PID: %04Xh\r\n" , (uint32_t)(*hs).idProduct); 
}

3.10,修改USBH_USR_DeviceAddressAssigned函数为:

void USBH_USR_DeviceAddressAssigned(void)
{
	printf("从机地址分配成功!\r\n");   
}

3.11,修改USBH_USR_Configuration_DescAvailable函数为:

void USBH_USR_Configuration_DescAvailable(USBH_CfgDesc_TypeDef * cfgDesc,
                                          USBH_InterfaceDesc_TypeDef *itfDesc,
                                          USBH_EpDesc_TypeDef *epDesc)
{
	USBH_InterfaceDesc_TypeDef *id; 
	id = itfDesc;   
	if((*id).bInterfaceClass==0x08)
	{
		printf("可移动存储器设备!\r\n"); 
	}else if((*id).bInterfaceClass==0x03)
	{
		printf("HID 设备!\r\n"); 
	}    
}

3.12,修改USBH_USR_Manufacturer_String函数为:

void USBH_USR_Manufacturer_String(void *ManufacturerString)
{
	printf("Manufacturer: %s\r\n",(char *)ManufacturerString);
}

3.13,修改USBH_USR_Product_String函数为:

void USBH_USR_Product_String(void *ProductString)
{
	printf("Product: %s\r\n",(char *)ProductString);  
}

3.14,修改USBH_USR_SerialNum_String函数为:

void USBH_USR_SerialNum_String(void *SerialNumString)
{
	printf("Serial Number: %s\r\n",(char *)SerialNumString);    
} 

3.15,修改USBH_USR_EnumerationDone函数为:

void USBH_USR_EnumerationDone(void)
{ 
	printf("设备枚举完成!\r\n\r\n");    
}

3.16,修改USBH_USR_DeviceNotSupported函数为:

void USBH_USR_DeviceNotSupported(void)
{
	printf("无法识别的USB设备!\r\n\r\n");    
} 

3.17,修改USBH_USR_UserInput函数为:

USBH_USR_Status USBH_USR_UserInput(void)
{ 
	printf("跳过用户确认步骤!\r\n");
	return USBH_USR_RESP_OK;
} 

3.18,修改USBH_USR_OverCurrentDetected函数为:

void USBH_USR_OverCurrentDetected (void)
{
	printf("端口电流过大!!!\r\n");
} 

3.19,修改USBH_USR_MSC_Application函数为:

extern u8 USH_User_App(void);		//用户测试主程序,在main函数定义!!
int USBH_USR_MSC_Application(void)
{
	u8 res=0;
	switch(AppState)
	{
		case USH_USR_FS_INIT://初始化文件系统 
			printf("开始执行用户程序!!!\r\n");
			AppState=USH_USR_FS_TEST;
			break;
		case USH_USR_FS_TEST://执行USB OTG 测试主程序
			res=USH_User_App(); //用户主程序
			res=0;
			if(res)AppState=USH_USR_FS_INIT;
			break;
		default:break;
	} 
	return res;
}

3.20,修改usbh_usr.h,新增包含:usb_hcd_int.h头文件,并将宏定义:USH_USR_FS_READLIST,改为:USH_USR_FS_TEST,并删掉后续的2个宏定义。
在这里插入图片描述
3.21,删除后续除USBH_USR_DeInit函数以外的其他所有函数,并修改:USBH_USR_DeInit函数为:

void USBH_USR_DeInit(void)
{
  	AppState=USH_USR_FS_INIT;
}

3.22,为了让fatfs 可以访问U盘,我们在usbh_usr.c的最后,新增3个函数,提供给fatfs的diskio.c调用。首先要声明一个USB_Host结构体(在main函数定义),如下:

extern USBH_HOST              USB_Host;//USB HOST结构体,存储主机相关状态。
然后,增加USBH_UDISK_Status函数,用于读取U盘状态,如下:
//获取U盘状态,返回值:0,U盘未就绪,1,就绪
u8 USBH_UDISK_Status(void)
{
	return HCD_IsDeviceConnected(&USB_OTG_Core);//返回U盘状态
}

3.23,新增USBH_UDISK_Read函数,用于读U盘,如下:

//读U盘
//buf:读数据缓存区
//sector:扇区地址
//cnt:扇区个数	
//返回值:错误状态;0,正常;其他,错误代码;		 
u8 USBH_UDISK_Read(u8* buf,u32 sector,u32 cnt)
{
	u8 res=1;
	if(HCD_IsDeviceConnected(&USB_OTG_Core)&&AppState==USH_USR_FS_TEST)//连接在&APP测试
	{  		    
		do
		{
			res=USBH_MSC_Read10(&USB_OTG_Core,buf,sector,512*cnt);
			USBH_MSC_HandleBOTXfer(&USB_OTG_Core ,&USB_Host);		      
			if(!HCD_IsDeviceConnected(&USB_OTG_Core))
			{
				res=1;//读写错误
				break;
			};   
		}while(res==USBH_MSC_BUSY);
	}else res=1;		  
	if(res==USBH_MSC_OK)res=0;	
	return res;
}

3.24,新增USBH_UDISK_Write函数,用于写U盘,如下:

//写U盘
//buf:写数据缓存区
//sector:扇区地址
//cnt:扇区个数	
//返回值:错误状态;0,正常;其他,错误代码;		 
u8 USBH_UDISK_Write(u8* buf,u32 sector,u32 cnt)
{
	u8 res=1;
	if(HCD_IsDeviceConnected(&USB_OTG_Core)&&AppState==USH_USR_FS_TEST)//连接在&APP测试
	{  		    
		do
		{
			res=USBH_MSC_Write10(&USB_OTG_Core,buf,sector,512*cnt); 
			USBH_MSC_HandleBOTXfer(&USB_OTG_Core ,&USB_Host);		      
			if(!HCD_IsDeviceConnected(&USB_OTG_Core))
			{
				res=1;//读写错误
				break;
			};   
		}while(res==USBH_MSC_BUSY);
	}else res=1;		  
	if(res==USBH_MSC_OK)res=0;	
	return res;
}

3.25,最后,新增的这三个函数,由于要在diskio.c里面调用,我们把这三个函数的声明,放到usbh_usr.h里面,如下所示:

u8 USBH_UDISK_Status(void);
u8 USBH_UDISK_Read(u8* buf,u32 sector,u32 cnt);
u8 USBH_UDISK_Write(u8* buf,u32 sector,u32 cnt);

编译一下,会提示一下错误,首先解决头文件问题,把 #include "lcd_log.h"屏蔽掉,其他的问题暂时不管

2、修改diskio.c

修改diskio.c。添加对U盘访问的支持。
1,新增usbh_usr.h头文件,并新增USB_DISK宏定义,如下所示:

#include "usbh_usr.h"

#define SD_CARD	 0  //SD卡,卷标为0
#define EX_FLASH 1	//外部flash,卷标为1
#define USB_DISK 2	//U盘,卷标为2

2,修改disk_initialize函数,添加U盘初始化部分,如下所示:

	case USB_DISK://U盘
	  		if(USBH_UDISK_Status())return 0;	//U盘连接成功,则返回1.否则返回0		  
			else return 1;

在这里插入图片描述
3,修改disk_read函数,添加U盘读函数,如下所示:

case USB_DISK://U盘 
			res=USBH_UDISK_Read(buff,sector,count);	  
			break;

4,修改disk_write函数,添加U盘写函数,如下所示:

case USB_DISK://U盘
			res=USBH_UDISK_Write((u8*)buff,sector,count); 
			break;

5,修改disk_ioctl函数,添加U盘支持部分,如下所示:

else if(pdrv==USB_DISK)	//U盘
	{
	    switch(cmd)
	    {
		    case CTRL_SYNC:
				res = RES_OK; 
		        break;	 
		    case GET_SECTOR_SIZE:
		        *(WORD*)buff=512;
		        res = RES_OK;
		        break;	 
		    case GET_BLOCK_SIZE:
		        *(WORD*)buff=512;
		        res = RES_OK;
		        break;	 
		    case GET_SECTOR_COUNT:
		        *(DWORD*)buff=USBH_MSC_Param.MSCapacity;
		        res = RES_OK;
		        break;
		    default:
		        res = RES_PARERR;
		        break;
	    }		
	}

3、修改ffconf.h

将_VOLUMES的值,修改为3,以支持3个磁盘(SD卡、SPI FLASH、U盘)。

4、修改usb_bsp.c

1,新增sys.h和delay.h等几个头文件,,如下所示:

#include "usb_bsp.h"
#include "sys.h"  
#include "delay.h" 

2,删掉用不到的宏定义和全局变量(头文件至USB_OTG_BSP_Init),并添加USB_HOST_PWRCTRL宏,用于控制USB HOST接口的对外供电,如下所示:

//USB主机电源控制口
#define USB_HOST_PWRCTRL 	PAout(15)	//PA15 

3,修改USB_OTG_BSP_Init函数为:

void USB_OTG_BSP_Init(USB_OTG_CORE_HANDLE *pdev)
{
	GPIO_InitTypeDef  GPIO_InitStructure;

	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能GPIOA时钟
	RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_OTG_FS, ENABLE);//使能USB OTG时钟	钟
	//GPIOA11,A12设置
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12;//PA11/12复用功能输出	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; 
	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;//PA15推挽输出		
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//输出功能
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; 
	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化
	USB_HOST_PWRCTRL=1;	//开启USB HOST电源供电
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource11,GPIO_AF_OTG_FS);//PA11,AF10(USB)
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource12,GPIO_AF_OTG_FS);//PA12,AF10(USB)
}

4,修改USB_OTG_BSP_EnableInterrupt函数为:

void USB_OTG_BSP_EnableInterrupt(USB_OTG_CORE_HANDLE *pdev)
{
	NVIC_InitTypeDef   NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = OTG_FS_IRQn; 
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;//抢占优先级0
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03;//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能通道
	NVIC_Init(&NVIC_InitStructure);//配置  
}

5,修改USB_OTG_BSP_DriveVBUS函数为:

void USB_OTG_BSP_DriveVBUS(USB_OTG_CORE_HANDLE *pdev, uint8_t state)
{ 
}

6,修改USB_OTG_BSP_ConfigVBUS函数为:

void  USB_OTG_BSP_ConfigVBUS(USB_OTG_CORE_HANDLE *pdev)
{ 
} 

7,删除USB_OTG_BSP_TimeInit、USB_OTG_BSP_TimerIRQ、BSP_Delay、BSP_SetTime等函数。
8,修改USB_OTG_BSP_uDelay函数为:

void USB_OTG_BSP_uDelay (const uint32_t usec)
{ 
   	delay_us(usec);
}

9,修改USB_OTG_BSP_mDelay函数为:

void USB_OTG_BSP_mDelay (const uint32_t msec)
{  
	delay_ms(msec);
} 

再编译一下,错误如下所示
在这里插入图片描述
有三个USB相关的未定义,这个会在主函数定义,而第一个错误是官方的例程用LCD,到时候修改或替换下即可,暂时可不用管它,进行下一步

5、修改main.c

#include "sys.h"
#include "delay.h"  
#include "usart.h"   
#include "led.h"
#include "lcd.h"
#include "key.h"  
#include "usmart.h"  
#include "sram.h"   
#include "malloc.h" 
#include "w25qxx.h"    
#include "sdio_sdcard.h"
#include "ff.h"  
#include "exfuns.h"    	 
#include "usbh_usr.h" 

//ALIENTEK 探索者STM32F407开发板 实验53
//USB U盘 实验-库函数版本 
//技术支持:www.openedv.com
//淘宝店铺:http://eboard.taobao.com
//广州市星翼电子科技有限公司    
//作者:正点原子 @ALIENTEK 

USBH_HOST  USB_Host;
USB_OTG_CORE_HANDLE  USB_OTG_Core;


//用户测试主程序
//返回值:0,正常
//       1,有问题
u8 USH_User_App(void)
{ 
	u32 total,free;
	u8 res=0;
	printf("设备连接成功!.");	 
	res=exf_getfree("2:",&total,&free);
	if(res==0)
	{
		printf("FATFS OK!");	
		printf("U Disk Total Size:%d MB",total);	 
		printf("U Disk  Free Size:%d MB",free); 	    
	} 
 
	while(HCD_IsDeviceConnected(&USB_OTG_Core))//设备连接成功
	{	
		LED1=!LED1;
		delay_ms(200);
	}   
	printf("设备连接中...");
	return res;
} 


int main(void)
{        
	u8 t;
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
	delay_init(168);  //初始化延时函数
	uart_init(115200);		//初始化串口波特率为115200
	LED_Init();				//初始化与LED连接的硬件接口
	KEY_Init();				//按键
  	
	W25QXX_Init();			//SPI FLASH初始化
	my_mem_init(SRAMIN);	//初始化内部内存池	
 	exfuns_init();			//为fatfs相关变量申请内存 

  	f_mount(fs[0],"0:",1); 	//挂载SD卡  
  	f_mount(fs[1],"1:",1); 	//挂载SD卡  
  	f_mount(fs[2],"2:",1); 	//挂载U盘     
 
	printf("设备连接中...");	
	
	//初始化USB主机
  	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_ms(1);
		t++;
		if(t==200)
		{
			LED0=!LED0;
			t=0;
		}
	}	
}

将main函数整个替换掉即可,然后编译,就剩下上面说的LCD这个错误,那么将这个错误解决掉即可
…\OBJ\FATFS.axf: Error: L6218E: Undefined symbol LCD_ErrLog (referred from usbh_msc_core.o).
解决办法:将LCD_ErrLog替换为printf,并添加#include "usart.h"头文件即可

5、功能测试

运行程序,插入U盘出现如下信息则表示功能测试OK
在这里插入图片描述

Uubt is for McU UsB BlueTooth ============================= This is a demo application for bluetooth USB dongle connected to STM32F4DISCOVERY (http://www.st.com/internet/evalboard/product/252419.jsp) board based on BTstack (http://code.google.com/p/btstack) project and ST USB libraries. LICENSING --------- My files are licensed under the terms of GPLv3, although I haven't thoroughly investigated the licenses compatibility for packages used. Please note that files from different projects involved use different licences. WHAT IS SPECIAL --------------- Pure FOSS components using hardware comprized of very cheap STM32F4DISCOVERY board and commodity bluetooth USB dongles. WHAT YOU NEED ------------- - STM32F4DISCOVERY board - cable to connect it to USB dongle (I use normal USB A male to micro-USB cable + USB A female/USB A female adapter) - USB dongle: USB parameters are currently hardcoded rather than read from descriptors, so you should verify that they match (I use lsusb -v for that purpose). Dongles tested thus far are: CSR and Atheros AR3011. Firmware loading is implemented for some Atheros chips but it is not very stable. - toolchain and libraries. I use linux, code sourcery lite (eabi build), https://github.com/texane/stlink project. You should download btstack source and STM32F4DISCOVERY firmware package (http://www.st.com/internet/com/SOFTWARE_RESOURCES/SW_COMPONENT/FIRMWARE/stm32f4discovery_fw.zip). COMPILING --------- Currently 2 build flavours are supported: bare (no OS) and for ChibiOS/RT (http://www.chibios.org). To build for ChibiOS/RT, additionally download respective sources (I use trunk, which is currently at 2.3.4+). You will probably not need newlib_stubs.c here. The description below is for no-OS build. Fix ST libs (mine are marked as 1.1.0 revision) using the patch provided. Btstack source probably needs configuring (I'm not sure). Couple of build options are currently implemented via Makefile variables, see Makefile head for
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值