一、USB发展历史
二、USB简介
USB有USB1.0/1.1/2.0/3.0多个版本,标准USB由4根线组成,VCC,GND,D+,D-,其中D+和D-是数据线,采用差分传输。在USB主机上,D-和D+都是接了15K的电阻到地,所以在没有设备接入的时候,D+、D-均是低电平。 而在USB设备中,如果是高速设备,则会在D+上接一个1.5K的电阻到VCC ,而如果是低速设备,则会在D-上接一个1.5K的电阻到VCC,当设备接入主机时,主机就可以判断是否有设备接入,并能判断设备是高速设备还是低速设备。
- DualCore:这通常指的是一个USB设备具有双核处理器,即设备内部有两个处理器核心,可以提高设备的处理性能和效率。
- HID(Human Interface Device):这是指一种USB设备类型,用于与人类交互,例如键盘、鼠标、游戏手柄等。
- MSC(Mass Storage Class):这是指一种USB设备类型,用于存储数据,例如闪存驱动器、移动硬盘等。
有些芯片内部有两个USB控制器,名称分别为USB_OTG_FS和USB_OTG_HS。其中HS代表实现高速480Mbps速度模式通信。FS意为全速,速度为12Mbps。HS高速模式必须外接PHY芯片才能实现,例如USB3300等。
⭐OTG的意思是既可以做USB HOST,也可以做USB DEVICE。
⭐USB Host是指驱动过后,板子就可以连接USB接口连接的器件,读取和转载数据了。
⭐USB Device是指驱动过后,板子可以当作一个USB移动设备,通过USB连接到电脑上,类似U盘。
三、USB引脚图
主要有两种情况,一种是单片机引脚控制USB电源,一种是USB一直接通5V电源
四、STM32F407库函数配置USB
4.1 资料准备
(1)SD卡带文件系统的基本工程
(2)USB源码
链接:https://pan.baidu.com/s/1Cy1WokfpHBpDONfbqT_wgQ?pwd=8888
提取码:8888
4.2 移植过程
4.3 修改错误
编译,报12个错误,从第一个错误解决(解决完一个问题可以尝试编译以下)
(1)添加头文件 #include "stm32f4xx.h"
(2)添加宏定义 USE_USB_OTG_FS
(3)修改usbh_usr.c和usbh_usr.h文件
cpp
#include "usbh_usr.h"
#include "ff.h"
#include "usart.h"
static u8 AppState;
extern USB_OTG_CORE_HANDLE USB_OTG_Core;
//USB OTG 中断服务函数
//处理所有USB中断
void OTG_FS_IRQHandler(void)
{
USBH_OTG_ISR_Handler(&USB_OTG_Core);
}
//USB HOST 用户回调函数.
USBH_Usr_cb_TypeDef USR_Callbacks=
{
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
};
/
//以下为各回调函数实现.
//USB HOST 初始化
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");
}
//检测到U盘插入
void USBH_USR_DeviceAttached(void)//U盘插入
{
printf("检测到USB设备插入!\r\n");
}
//检测到U盘拔出
void USBH_USR_DeviceDisconnected (void)//U盘移除
{
printf("USB设备拔出!\r\n");
}
//复位从机
void USBH_USR_ResetDevice(void)
{
printf("复位设备...\r\n");
}
//检测到从机速度
//DeviceSpeed:从机速度(0,1,2 / 其他)
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");
}
}
//检测到从机的描述符
//DeviceDesc:设备描述符指针
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);
}
//从机地址分配成功
void USBH_USR_DeviceAddressAssigned(void)
{
printf("从机地址分配成功!\r\n");
}
//配置描述符获有效
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");
}
}
//获取到设备Manufacturer String
void USBH_USR_Manufacturer_String(void *ManufacturerString)
{
printf("Manufacturer: %s\r\n",(char *)ManufacturerString);
}
//获取到设备Product String
void USBH_USR_Product_String(void *ProductString)
{
printf("Product: %s\r\n",(char *)ProductString);
}
//获取到设备SerialNum String
void USBH_USR_SerialNum_String(void *SerialNumString)
{
printf("Serial Number: %s\r\n",(char *)SerialNumString);
}
//设备USB枚举完成
void USBH_USR_EnumerationDone(void)
{
printf("设备枚举完成!\r\n\r\n");
}
//无法识别的USB设备
void USBH_USR_DeviceNotSupported(void)
{
printf("无法识别的USB设备!\r\n\r\n");
}
//等待用户输入按键,执行下一步操作
USBH_USR_Status USBH_USR_UserInput(void)
{
printf("跳过用户确认步骤!\r\n");
return USBH_USR_RESP_OK;
}
//USB接口电流过载
void USBH_USR_OverCurrentDetected (void)
{
printf("端口电流过大!!!\r\n");
}
extern u8 USH_User_App(void); //用户测试主程序
//USB HOST MSC类用户应用程序
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;
}
//用户要求重新初始化设备
void USBH_USR_DeInit(void)
{
AppState=USH_USR_FS_INIT;
}
//无法恢复的错误!!
void USBH_USR_UnrecoveredError (void)
{
printf("无法恢复的错误!!!\r\n\r\n");
}
//用户定义函数,实现fatfs diskio的接口函数
extern USBH_HOST USB_Host;
//获取U盘状态
//返回值:0,U盘未就绪
// 1,就绪
u8 USBH_UDISK_Status(void)
{
return HCD_IsDeviceConnected(&USB_OTG_Core);//返回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;
}
//写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;
}
cpp
/**
******************************************************************************
* @file usbh_usr.h
* @author MCD Application Team
* @version V2.1.0
* @date 19-March-2012
* @brief Header file for usbh_usr.c
******************************************************************************
* @attention
*
* <h2><center>© COPYRIGHT 2012 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __USH_USR_H__
#define __USH_USR_H__
/* Includes ------------------------------------------------------------------*/
#include "ff.h"
#include "usbh_core.h"
#include "usb_conf.h"
#include <stdio.h>
#include "usbh_msc_core.h"
#include "usb_hcd_int.h"
/** @addtogroup USBH_USER
* @{
*/
/** @addtogroup USBH_MSC_DEMO_USER_CALLBACKS
* @{
*/
/** @defgroup USBH_USR
* @brief This file is the Header file for usbh_usr.c
* @{
*/
/** @defgroup USBH_USR_Exported_Types
* @{
*/
extern USBH_Usr_cb_TypeDef USR_Callbacks;
/**
* @}
*/
/** @defgroup USBH_USR_Exported_Defines
* @{
*/
/* State Machine for the USBH_USR_ApplicationState */
#define USH_USR_FS_INIT 0
#define USH_USR_FS_TEST 1
/**
* @}
*/
/** @defgroup USBH_USR_Exported_Macros
* @{
*/
/**
* @}
*/
/** @defgroup USBH_USR_Exported_Variables
* @{
*/
extern uint8_t USBH_USR_ApplicationState ;
/**
* @}
*/
/** @defgroup USBH_USR_Exported_FunctionsPrototype
* @{
*/
void USBH_USR_ApplicationSelected(void);
void USBH_USR_Init(void);
void USBH_USR_DeInit(void);
void USBH_USR_DeviceAttached(void);
void USBH_USR_ResetDevice(void);
void USBH_USR_DeviceDisconnected (void);
void USBH_USR_OverCurrentDetected (void);
void USBH_USR_DeviceSpeedDetected(uint8_t DeviceSpeed);
void USBH_USR_Device_DescAvailable(void *);
void USBH_USR_DeviceAddressAssigned(void);
void USBH_USR_Configuration_DescAvailable(USBH_CfgDesc_TypeDef * cfgDesc,
USBH_InterfaceDesc_TypeDef *itfDesc,
USBH_EpDesc_TypeDef *epDesc);
void USBH_USR_Manufacturer_String(void *);
void USBH_USR_Product_String(void *);
void USBH_USR_SerialNum_String(void *);
void USBH_USR_EnumerationDone(void);
USBH_USR_Status USBH_USR_UserInput(void);
void USBH_USR_DeInit(void);
void USBH_USR_DeviceNotSupported(void);
void USBH_USR_UnrecoveredError(void);
int USBH_USR_MSC_Application(void);
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);
/**
* @}
*/
#endif /*__USH_USR_H__*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
编译之后只存在3个错误
(4)修改diski.c文件,添加对U盘的访问
cpp
/*-----------------------------------------------------------------------*/
/* Low level disk I/O module SKELETON for FatFs (C)ChaN, 2019 */
/*-----------------------------------------------------------------------*/
/* If a working storage control module is available, it should be */
/* attached to the FatFs via a glue function rather than modifying it. */
/* This is an example of glue functions to attach various exsisting */
/* storage control modules to the FatFs module with a defined API. */
/*-----------------------------------------------------------------------*/
#include "ff.h" /* Obtains integer types */
#include "diskio.h" /* Declarations of disk functions */
#include "sdio_sdcard.h"
#include "usbh_usr.h"
/* Definitions of physical drive number for each drive */
#define DEV_MMC 1 /* Example: Map MMC/SD card to physical drive 0 */
#define DEV_USB 0 /* Example: Map USB MSD to physical drive 1 */
#define DEV_RAM 2 /* Example: Map Ramdisk to physical drive 2 */
/*-----------------------------------------------------------------------*/
/* Get Drive Status */
/*-----------------------------------------------------------------------*/
DSTATUS disk_status (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
switch (pdrv)
{
case DEV_RAM :
break;
case DEV_MMC :
break;
case DEV_USB :
return 0;
}
return STA_NOINIT;
}
/*-----------------------------------------------------------------------*/
/* Inidialize a Drive */
/*-----------------------------------------------------------------------*/
DSTATUS disk_initialize (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
int result;
switch (pdrv)
{
case DEV_RAM :
break;
case DEV_MMC :
break;
case DEV_USB :
if(USBH_UDISK_Status())return 0; //U盘连接成功,则返回1.否则返回0
break;
}
return STA_NOINIT;
}
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
/*-----------------------------------------------------------------------*/
DRESULT disk_read (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
BYTE *buff, /* Data buffer to store read data */
LBA_t sector, /* Start sector in LBA */
UINT count /* Number of sectors to read */
)
{
int result;
switch (pdrv)
{
case DEV_RAM :
break;
case DEV_MMC :
break;
case DEV_USB :
result=USBH_UDISK_Read(buff,sector,count);
if(result==0) return 0;
}
return RES_PARERR;
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
/*-----------------------------------------------------------------------*/
#if FF_FS_READONLY == 0
DRESULT disk_write (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
const BYTE *buff, /* Data to be written */
LBA_t sector, /* Start sector in LBA */
UINT count /* Number of sectors to write */
)
{
int res;
switch (pdrv)
{
case DEV_RAM :
break;
case DEV_MMC :
break;
case DEV_USB :
res=USBH_UDISK_Write((u8*)buff,sector,count);
if(res==0) return 0;
break;
}
return RES_PARERR;
}
#endif
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
/*-----------------------------------------------------------------------*/
DRESULT disk_ioctl (
BYTE pdrv, /* Physical drive nmuber (0..) */
BYTE cmd, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
int res=0;
switch (pdrv)
{
case DEV_RAM :
break;
case DEV_MMC :
break;
case DEV_USB :
res=1;
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;
}
}
if(res==1) return 0;
return RES_PARERR;
}
DWORD get_fattime (void)
{
return 0;
}
(5)修改ffconf.h文件,将_VOLUME的值改成2,以支持2个磁盘(SD卡和U盘)
cpp
#define FF_VOLUMES 2//支持2个磁盘(SD卡和U盘)
(6)修改usb_bsp.c文件
cpp
#include "usb_bsp.h"
#include "sys.h"
#include "delay.h"
//USB主机电源控制口
#define USB_HOST_PWRCTRL PAout(15) //PA15
void USB_OTG_BSP_Init(USB_OTG_CORE_HANDLE *pdev)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOA , ENABLE);
RCC_AHB2PeriphClockCmd( RCC_AHB2Periph_OTG_FS , ENABLE);
GPIO_InitStructure.GPIO_Pin = 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_InitStructure.GPIO_Pin = GPIO_Pin_15;
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);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource12,GPIO_AF_OTG_FS);
}
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;
NVIC_InitStructure.NVIC_IRQChannelSubPriority =0x03;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
//USB OTG 中断设置,开启USB FS中断
//pdev:USB OTG内核结构体指针
void USB_OTG_BSP_DisableInterrupt(void)
{
}
//USB OTG 端口供电设置(本例程未用到)
//pdev:USB OTG内核结构体指针
//state:0,断电;1,上电
void USB_OTG_BSP_DriveVBUS(USB_OTG_CORE_HANDLE *pdev, uint8_t state)
{
}
//USB_OTG 端口供电IO配置(本例程未用到)
//pdev:USB OTG内核结构体指针
void USB_OTG_BSP_ConfigVBUS(USB_OTG_CORE_HANDLE *pdev)
{
}
//USB_OTG us级延时函数
//本例程采用SYSTEM文件夹的delay.c里面的delay_us函数实现
//官方例程采用的是定时器2来实现的.
//usec:要延时的us数.
void USB_OTG_BSP_uDelay (const uint32_t usec)
{
delay_us(usec);
}
//USB_OTG ms级延时函数
//本例程采用SYSTEM文件夹的delay.c里面的delay_ms函数实现
//官方例程采用的是定时器2来实现的.
//msec:要延时的ms数.
void USB_OTG_BSP_mDelay (const uint32_t msec)
{
delay_ms(msec);
}
4.4 main.c函数
cpp
USBH_HOST USB_Host;
USB_OTG_CORE_HANDLE USB_OTG_Core;
FATFS fs[2];
//U盘插入以后,实现用户需要实现的功能
//返回值:0,正常
// 1,有问题
u8 USH_User_App(void)
{
u8 result=0;
printf("USB设备连接成功\r\n");
result=f_mount(&fs[1],"1:",1); //重新挂载U盘
printf("f_mount %d\r\n",result);
while(HCD_IsDeviceConnected(&USB_OTG_Core))//只要U盘是连接状态,则一直执行while循环
{
}
f_mount(0,"1:",1); //卸载U盘
printf("USB设备连接中\r\n");
return result;
}
main()
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
delay_init(168); //初始化延时函数
uart_init(115200); //初始化串口波特率为115200
//初始化USB主机
USBH_Init(&USB_OTG_Core,USB_OTG_FS_CORE_ID,&USB_Host,&USBH_MSC_cb,&USR_Callbacks);
while(1)
{
USBH_Process(&USB_OTG_Core, &USB_Host);//用于实现USB主机通信的核心状态机处理,该函数必须被循环调用,而且调用频率越快越好,以便及时处理各种事务
}
}
注意:如果只有一个设备的情况下需要先挂载0磁盘,然后下一个设备挂载1磁盘。因为如果直接挂载1磁盘,他挂载不会报错,但是打开文件时报错,The volume has no work area。
4.5 测试结果
4.6 完整工程代码
链接:https://pan.baidu.com/s/1-zBpkGQRTFZnnn-ZNXB3dg
提取码:生日
五、STM32Cubemx配置USB
下面配置USB为存储设备,单片机对U盘数据进行读写
5.1 配置时钟
5.2 配置USB为全速模式(没有PHY芯片只能配置为全速模式)
5.3 配置USB电源控制引脚,看原理图,然后将该引脚配置为输出,并输出高低电平使USB开启供电
5.4 配置USB_HOST模式
5.5 配置FATFS文件系统
5.6 配置USB时钟,USB时钟必须使48Mhz
5.7 将堆栈设置大一些,防止USB调用malloc申请内存空间时失败进入硬件中断错误。
5.7 生成文件
5.8 加入测试代码
1、 在main.c文件中前面加入如下代码
cpp
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
extern ApplicationTypeDef Appli_state;
extern USBH_HandleTypeDef hUsbHostFS;
extern char USBHPath[4]; // USBH logical drive path
FATFS FatfsUDisk; // File system object for USB disk logical drive
FIL myFile; // File object
static void MSC_Application(void)
{
FRESULT fres; // FatFs function common result code
uint32_t byteswrite;
uint8_t str[] = "hello world!";
/* Register the file system object to the FatFs module */
if( f_mount(&FatfsUDisk, (TCHAR const*)USBHPath, 0) != FR_OK)
{
Error_Handler(); //FatFs Initialization Error
}
else
{
/* Create and Open a new text file object with write access */
if(f_open(&myFile, "test.txt", FA_CREATE_ALWAYS | FA_WRITE) != FR_OK)
{
Error_Handler(); //'STM32.TXT' file Open for write Error
}
else
{
fres = f_write(&myFile, str, sizeof(str), (void *)&byteswrite);
if(byteswrite == 0 || (fres != FR_OK))
{
Error_Handler();
}
else
{
f_close(&myFile); //Close the open text file
}
}
}
}
/* USER CODE END 0 */
2、 在main.c文件中 int main(void) 函数中 while(1)内加入如下代码
cpp
while (1)
{
MX_USB_HOST_Process();
switch(Appli_state)
{
case APPLICATION_READY:
MSC_Application();
Appli_state = APPLICATION_DISCONNECT;
break;
case APPLICATION_DISCONNECT:
f_mount(NULL, "", 0);
break;
default:
break;
}
}
3、 插上U盘,运行代码一小段时间后,取下U盘,插入电脑看是否有代码中建立的文件及写入文件的内容!有则成功啦!
六、STM32F407实现USB在线升级
USB和文件系统移植成功后,就可以开始主函数的书写
首先主函数里面需要循环调用USBH_Process函数,它的作用是:用于实现USB主机通信的核心状态机处理,该函数必须被循环调用,而且调用频率越快越好,以便及时处理各种事务
其次,当设备检测到USB的插入后,会自动跳转到USH_User_App函数,此时我们需要在该函数中加入程序升级的代码,具体思路如下:读.bin文件,然后下载到指令地址,最后跳转到指令地址运行。
最后,总体实现代码如下所示。
cpp
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "key.h"
#include "sdio_sdcard.h"
#include "ff.h"
#include "string.h"
#include "usbh_usr.h"
#include "flash.h"
//首先对内部Flash空间进行划分,前128K用于存储BootLoader程序,后面的空间用于存储App程序。
#define IAP_SIZE ((uint32_t)0x60000) /* 128Kbytes as IAP size */
#define APPLICATIONADDRESS ((uint32_t)0x08060000) /* User start code space */
#define APPLICATIONSIZE ((uint32_t)0x080E0000)
#define BUF_SIZE 128
u8 buf[BUF_SIZE+5];
USBH_HOST USB_Host;
USB_OTG_CORE_HANDLE USB_OTG_Core;
int writeNewProgram(void);
typedef void (*pFunction)(void);
pFunction Jump_To_Application;
uint32_t JumpAddress;
//跳转到App程序运行
void jumpToApp(void)
{
if ( ( ( * ( __IO uint32_t * ) APPLICATIONADDRESS ) & 0x2FFE0000 ) == 0x20000000 ) //检查栈顶地址是否有数据,FLASH写入成功
{
printf("正在跳转运行程序\r\n");
JumpAddress = *(__IO uint32_t*) (APPLICATIONADDRESS + 4);//用户代码区第二个字为程序开始地址(复位地址)
Jump_To_Application = (pFunction) JumpAddress;//初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
MSR_MSP(*(vu32*)APPLICATIONADDRESS); //初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
RCC_AHB2PeriphClockCmd( RCC_AHB2Periph_OTG_FS , DISABLE); //必须失能USB,不然后续代码会因为USB卡死
Jump_To_Application();
}
}
//U盘插入以后,实现用户需要实现的功能
//返回值:0,正常
// 1,有问题
u8 USH_User_App(void)
{
u8 result=0;
printf("USB设备连接成功\r\n");
if(!writeNewProgram())
jumpToApp();
while(HCD_IsDeviceConnected(&USB_OTG_Core))//只要U盘是连接状态,则一直执行while循环
{
}
printf("USB设备连接中\r\n");
return result;
}
int writeNewProgram(void)
{
FRESULT result;
FIL fil;
FATFS fs;
int isFinish = 0;
int bytesread;
char *fileName="LED.bin";
uint32_t startaddress = APPLICATIONADDRESS;
uint32_t endaddress = APPLICATIONSIZE;
printf("start write new program");
result=f_mount(&fs,"0:",1); //重新挂载U盘
printf("f_mount %d\r\n",result);
result = f_open(&fil,fileName, FA_READ );//打开程序文件
printf("f_open %d\r\n",result);
if(result)
{
printf("open %s error\r\n",fileName);
isFinish=1;
}
else
{
printf("open %s sucess\r\n",fileName);
}
printf("start program\r\n");
while( startaddress < endaddress && isFinish == 0)
{
result = f_read(&fil, buf,BUF_SIZE, (UINT*)&bytesread);//读取128Bytes数据
if(result)
{
printf("read address error\r\n");
isFinish=1;
break;
}
else
{
printf("read address sucess ,data is :%d\r\n",bytesread);
}
if(STMFLASH_Write(startaddress,(uint32_t *)buf,bytesread/4))
{
printf("STMFLASH_Write err\r\n");
}
else
{
printf("STMFLASH_Write OK\r\n");
}
startaddress += bytesread;
if( bytesread < BUF_SIZE )//如果读取数据长度错误或者读取完毕
{
break;
}
}
result = f_close(&fil);
if(result)
{
printf("close %s error:%d\r\n",fileName,result);
}
else
{
printf("close %s sucess\r\n",fileName);
}
printf("end write program\r\n");
result=f_mount(NULL,"0:",0);
return isFinish;
}
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
delay_init(168); //初始化延时函数
uart_init(115200); //初始化串口波特率为115200
//初始化USB主机
USBH_Init(&USB_OTG_Core,USB_OTG_FS_CORE_ID,&USB_Host,&USBH_MSC_cb,&USR_Callbacks);
while(1)
{
USBH_Process(&USB_OTG_Core, &USB_Host);//用于实现USB主机通信的核心状态机处理,该函数必须被循环调用,而且调用频率越快越好,以便及时处理各种事务
}
}
链接:https://pan.baidu.com/s/18uUT0wrLKnioZBnBwAgD6w
提取码:生日
七、STM32 USB DEVICE 复位后 无法识别
现象是,如果USB一直处于插着状态,软件复位后,无法识别USB插入,那么就在USB初始化前强制USB时钟复位,就相当于告诉电脑断开链接。
cpp
void USB_Disconnected(void) {
__HAL_RCC_USB_FORCE_RESET();
HAL_Delay(200);
__HAL_RCC_USB_RELEASE_RESET();
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_Initure.Pin = GPIO_PIN_11 | GPIO_PIN_12;
GPIO_Initure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_Initure.Pull = GPIO_PULLDOWN;
GPIO_Initure.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_Initure);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_11, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_12, GPIO_PIN_RESET);
HAL_Delay(300);
}