HAL库 通过USB Boot进行APP程序升级

硬件:stm32f407VET6芯片;

软件:STM32CubeMx、Keil5

上位机:Dfuse DemoV3.06

    这里给出通过在Bootlaoder中使用USB方式来更新APP程序的方法,首先我们编写一个自己的bootloader,关于bootloader的大致原理可以参考我之前的文章HAL库执行bootloader跳转操作:_hal库bootloader-优快云博客,这里boot升级我采用单APP升级的方式 ,主要分为三部分讲解:

    一、程序配置和Bootlaoder编写;

    二、Dfuse DemoV3.06上位机和对应USB驱动安装;

    三、使用上位机配合Boot程序进行USB方式的单APP升级;

一、程序配置和Bootlaoder编写

    这里我们先打开cubemx配置芯片的USB硬件模式,需要使能USB_OTG_FS,设置如下图,需要注意开启USB的NVIC中断;

    使能完USB硬件后,我们还需要配置USB工作在DFU模式,DFU全称为Download Firmware Update,是ST官方推出的一个通过USB接口进行IAP升级的方案,我们就是通过该模式来进行Boot升级,相关配置如下:

    需要注意的是下图中关于“USBD_DFU_APP_DEFAULT_ADD(Base_Address)”这里设置的值为我们APP程序的起始地址,这里我将APP程序起始地址设为0x08010000;

     将上述程序进行生成,然后在生成的文件中找到usbd_dfu_if.c文件并打开,添加Flash操作相关代码分别是 上锁、解锁、擦除、写入、读取、返回Flash操作时间,代码如下:

/* Private functions ---------------------------------------------------------*/
/**
  * @brief  Memory initialization routine.
  * @retval USBD_OK if operation is successful, MAL_FAIL else.
  */
uint16_t MEM_If_Init_FS(void)
{
  /* USER CODE BEGIN 0 */
	HAL_FLASH_Unlock();
  __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR);
  return (USBD_OK);
  /* USER CODE END 0 */
}

/**
  * @brief  De-Initializes Memory
  * @retval USBD_OK if operation is successful, MAL_FAIL else
  */
uint16_t MEM_If_DeInit_FS(void)
{
  /* USER CODE BEGIN 1 */
	HAL_FLASH_Lock();
  return (USBD_OK);
  /* USER CODE END 1 */
}

/**
  * @brief  Erase sector.
  * @param  Add: Address of sector to be erased.
  * @retval 0 if operation is successful, MAL_FAIL else.
  */
uint16_t MEM_If_Erase_FS(uint32_t Add)
{
  /* USER CODE BEGIN 2 */
  UNUSED(Add);
	uint32_t error = 0;
	FLASH_EraseInitTypeDef flash_dat;          //定义一个结构体变量,里面有擦除操作需要定义的变量
	
	HAL_FLASH_Unlock();                                    //第二步:解锁                        
	flash_dat.TypeErase = FLASH_TYPEERASE_SECTORS;         //擦除类型是“Page Erase” 仅删除页面 另外一个参数是全部删除
	flash_dat.Sector = FLASH_SECTOR_5;            //擦除地址对应的页
	flash_dat.NbSectors = 1;                               //一次性擦除1页,可以是任意页
	flash_dat.Banks=FLASH_BANK_1;
	flash_dat.VoltageRange=FLASH_VOLTAGE_RANGE_3;
	HAL_FLASHEx_Erase(&flash_dat,&error);            //第三步:参数写好后调用擦除函数

  return (USBD_OK);
  /* USER CODE END 2 */
}

/**
  * @brief  Memory write routine.
  * @param  src: Pointer to the source buffer. Address to be written to.
  * @param  dest: Pointer to the destination buffer.
  * @param  Len: Number of data to be written (in bytes).
  * @retval USBD_OK if operation is successful, MAL_FAIL else.
  */
uint16_t MEM_If_Write_FS(uint8_t *src, uint8_t *dest, uint32_t Len)
{
  /* USER CODE BEGIN 3 */
  UNUSED(src);
  UNUSED(dest);
  UNUSED(Len);
	uint32_t i = 0;
	for(i=0;i<Len;i+=4)
	{		
		HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, (uint32_t)(dest + i), *(uint32_t *)(src + i));
		if(*(uint32_t *)(src + i) != *(uint32_t *)(dest + i))
		{
				/* Flash content doesn't match SRAM content */
				return (USBD_FAIL);
		}
	}
	
  return (USBD_OK);
  /* USER CODE END 3 */
}

/**
  * @brief  Memory read routine.
  * @param  src: Pointer to the source buffer. Address to be written to.
  * @param  dest: Pointer to the destination buffer.
  * @param  Len: Number of data to be read (in bytes).
  * @retval Pointer to the physical address where data should be read.
  */
