本文主要是介绍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>© 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>© 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, §orerror);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程序编写的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!