文章目录
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