STM32CbueMX之 USB下载更新固件Download Firmware Update(DFU)之一BootLoader程序编写

本文主要是介绍STM32CbueMX之 USB下载更新固件Download Firmware Update(DFU)之一BootLoader程序编写,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

声明:

STM32CbueMX之 USB下载更新固件Download Firmware Update(DFU)之一BootLoader程序编写https://blog.csdn.net/sudaroot/article/details/102549606
STM32CbueMX之 USB下载更新固件Download Firmware Update(DFU)之二APP编写及烧录升级https://blog.csdn.net/sudaroot/article/details/102743141
STM32CbueMX之 USB下载更新固件Download Firmware Update(DFU)之三Leave DFU mode会卡死https://blog.csdn.net/sudaroot/article/details/102746505
STM32CbueMX之 USB下载更新固件Download Firmware Update(DFU)之四FreeRTOS跳转运行失败https://blog.csdn.net/sudaroot/article/details/102800541

以下内容参考:

C:\Users\admin\STM32Cube\Repository\STM32Cube_FW_F4_V1.24.1\Projects\STM324xG_EVAL\Applications\USB_Device\DFU_Standalone

背景:

如果产品有USB电路且接口外露都适用,连上USB,打开DfuSe_Demo烧录固件,即可完成固件更新。

固件就是烧录在单片机的软件。

如果你使用的是F4以上的系列,boot0接高,boot1接地,进入系统启动模式,接上usb线PC,即可看到DFU模式。

F4系列默认系统BootLoader自带DFU程序。

需求:

1、做一个平时上电就运行固件,做一个LED闪烁。

2、当我们按住板子某个按键    上电就运行UFD模式,等待固件更新,此时LED灯常亮;

      更新完成后断电重启,即可看到新固件的现象。

硬件:

原理:

和IAP原理大同小异。

需要了解ST单片机的启动流程。

我把内部flash分成两个区域,

1、是BootLoader区域,就是带有DFU和启动(固件称为APP)的功能。起始地址:0x8000000,大小:64K。

2、是APP区域,放置项目功能代码。起始地址:0x8010000,大小:960K。

故我们需要写两个程序,一个是BootLoader程序,一个是APP程序。

简单讲一下:

上电 ST从flash 地址 0x8000000 处取代码执行。即执行BootLoader区域的程序。再判断按键是否按下,

1、没有按下则通过函数指针跳转到APP区域执行项目功能代码(跳转前需做准备工作);

2、有按下则初始化USB DFU函数,等待更新APP区域的固件,更新完成后断电重启。

安装DFU烧录软件:DfuSe_Demo

官网下载链接:

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

默认安装即可。

安装成功后得到两个软件。

Dfu file manager是把bin文件或者hex文件生成  .dfu后缀的文件,  .dfu后缀的文件就是我们的固件。

DfuSe_Demo是烧录 文件后缀   .duf  软件。

编写BootLoader程序的STM32CubeMX:

1、选择外部晶振25MHz

系统最大时钟配置为168MHz,USB时钟一定为48MHz。

2、选择USB_FS(全速)模式,选择从机模式。

2、选择DFU类;

USBD_DFU_APP_DEFAULT_ADD (Base Address 0x):0x08010000。

指你打算把固件放在哪里,以你使用的芯片flash最小页单位对齐(flash最小擦除单位是页)。这里我打算把APP放在从内部flash  64K 处起,前面放置BootLoader程序。

USBD_DFU_MEDIA Interface:@Internal Flash   /0x08000000/04*016Ka,01*064Kg,07*128Kg。

@Internal Flash   /0x08000000/04*016Ka,01*064Kg,07*128Kg。即:内部flash从0x08000000地址起,连续分配,前04*016K只读存放BootLoader程序,后面01*064K和07*128K可读可写。更详细的说明靠下面详细说明。

注意:由于芯片不同,芯片的内部flash分布情况也不一定相同,故请参考使用的芯片参考手册。

