USB和文件系统移植成功后,就可以开始主函数的书写
首先主函数里面需要循环调用USBH_Process函数,它的作用是:用于实现USB主机通信的核心状态机处理,该函数必须被循环调用,而且调用频率越快越好,以便及时处理各种事务
其次,当设备检测到USB的插入后,会自动跳转到USH_User_App函数,此时我们需要在该函数中加入程序升级的代码,具体思路如下:读.bin文件,然后下载到指令地址,最后跳转到指令地址运行。
最后,总体实现代码如下所示。
#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
提取码:生日