硬件: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的起始地址。