闪存的描述(由PC工具DFuSe使用)每个备用设置字符串描述符都必须遵循此内存映射,

以便PC主机软件可以解码所选设备的正确映射:

●@:检测到这是一个特殊的映射描述符(避免解码标准描述符)

●/:用于区域之间的分隔符

●每个地址以“ 0x”开头的最大8位数字

●/:用于区域之间的分隔符

●扇区数的最大2位数字

●* :用于扇区数和扇区大小之间的分隔符

●扇区大小在0到999之间的最大3位

●扇区大小乘数的1位数字。有效条目为:B(字节),K(千),M(兆)

●扇区类型的1位数字,如下所示:

        – a(0x41):可读

        – b(0x42):可擦除

        – c(0x43):可读和可擦除

              (0x44):可写

         – e(0x45):可读写

           –f(0x46):可擦除和可写

          –g(0x47):可读写,可写

注意:如果目标内存不连续,则用户可以添加斜线“ /”之后要解码的新扇区,

如以下示例所示:“ @ Flash / 0xF000 / 1 * 4Ka / 0xE000 / 1 * 4Kg / 0x8000 / 2 * 24Kg”

USB的抢占中断级别设置成15;最低的抢占中断。

原因:DfuSeDemo烧录完固件后,点击Leave DFU mode会卡死,并不会跳转到APP运行。

源码:函数 static void DFU_Leave(USBD_HandleTypeDef *pdev)逐级调用到了HAL_StatusTypeDef  USB_DevDisconnect(USB_OTG_GlobalTypeDef *USBx)会卡死在HAL_Delay(3U);,,后来仿真发现系统时钟中断没发生,准确地说是中断发生了,而由于USB中断和系统时钟中断默认都是抢占优先级最高的0,就会发生系统时钟中断不能抢到中断执行。导致节拍数一直没变,  while((HAL_GetTick() - tickstart) < wait)循环卡死。

/*** @brief  USB_DevDisconnect : Disconnect the USB device by disabling the pull-up/pull-down* @param  USBx  Selected device* @retval HAL status*/
HAL_StatusTypeDef  USB_DevDisconnect(USB_OTG_GlobalTypeDef *USBx)
{uint32_t USBx_BASE = (uint32_t)USBx;USBx_DEVICE->DCTL |= USB_OTG_DCTL_SDIS;HAL_Delay(3U);   return HAL_OK;
}

USBD_DFU_XFER_SIZE:USB数据pack大小,越大配置速度越快。默认配置1024Bytes.  1024Bytes使用的是堆空间,故堆空间要大于1024Bytes.  原因:代码如下。

#define USBD_malloc         malloc

 /* Allocate Audio structure */
  pdev->pClassData = USBD_malloc(sizeof (USBD_DFU_HandleTypeDef));

个人使用习惯是 堆 空间比1024B 大 512B 即0x600.

个人觉得这个项目的main函数生成的不适合用于这个DFU,原因是调用关系。如,我没按下按键不需要初始化USB,生成的确调用了初始化。故不生成main函数,自己写。

我的板子上PA0是按键输入,PB0是一个LED灯。(根据情况定)

最后生成代码。

生成的USB功能相关文件:

usb_device.c                初始化
usbd_conf.c                  常规低层驱动程序配置
usbd_desc.c                 USB设备描述符
usbd_dfu_if.c                内部闪存管理

usb_device.h                初始化
usbd_conf.h                 USB设备驱动程序配置文件
usbd_desc.h                USB设备描述符头文件
usbd_dfu_if.h               内部闪存管理头文件

编程

1、打开usbd_dfu_if.h添加下面F429IG内部flash分区定义

项目添加/* USER CODE BEGIN EXPORTED_DEFINES */ ~ /* USER CODE END EXPORTED_DEFINES */代码