uint8_t *MEM_If_Read_FS(uint8_t *src, uint8_t *dest, uint32_t Len)
{
  /* Return a valid address to avoid HardFault */
  /* USER CODE BEGIN 4 */
  UNUSED(src);
  UNUSED(dest);
  UNUSED(Len);
	uint32_t i = 0;
	uint8_t *psrc = src;

	for (i = 0; i < Len; i++)
	{
		dest[i] = *psrc++;
	}
	/* Return a valid address to avoid HardFault */
	return (uint8_t *)(dest);
  /* USER CODE END 4 */
}

/**
  * @brief  Get status routine
  * @param  Add: Address to be read from
  * @param  Cmd: Number of data to be read (in bytes)
  * @param  buffer: used for returning the time necessary for a program or an erase operation
  * @retval USBD_OK if operation is successful
  */
uint16_t MEM_If_GetStatus_FS(uint32_t Add, uint8_t Cmd, uint8_t *buffer)
{
  /* USER CODE BEGIN 5 */
  UNUSED(Add);
  UNUSED(buffer);

	uint16_t FLASH_PROGRAM_TIME = 50;
	uint16_t FLASH_ERASE_TIME = 50;

	switch(Cmd)
	{
	case DFU_MEDIA_PROGRAM:
			buffer[1] = (uint8_t)FLASH_PROGRAM_TIME;
			buffer[2] = (uint8_t)(FLASH_PROGRAM_TIME << 8);
			buffer[3] = 0;
			break;
	case DFU_MEDIA_ERASE:
	default:
			buffer[1] = (uint8_t)FLASH_ERASE_TIME;
	}

  return (USBD_OK);
  /* USER CODE END 5 */
}

      配置好USB升级方式后,我们就需要编写Boot程序中关于升级的一些判断,这里的判断根据不同的交互方式有所不同,有些使用串口通讯交互,有些使用按键+指示灯/屏幕交互,这里我使用的是按键+屏幕交互,按键接入单片机Wake_Up引脚,Bootloader和APP大体程序执行流程如下:

参考文章:

【STM32】HAL库USB实现软件升级DFU的功能操作及配置_stm32f205 dfu-优快云博客

STM32 USB的DFU模式升级_stm32 dfu-优快云博客

二、Dfuse DemoV3.06上位机和对应USB驱动安装

1、下载Dfuse DemoV3.06上位机安装包,下载地址如下:

STSW-STM32080 - DfuSe USB device firmware upgrade (UM0412) - STMicroelectronics

2、点击下述红色方框中的安装文件,一直点“next”直至完成安装;

3、通过USB线连接电脑和单片机的USB接口,进入单片机BOOT升级模式,此时打开windows设备管理器,查看连接设备,出现下述图标是因为没有安装Dfuse Demo相关驱动,这里我们右键有感叹号的设备,选择“更新驱动程序”,选择“浏览我的电脑以查找驱动程序”

  这里驱动程序的路径如下,根据电脑的系统选择相应的文件夹,这里由于我的电脑是win10系统,我就选择“win10”文件夹作为驱动路径

如下图,选择完驱动路径后点击“下一步”等待驱动安装即可,

    安装完后再在“设备管理器”可以看到下述两种情况,都表示驱动安装成功。(针对本人的USB Boot升级程序,驱动安装成功后单片机仍处于BOOT模式,此时我们只需要长按wake_up键3s左右等待单片机关机以退出BOOT模式,后面正常使用即可;)

    三、使用上位机配合Boot程序进行USB方式的单APP升级

  1、通过USB线连接电脑和单片机的USB接口,使单片机进入BOOT模式,打开Dfuse Demo程序

  2、程序左上角红框内显示设备名称即表示连接正常,此时点击上位机下方“Choose...”加载我们提供的.dfu格式的升级文件

  3、提示加载完毕,并选择“Verify after download”

4、点击“Upgrade”按钮,有个弹窗,选择“是”,然后等待Boot升级程序

5、出现下述红框中的内容表示升级成功。(针对本人的Boot程序,需要再次长按wake_up键3s左右等待单片机进入深度休眠以退出BOOT模式,后面正常使用即可)

    注意如果未安装驱动、单片机不处于BOOT模式、电脑未和单片机连接等异常情况,上位机界面左上角是空的;

如何生成.dfu文件:

1、生成app程序bin文件:

2、将bin文件转化为.dfu文件:

官方DFU固件更新软件实现对STM32的USB方式代码升级简易说明(STM32-V5开发板) - 开发环境 - 硬汉嵌入式论坛 - Powered by Discuz!

    下面这里的Address填APP的起始地址。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值