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
在这里插入图片描述

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值