/* USER CODE BEGIN Header */
/********************************************************************************* @file           : usbd_dfu_if.h* @brief          : Header for usbd_dfu_if.c file.******************************************************************************* @attention** <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.* All rights reserved.</center></h2>** This software component is licensed by ST under Ultimate Liberty license* SLA0044, the "License"; You may not use this file except in compliance with* the License. You may obtain a copy of the License at:*                             www.st.com/SLA0044********************************************************************************/
/* USER CODE END Header *//* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __USBD_DFU_IF_H__
#define __USBD_DFU_IF_H__#ifdef __cplusplusextern "C" {
#endif/* Includes ------------------------------------------------------------------*/
#include "usbd_dfu.h"/* USER CODE BEGIN INCLUDE *//* USER CODE END INCLUDE *//** @addtogroup STM32_USB_DEVICE_LIBRARY* @brief For Usb device.* @{*//** @defgroup USBD_MEDIA USBD_MEDIA* @brief Header file for the usbd_dfu_if.c file.* @{*//** @defgroup USBD_MEDIA_Exported_Defines USBD_MEDIA_Exported_Defines* @brief Defines.* @{*//* USER CODE BEGIN EXPORTED_DEFINES *//* Base address of the Flash sectors *//* Bank 1 */#define ADDR_FLASH_SECTOR_0     ((uint32_t)0x08000000) /* Base @ of Sector 0, 16 Kbytes */#define ADDR_FLASH_SECTOR_1     ((uint32_t)0x08004000) /* Base @ of Sector 1, 16 Kbytes */#define ADDR_FLASH_SECTOR_2     ((uint32_t)0x08008000) /* Base @ of Sector 2, 16 Kbytes */#define ADDR_FLASH_SECTOR_3     ((uint32_t)0x0800C000) /* Base @ of Sector 3, 16 Kbytes */#define ADDR_FLASH_SECTOR_4     ((uint32_t)0x08010000) /* Base @ of Sector 4, 64 Kbytes */#define ADDR_FLASH_SECTOR_5     ((uint32_t)0x08020000) /* Base @ of Sector 5, 128 Kbytes */#define ADDR_FLASH_SECTOR_6     ((uint32_t)0x08040000) /* Base @ of Sector 6, 128 Kbytes */#define ADDR_FLASH_SECTOR_7     ((uint32_t)0x08060000) /* Base @ of Sector 7, 128 Kbytes */#define ADDR_FLASH_SECTOR_8     ((uint32_t)0x08080000) /* Base @ of Sector 8, 128 Kbytes */#define ADDR_FLASH_SECTOR_9     ((uint32_t)0x080A0000) /* Base @ of Sector 9, 128 Kbytes */#define ADDR_FLASH_SECTOR_10    ((uint32_t)0x080C0000) /* Base @ of Sector 10, 128 Kbytes */#define ADDR_FLASH_SECTOR_11    ((uint32_t)0x080E0000) /* Base @ of Sector 11, 128 Kbytes *//* Bank 2 */#define ADDR_FLASH_SECTOR_12    ((uint32_t)0x08100000) /* Base @ of Sector 12, 16 Kbytes */#define ADDR_FLASH_SECTOR_13    ((uint32_t)0x08104000) /* Base @ of Sector 13, 16 Kbytes */#define ADDR_FLASH_SECTOR_14    ((uint32_t)0x08108000) /* Base @ of Sector 14, 16 Kbytes */#define ADDR_FLASH_SECTOR_15    ((uint32_t)0x0810C000) /* Base @ of Sector 15, 16 Kbytes */#define ADDR_FLASH_SECTOR_16    ((uint32_t)0x08110000) /* Base @ of Sector 16, 64 Kbytes */#define ADDR_FLASH_SECTOR_17    ((uint32_t)0x08120000) /* Base @ of Sector 17, 128 Kbytes */#define ADDR_FLASH_SECTOR_18    ((uint32_t)0x08140000) /* Base @ of Sector 18, 128 Kbytes */#define ADDR_FLASH_SECTOR_19    ((uint32_t)0x08160000) /* Base @ of Sector 19, 128 Kbytes */#define ADDR_FLASH_SECTOR_20    ((uint32_t)0x08180000) /* Base @ of Sector 20, 128 Kbytes */#define ADDR_FLASH_SECTOR_21    ((uint32_t)0x081A0000) /* Base @ of Sector 21, 128 Kbytes */#define ADDR_FLASH_SECTOR_22    ((uint32_t)0x081C0000) /* Base @ of Sector 22, 128 Kbytes */#define ADDR_FLASH_SECTOR_23    ((uint32_t)0x081E0000) /* Base @ of Sector 23, 128 Kbytes */
/* USER CODE END EXPORTED_DEFINES *//*** @}*//** @defgroup USBD_MEDIA_Exported_Types USBD_MEDIA_Exported_Types* @brief Types.* @{*//* USER CODE BEGIN EXPORTED_TYPES *//* USER CODE END EXPORTED_TYPES *//*** @}*//** @defgroup USBD_MEDIA_Exported_Macros USBD_MEDIA_Exported_Macros* @brief Aliases.* @{*//* USER CODE BEGIN EXPORTED_MACRO *//* USER CODE END EXPORTED_MACRO *//*** @}*//** @defgroup USBD_MEDIA_Exported_Variables USBD_MEDIA_Exported_Variables* @brief Public variables.* @{*//** MEDIA Interface callback. */
extern USBD_DFU_MediaTypeDef USBD_DFU_fops_FS;/* USER CODE BEGIN EXPORTED_VARIABLES *//* USER CODE END EXPORTED_VARIABLES *//*** @}*//** @defgroup USBD_MEDIA_Exported_FunctionsPrototype USBD_MEDIA_Exported_FunctionsPrototype* @brief Public functions declaration.* @{*//* USER CODE BEGIN EXPORTED_FUNCTIONS *//* USER CODE END EXPORTED_FUNCTIONS *//*** @}*//*** @}*//*** @}*/#ifdef __cplusplus
}
#endif#endif /* __USBD_DFU_IF_H__ *//************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

