声明:
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
官网下载链接:
默认安装即可。
安装成功后得到两个软件。
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 __cplusplus
extern "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 1
if (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;
#else
if(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 1
bank = FLASH_BANK_1;
#else
if(Addr < ADDR_FLASH_SECTOR_12) bank = FLASH_BANK_1;
else bank = FLASH_BANK_2;
#endif
return 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下载交流经验。感谢~!