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 __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>&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 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下载交流经验。感谢~!

 

 

  • 3
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 现代嵌入式系统大量使用SD卡存储数据,但在大量数据存储在SD卡上时,需要保证SD卡的文件系统稳定压缩。通常,我们使用Bootloader程序实现SD卡Firmware升级功能,该程序支持从SD卡获得启动信息,进而读取Firmware文件更新系统。在本文中,我们将详细介绍STM32F407 SD卡升级Bootloader程序下载。 1. 准备材料:  STM32F407核心板;  USB转串口模块;  SD卡 FAT32文件系统; 2. 确定SD卡Firmware文件格式: Firmware文件应该是整个程序代码和堆栈的BIN文件格式,用于升级整个系统软件。 3. 配置系统引导文件: 使用STMCubeMx或其他软件将Bootloader程序配置为系统引导文件,启动时首先加载它。 4. Bootloader程序下载准备工作: 在F407的SDIO1端口运行Bootloader程序,将Flash扇区1准备成一个Firmware更新的接收数据块。 5. SD卡下载: 从SD卡中打开Firmware文件夹查找Firmware更新程序(含APP压缩包在内),启动STM32F407 Bootloader程序从SD卡中读取整个文件,将文件传输至Flash扇区1。升级过程通常需要等待一段时间。 6. 启动更新程序: 在更新完成后重新启动针对新Firmware更新程序,观察系统是否正常运行,APP程序更新后的状态是否与预期一致。 7. 完整性检查: 确定存储在SD卡上的Firmware文件的大小以进行检查,确认每次更新时文件的大小以及完整性。此外,应检查当前正在运行的Firmware版本,以确认其是Firmware更新后的最新版本。 以上是关于STM32F407 SD卡升级Bootloader程序下载的详细步骤,需要工程师们按照步骤进行升级,以确保整个系统在Firmware更新后的可靠性,有效提升嵌入式系统的稳定性和确保可靠性,同时避免因硬件损坏或数据丢失而造成的混乱和损失。 ### 回答2: STM32F407是一款易于使用的高性能微控制器,可以进行SD卡升级和Bootloader程序下载。在进行升级和下载之前,需要先下载相应的编译器和ST-Link工具。接下来,按照以下步骤进行操作: 1. 在SD卡中添加升级文件,如固件文件。 2. 在ST-Link工具中选择"Firmware Upgrade"选项,点击"Connect"按钮连接STM32F407芯片。 3. 确认芯片型号和FLASH大小并进行擦除。 4. 选择"Program and Verify"选项,并选择升级文件进行下载。 5. 点击"Start"按钮开始下载下载完成后,可以进行Bootloader程序下载。首先需要建立一个新项目,将Bootloader程序添加进去,并进行编译。接下来,将STM32F407芯片连接到ST-Link工具中,选择"Connect"选项,然后点击"Program and Verify"选项进行下载。完成后,可以重启设备并测试Bootloader程序是否正常运行。 总的来说,STM32F407的SD卡升级和Bootloader程序下载过程相对较为简单,只需要按照以上步骤进行操作即可。其中需要注意的是,在下载过程中不能中断电力供应,否则可能会导致芯片损坏。 ### 回答3: 在使用STM32F407微控制器的开发板进行SD卡升级时,需要先将Bootloader程序下载到板子中。Bootloader程序允许在初次启动时进行SD卡升级,这可以利用SD卡来更新控制器的固件,使得系统更稳定、更可靠。 下载Bootloader程序的方法有很多种,可以通过ST-Link V2下载器,也可以通过串口下载程序。使用ST-Link V2下载器可以通过JTAG/SWD接口将Bootloader程序下载到系统中,需要注意的是,在下载时需要选择正确的程序烧录地址。 如果使用串口下载程序,则需要在Bootloader程序中添加一个串口下载器的协议,并将该程序编译到系统中。此时,我们需要将升级文件打包成一个.bin等二进制格式的文件,并通过串口将其发送给Bootloader程序进行升级,具体操作步骤可以参考相应的程序开发文档。 总结来说,SD卡升级Bootloader程序下载主要有两种方式,一是通过ST-Link V2下载器进行下载,二是通过串口将程序编译到系统中并进行升级。在具体实现过程中,需要注意选择正确的烧录地址,并严格按照开发文档操作,确保升级过程顺利完成。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值