2、打开usbd_dfu_if.c填充下面函数

    MEM_If_Init_FS,             闪存初始化,解锁内部flash。
    MEM_If_DeInit_FS,        闪存反(取消)初始化,上锁内部flash。
    MEM_If_Erase_FS,        闪存擦除。
    MEM_If_Write_FS,         闪存写入。
    MEM_If_Read_FS,         闪存读取。
    MEM_If_GetStatus_FS  获取闪存状态,返回写入或擦除操作所需的时间。

/* USER CODE BEGIN Header */
/********************************************************************************* @file           : usbd_dfu_if.c* @brief          : Usb device for Download Firmware Update.******************************************************************************* @attention** <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.* All rights reserved.</center></h2>** This software component is licensed by ST under Ultimate Liberty license* SLA0044, the "License"; You may not use this file except in compliance with* the License. You may obtain a copy of the License at:*                             www.st.com/SLA0044********************************************************************************/
/* USER CODE END Header *//* Includes ------------------------------------------------------------------*/
#include "usbd_dfu_if.h"/* USER CODE BEGIN INCLUDE *//* USER CODE END INCLUDE *//* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*//* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*//* USER CODE END PV *//** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY* @brief Usb device.* @{*//** @defgroup USBD_DFU* @brief Usb DFU device module.* @{*//** @defgroup USBD_DFU_Private_TypesDefinitions* @brief Private types.* @{*//* USER CODE BEGIN PRIVATE_TYPES *//* USER CODE END PRIVATE_TYPES *//*** @}*//** @defgroup USBD_DFU_Private_Defines* @brief Private defines.* @{*/#define FLASH_DESC_STR      "@Internal Flash   /0x08000000/04*016Ka,01*064Kg,07*128Kg"/* USER CODE BEGIN PRIVATE_DEFINES */
#define FLASH_ERASE_TIME    (uint16_t)50
#define FLASH_PROGRAM_TIME  (uint16_t)50
/* USER CODE END PRIVATE_DEFINES *//*** @}*//** @defgroup USBD_DFU_Private_Macros* @brief Private macros.* @{*//* USER CODE BEGIN PRIVATE_MACRO *//* USER CODE END PRIVATE_MACRO *//*** @}*//** @defgroup USBD_DFU_Private_Variables* @brief Private variables.* @{*//* USER CODE BEGIN PRIVATE_VARIABLES *//* USER CODE END PRIVATE_VARIABLES *//*** @}*//** @defgroup USBD_DFU_Exported_Variables* @brief Public variables.* @{*/extern USBD_HandleTypeDef hUsbDeviceFS;/* USER CODE BEGIN EXPORTED_VARIABLES *//* USER CODE END EXPORTED_VARIABLES *//*** @}*//** @defgroup USBD_DFU_Private_FunctionPrototypes* @brief Private functions declaration.* @{*/static uint16_t MEM_If_Init_FS(void);
static uint16_t MEM_If_Erase_FS(uint32_t Add);
static uint16_t MEM_If_Write_FS(uint8_t *src, uint8_t *dest, uint32_t Len);
static uint8_t *MEM_If_Read_FS(uint8_t *src, uint8_t *dest, uint32_t Len);
static uint16_t MEM_If_DeInit_FS(void);
static uint16_t MEM_If_GetStatus_FS(uint32_t Add, uint8_t Cmd, uint8_t *buffer);/* USER CODE BEGIN PRIVATE_FUNCTIONS_DECLARATION */
static uint32_t GetSector(uint32_t Address);
static uint32_t GetBank(uint32_t Addr);
/* USER CODE END PRIVATE_FUNCTIONS_DECLARATION *//*** @}*/#if defined ( __ICCARM__ ) /* IAR Compiler */#pragma data_alignment=4
#endif
__ALIGN_BEGIN USBD_DFU_MediaTypeDef USBD_DFU_fops_FS __ALIGN_END =
{(uint8_t*)FLASH_DESC_STR,MEM_If_Init_FS,MEM_If_DeInit_FS,MEM_If_Erase_FS,MEM_If_Write_FS,MEM_If_Read_FS,MEM_If_GetStatus_FS
};/* 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();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 */uint32_t startsector = 0, sectorerror = 0;/* Variable contains Flash operation status */HAL_StatusTypeDef status;FLASH_EraseInitTypeDef eraseinitstruct;/* Get the number of sector */startsector = GetSector(Add);eraseinitstruct.TypeErase = FLASH_TYPEERASE_SECTORS;eraseinitstruct.Banks = GetBank(Add);eraseinitstruct.Sector = startsector;eraseinitstruct.NbSectors = 1;eraseinitstruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;status = HAL_FLASHEx_Erase(&eraseinitstruct, &sectorerror);if (status != HAL_OK){return USBD_FAIL;}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 */uint32_t i = 0;for (i = 0; i < Len; i += 4){/* Device voltage range supposed to be [2.7V to 3.6V], the operation will* be done by byte */if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, (uint32_t) (dest + i),*(uint32_t*) (src + i)) == HAL_OK){/* Check the written value */if (*(uint32_t*) (src + i) != *(uint32_t*) (dest + i)){/* Flash content doesn't match SRAM content */return USBD_FAIL;}}else{/* Error occurred while writing data in Flash memory */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 */uint32_t i = 0;uint8_t *psrc = src;for (i = 0; i < Len; i++){dest[i] = *psrc++;}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 */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:buffer[1] = (uint8_t) FLASH_ERASE_TIME;buffer[2] = (uint8_t) (FLASH_ERASE_TIME << 8);buffer[3] = 0;default:break;}return (USBD_OK);/* USER CODE END 5 */
}/* USER CODE BEGIN PRIVATE_FUNCTIONS_IMPLEMENTATION */
static uint32_t GetSector(uint32_t Address)
{#if 1if (Address < ADDR_FLASH_SECTOR_1)return FLASH_SECTOR_0;else if (Address < ADDR_FLASH_SECTOR_2)return FLASH_SECTOR_1;else if (Address < ADDR_FLASH_SECTOR_3)return FLASH_SECTOR_2;else if (Address < ADDR_FLASH_SECTOR_4)return FLASH_SECTOR_3;else if (Address < ADDR_FLASH_SECTOR_5)return FLASH_SECTOR_4;else if (Address < ADDR_FLASH_SECTOR_6)return FLASH_SECTOR_5;else if (Address < ADDR_FLASH_SECTOR_7)return FLASH_SECTOR_6;else if (Address < ADDR_FLASH_SECTOR_8)return FLASH_SECTOR_7;else if (Address < ADDR_FLASH_SECTOR_9)return FLASH_SECTOR_8;else if (Address < ADDR_FLASH_SECTOR_10)return FLASH_SECTOR_9;else if (Address < ADDR_FLASH_SECTOR_11)return FLASH_SECTOR_10;return FLASH_SECTOR_11;#elseif(Address < ADDR_FLASH_SECTOR_1)       return FLASH_SECTOR_0;else if(Address < ADDR_FLASH_SECTOR_2)  return FLASH_SECTOR_1;else if(Address < ADDR_FLASH_SECTOR_3)  return FLASH_SECTOR_2;else if(Address < ADDR_FLASH_SECTOR_4)  return FLASH_SECTOR_3;else if(Address < ADDR_FLASH_SECTOR_5)  return FLASH_SECTOR_4;else if(Address < ADDR_FLASH_SECTOR_6)  return FLASH_SECTOR_5;else if(Address < ADDR_FLASH_SECTOR_7)  return FLASH_SECTOR_6;else if(Address < ADDR_FLASH_SECTOR_8)  return FLASH_SECTOR_7;else if(Address < ADDR_FLASH_SECTOR_9)  return FLASH_SECTOR_8;else if(Address < ADDR_FLASH_SECTOR_10) return FLASH_SECTOR_9;else if(Address < ADDR_FLASH_SECTOR_11) return FLASH_SECTOR_10;else if(Address < ADDR_FLASH_SECTOR_12) return FLASH_SECTOR_11;else if(Address < ADDR_FLASH_SECTOR_13) return FLASH_SECTOR_12;else if(Address < ADDR_FLASH_SECTOR_14) return FLASH_SECTOR_13;else if(Address < ADDR_FLASH_SECTOR_15) return FLASH_SECTOR_14;else if(Address < ADDR_FLASH_SECTOR_16) return FLASH_SECTOR_15;else if(Address < ADDR_FLASH_SECTOR_17) return FLASH_SECTOR_16;else if(Address < ADDR_FLASH_SECTOR_18) return FLASH_SECTOR_17;else if(Address < ADDR_FLASH_SECTOR_19) return FLASH_SECTOR_18;else if(Address < ADDR_FLASH_SECTOR_20) return FLASH_SECTOR_19;else if(Address < ADDR_FLASH_SECTOR_21) return FLASH_SECTOR_20;else if(Address < ADDR_FLASH_SECTOR_22) return FLASH_SECTOR_21;else if(Address < ADDR_FLASH_SECTOR_23) return FLASH_SECTOR_22;return FLASH_SECTOR_23;#endif
}/*** @brief  Gets the bank of a given address* @param  Addr: Address of the FLASH Memory* @retval The bank of a given address*/
static uint32_t GetBank(uint32_t Addr)
{uint32_t bank = 0;/* Sector in bank 1 */#if 1bank = FLASH_BANK_1;#elseif(Addr < ADDR_FLASH_SECTOR_12) bank = FLASH_BANK_1;else bank = FLASH_BANK_2;#endifreturn bank;
}
/* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION *//*** @}*//*** @}*//************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

main.c

static void USB_GPIO_DeInit(void); USB引脚复位功能,效果就是模拟上电USB拔出100ms再插上。以前博客有详细说。

static void JumpToApp(void);跳转到APP函数。

#include <stdio.h>int fputc(int ch, FILE* FILE)
{HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, HAL_MAX_DELAY);return ch;
}static void USB_GPIO_DeInit(void)
{GPIO_InitTypeDef GPIO_InitStruct = {0};/* GPIO Ports Clock Enable */__HAL_RCC_GPIOA_CLK_ENABLE();/*Configure GPIO pin Output Level */HAL_GPIO_WritePin(GPIOA, GPIO_PIN_11 | GPIO_PIN_12, GPIO_PIN_RESET);/*Configure GPIO pin : BLINK_LED_Pin */GPIO_InitStruct.Pin = GPIO_PIN_11 | GPIO_PIN_12;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_PULLDOWN;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);HAL_Delay(100);
}static void JumpToApp(void)
{typedef  void (*pFunction)(void);static pFunction JumpToApplication;static uint32_t JumpAddress;/* Test if user code is programmed starting from USBD_DFU_APP_DEFAULT_ADD * address */if (((*(__IO uint32_t *) USBD_DFU_APP_DEFAULT_ADD) & 0x2FFC0000) == 0x20000000){/* Jump to user application */JumpAddress = *(__IO uint32_t *) (USBD_DFU_APP_DEFAULT_ADD + 4);JumpToApplication = (pFunction) JumpAddress;/* Initialize user application's Stack Pointer */__set_MSP((*(__IO uint32_t *) USBD_DFU_APP_DEFAULT_ADD));JumpToApplication();}
}int main(void)
{/* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();USB_GPIO_DeInit();MX_USART1_UART_Init();if(HAL_GPIO_ReadPin(WKUP_KEY_GPIO_Port, WKUP_KEY_Pin) != GPIO_PIN_SET){JumpToApp(); printf("跳转失败,可能跳转区域为空白\r\n");printf("开始进入DFU模式\r\n");}MX_USB_DEVICE_Init();printf("sudaroot DFU\r\n");HAL_GPIO_WritePin(RUN_LED_GPIO_Port, RUN_LED_Pin, GPIO_PIN_RESET);   /* Infinite loop */while (1){}
}

解释一下,if (((*(__IO uint32_t *) USBD_DFU_APP_DEFAULT_ADD) & 0x2FFC0000) == 0x20000000)这代码。

第一:USBD_DFU_APP_DEFAULT_ADD这个地址存放的是栈顶地址。

第二:有效的SRAM空间,SRAM基地址是0x20000000, F429IGT6的SRAM大小是256KB = 0x40000 byte

           由于地址是从0x20000000开始的,故0x20000000 ~ 0x2003FFFF为有效空间。‭                                                                  

第三:栈顶地址 & 0x2FFC0000 == 0x20000000,的意思是判断栈顶是否合法有效,即是否在0x20000000 ~ 0x2003FFFF为有               效空间内。

            那么0x2FFC0000又是怎么算出来的?把0x3FFFF取反得到0xFFFC 0000‬,由于且不小于0x20000000,
           所以0x20000000 | 0xFFFC 0000 = 0x2 FFFC 0000;

现象:

1、正常上电,有APP就跳转,没有就进入DFU模式。

2、按住按键再上电,进入DFU模式。

进入DFU模式后,插上板子通过USB连接到电脑,打开设备管理器 和 上面安装的DfuSe_Demo

双击分区,得到各个分区的权限。

  全篇完。

本人是一个嵌入式未入门小白,博客仅仅代表我个人主观见解,记录成长笔记。
笔记是以最简单的方式,只展示最核心的原理。
若有与 大神大大 见解有歧义,我绝对坚信 大神大大 见解是对的,我的是错的。
若无积分等无法下载源码,可加入QQ群657407920下载交流经验。感谢~!

 

 

这篇关于STM32CbueMX之 USB下载更新固件Download Firmware Update(DFU)之一BootLoader程序编写的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/697395

相关文章

Python pip下载包及所有依赖到指定文件夹的步骤说明

《Pythonpip下载包及所有依赖到指定文件夹的步骤说明》为了方便开发和部署,我们常常需要将Python项目所依赖的第三方包导出到本地文件夹中,:本文主要介绍Pythonpip下载包及所有依... 目录步骤说明命令格式示例参数说明离线安装方法注意事项总结要使用pip下载包及其所有依赖到指定文件夹,请按照以

MyBatis Plus 中 update_time 字段自动填充失效的原因分析及解决方案(最新整理)

《MyBatisPlus中update_time字段自动填充失效的原因分析及解决方案(最新整理)》在使用MyBatisPlus时,通常我们会在数据库表中设置create_time和update... 目录前言一、问题现象二、原因分析三、总结:常见原因与解决方法对照表四、推荐写法前言在使用 MyBATis

python编写朋克风格的天气查询程序

《python编写朋克风格的天气查询程序》这篇文章主要为大家详细介绍了一个基于Python的桌面应用程序,使用了tkinter库来创建图形用户界面并通过requests库调用Open-MeteoAPI... 目录工具介绍工具使用说明python脚本内容如何运行脚本工具介绍这个天气查询工具是一个基于 Pyt

Ubuntu设置程序开机自启动的操作步骤

《Ubuntu设置程序开机自启动的操作步骤》在部署程序到边缘端时,我们总希望可以通电即启动我们写好的程序,本篇博客用以记录如何在ubuntu开机执行某条命令或者某个可执行程序,需要的朋友可以参考下... 目录1、概述2、图形界面设置3、设置为Systemd服务1、概述测试环境:Ubuntu22.04 带图

MyBatis编写嵌套子查询的动态SQL实践详解

《MyBatis编写嵌套子查询的动态SQL实践详解》在Java生态中,MyBatis作为一款优秀的ORM框架,广泛应用于数据库操作,本文将深入探讨如何在MyBatis中编写嵌套子查询的动态SQL,并结... 目录一、Myhttp://www.chinasem.cnBATis动态SQL的核心优势1. 灵活性与可

Python程序打包exe,单文件和多文件方式

《Python程序打包exe,单文件和多文件方式》:本文主要介绍Python程序打包exe,单文件和多文件方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录python 脚本打成exe文件安装Pyinstaller准备一个ico图标打包方式一(适用于文件较少的程

Mybatis嵌套子查询动态SQL编写实践

《Mybatis嵌套子查询动态SQL编写实践》:本文主要介绍Mybatis嵌套子查询动态SQL编写方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言一、实体类1、主类2、子类二、Mapper三、XML四、详解总结前言MyBATis的xml文件编写动态SQL

Python程序的文件头部声明小结

《Python程序的文件头部声明小结》在Python文件的顶部声明编码通常是必须的,尤其是在处理非ASCII字符时,下面就来介绍一下两种头部文件声明,具有一定的参考价值,感兴趣的可以了解一下... 目录一、# coding=utf-8二、#!/usr/bin/env python三、运行Python程序四、

无法启动此程序因为计算机丢失api-ms-win-core-path-l1-1-0.dll修复方案

《无法启动此程序因为计算机丢失api-ms-win-core-path-l1-1-0.dll修复方案》:本文主要介绍了无法启动此程序,详细内容请阅读本文,希望能对你有所帮助... 在计算机使用过程中,我们经常会遇到一些错误提示,其中之一就是"api-ms-win-core-path-l1-1-0.dll丢失

SpringBoot后端实现小程序微信登录功能实现

《SpringBoot后端实现小程序微信登录功能实现》微信小程序登录是开发者通过微信提供的身份验证机制,获取用户唯一标识(openid)和会话密钥(session_key)的过程,这篇文章给大家介绍S... 目录SpringBoot实现微信小程序登录简介SpringBoot后端实现微信登录SpringBoo