Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >STM32高级开发——使用DFU方案

STM32高级开发——使用DFU方案

作者头像
李肖遥
发布于 2022-12-22 02:47:47
发布于 2022-12-22 02:47:47
1.5K00
代码可运行
举报
运行总次数:0
代码可运行

素材来源:https://blog.csdn.net/zhengyangliu123/article/details/78788815

整理:技术让梦想更伟大 | 李肖遥

什么是 DFU

DFU全称为Device Firmware update,是ST官方推出的一个通过USB接口进行IAP升级的方案,同串口ISP一样,他们都集成在了芯片内部的Bootloader区段,可以通过配置boot引脚来启动。(具体可参照ST文档:AN2606)。不过内置DFU的芯片大部分型号都比较新,如果你用的型号没有内置DFU程序,没关系我们也可以通过CubeMX来快速生成和移植一个DFU功能程序到你的Flash中来使用。

DFU方案完整的组件包括单片机DFU Demo代码、PC端升级程序、PC端Demo代码以及相关资料手册等。通过使用DFU方案,我们可以快速的集成升级功能到开发的产品中,同时还能够快速的开发与之配套的升级程序。

使用CubeMX生成初始工程

由于官方提供的DFU例程并不多,我们很难找到现成的可已使用DFU程序,但是通过CubeMX我们可以很快速的配置和生成DFU的Bootloader,下面我们正式开始。

  1. 新建CubeMX工程 首先选定好IC的型号,进入配置界面,由于只是Bootloader代码所以这里我们只需要配置USB功能和一个做Bootloader触发的引脚就可,其余的时钟等部分一切按照正常方式配置。
  2. 设置USB引脚功能 设定USB模式为Device(HS还是FS并不影响DFU的功能,按照应用选择就可)。
  1. 开启DFU组件 在MiddleWares中加入USB DFU组件
  1. 设置DFU参数 开启DFU组件后,CubeMX的程序设置窗口的MiddleWares中就会出现DFU程序设置按钮。

点开它将APP加载的地址改为0x0800_c000,这个加载地址根据你实际的应用设置,目前我们选择让flash的前三个sector为Bootloader的区域。

第二个全是字段的参数是用来在DFU连接升级软件式传输给软件用来获取Flash结构字符串数据,很好理解这个小协议的内容,点击设置后,下方的CubeMX的参数说明也写的很清晰,这里就不多说了。当然这些参数也在工程生成后在 usbd_conf.h 和 usbd_dfu_if.c 文件中修改。

  1. 最后的设置 最后我们添加一个外部的按键作为触发单片机启动时进入DFU的方式,按键按下后就启动DFU模式,否则直接加载后方APP程序,这里选用PA0引脚,给它设置个User Label 就叫 USER_BTN_GPIO_Port。

修改补全工程

实现 DFU 功能代码

打开 src 目录下的 usbd_dfu_if.c 文件补全其中的功能代码

Flash 解锁

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
uint16_t MEM_If_Init_HS(void)
{
    HAL_FLASH_Unlock();
    return (USBD_OK);
}

Flash 上锁

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
uint16_t MEM_If_DeInit_HS(void)
{
    HAL_FLASH_Lock();
    return (USBD_OK);
}

Flash 擦除

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
static uint32_t GetSector(uint32_t Address)
{
     uint32_t sector = 0;

     if ((Address < ADDR_FLASH_SECTOR_1) && (Address >= ADDR_FLASH_SECTOR_0))
     {
        sector = FLASH_SECTOR_0;
     }

     ......

      }
      else if ((Address < ADDR_FLASH_SECTOR_23) && (Address >= ADDR_FLASH_SECTOR_22))
      {
        sector = FLASH_SECTOR_22;
      }
      else
      {
        sector = FLASH_SECTOR_23;
      }
      return sector;
    }

    uint16_t MEM_If_Erase_HS(uint32_t Add)
    {
      uint32_t startsector = 0;
      uint32_t sectornb = 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.VoltageRange = FLASH_VOLTAGE_RANGE_3;
      eraseinitstruct.Sector = startsector;
      eraseinitstruct.NbSectors = 1;
      status = HAL_FLASHEx_Erase(&eraseinitstruct, &sectornb);

      if (status != HAL_OK)
      {
        return (USBD_FAIL);
      }
      return (USBD_OK);
}

Flash 写入

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
uint16_t MEM_If_Write_HS(uint8_t *src, uint8_t *dest, uint32_t Len)
{
    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);
}

Flash 读取

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
uint8_t *MEM_If_Read_HS(uint8_t *src, uint8_t *dest, uint32_t Len)
{
      /* Return a valid address to avoid HardFault */
      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);
}

获取 Flash 擦写时间参数

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
uint16_t MEM_If_GetStatus_HS(uint32_t Add, uint8_t Cmd, uint8_t *buffer)
{
      /* USER CODE BEGIN 11 */
      uint16_t time;

      time = TimingTable[GetSector(Add)];

      switch (Cmd)
      {
      case DFU_MEDIA_PROGRAM:
        buffer[1] = (uint8_t)time;
        buffer[2] = (uint8_t)(time << 8);
        buffer[3] = 0;
        break;

          case DFU_MEDIA_ERASE:
          default:
        buffer[1] = (uint8_t)time;
        buffer[2] = (uint8_t)(time << 8);
        buffer[3] = 0;
        break;
      }
      return (USBD_OK);
      /* USER CODE END 11 */
}

usbd_dfu_if.h 文件添加的宏定义

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/* Define flash address */
// BLANK 1

#define ADDR_FLASH_SECTOR_0 0x08000000


#define ADDR_FLASH_SECTOR_1 0x08004000


#define ADDR_FLASH_SECTOR_2 0x08008000


#define ADDR_FLASH_SECTOR_3 0x0800C000


#define ADDR_FLASH_SECTOR_4 0x08010000


#define ADDR_FLASH_SECTOR_5 0x08020000


#define ADDR_FLASH_SECTOR_6 0x08040000


#define ADDR_FLASH_SECTOR_7 0x08060000


#define ADDR_FLASH_SECTOR_8 0x08080000


#define ADDR_FLASH_SECTOR_9 0x080A0000


#define ADDR_FLASH_SECTOR_10 0x080C0000


#define ADDR_FLASH_SECTOR_11 0x080E0000

// BLANK 2

#define ADDR_FLASH_SECTOR_12 0x08100000


#define ADDR_FLASH_SECTOR_13 0x08104000


#define ADDR_FLASH_SECTOR_14 0x08108000


#define ADDR_FLASH_SECTOR_15 0x0810C000


#define ADDR_FLASH_SECTOR_16 0x08110000


#define ADDR_FLASH_SECTOR_17 0x08120000


#define ADDR_FLASH_SECTOR_18 0x08140000


#define ADDR_FLASH_SECTOR_19 0x08160000


#define ADDR_FLASH_SECTOR_20 0x08180000


#define ADDR_FLASH_SECTOR_21 0x081A0000


#define ADDR_FLASH_SECTOR_22 0x081C0000


#define ADDR_FLASH_SECTOR_23 0x081E0000


/* Flash oprate time from datasheet page 128 */

#define FLASH_SECTOR_16KB_WRITE_ERASE_TIME 500       //500 usb frame,means 500ms


#define FLASH_SECTOR_64KB_WRITE_ERASE_TIME 1100


#define FLASH_SECTOR_128KB_WRITE_ERASE_TIME 2000

修改Main文件

首先在main文件前添加几个用于加载APP程序的变量和函数定义

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
typedef void (*pFunction)(void);

pFunction JumpToApplication;
uint32_t JumpAddress;1234

然后再 main 函数中加入 外部按键的判断、APP程序加载以及USB DFU初始化功能

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int main(void)
{
      /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
      HAL_Init();

      /* Configure the system clock */
      SystemClock_Config();

      /* Initialize all configured peripherals */
      MX_GPIO_Init();

      if (HAL_GPIO_ReadPin(USER_BTN_GPIO_Port, USER_BTN_Pin) == GPIO_PIN_SET)
      {
        HAL_GPIO_WritePin(GPIOG, LD3_Pin, GPIO_PIN_SET); // For debug
        /* Test if user code is programmed starting from address 0x0800C000 */
        if (((*(__IO uint32_t *)USBD_DFU_APP_DEFAULT_ADD) & 0x2FF80000) == 0x20000000)
        {
          HAL_GPIO_WritePin(GPIOG, LD4_Pin, GPIO_PIN_SET); // For debug
          /* Jump to user application */
          JumpAddress = *(__IO uint32_t *)(USBD_DFU_APP_DEFAULT_ADD + 4);
          JumpToApplication = (pFunction)JumpAddress;

          /* Reset of all peripherals */
          HAL_DeInit();

          /* Set interrupt vector to app code */
          SCB->VTOR = USBD_DFU_APP_DEFAULT_ADD;

          /* Initialize user application's Stack Pointer */
          __set_MSP(*(__IO uint32_t *)USBD_DFU_APP_DEFAULT_ADD);
          JumpToApplication();
        }
      }

      MX_USB_DEVICE_Init();

      while (1)
      {
      }
}

编译程序下载进入单片机

使用DfuSe

从ST官网DfuSe的程序安装包,并安装。然后我们按下之前写的触发按键并复位单片机,让单片机初始 USB DFU 功能,这时如果你插着单片机的USB线,系统应该已经识别了。如果没有右键更新驱动程序,手动指定驱动搜索路径在DfuSe安装目录下的 \Bin\Driver 内。如果直接无法识别USB设备,建议在CubeMx配置完工程后就编译下载测试一下,看看是不是你在移植过程中哪里写错了。

然后我们需要生成一个地址设定在0x0800_c000后的测试程序,就先编写一个 Blink LED 的程序吧,生成bin、hex或S19文件。然后我们打开DfuSe软件的Dfu file manager来生成DFU软件用的.dfu格式的文件。选择第一项,第二个是用来将.dfu反向变换回来的。大概的操作已经标在图片上了,操作比较简单就不做详细介绍了,记得把Address的地址改到偏移后的地址上否则下载会出错,其他参数可以不用修改。

然后我们打开DfuSe程序,在Upgrade中选择生成好的blink.dfu文件,勾选校验功能,下载程序。成功后复位单片机,LED开始闪烁,移植成功。

更多

仔细区看看DfuSe的安装目录,里面有DFU的资料文档,还有DFU的工程源代码,可以用来改写自己需要的DFU升级程序。

参考资料

如何使用CubeMx生成一个DFU工程

ST官网DfuSe

http://www.stmicroelectronics.com.cn/content/st_com/zh/products/development-tools/software-development-tools/stm32-software-development-tools/stm32-programmers/stsw-stm32080.html

版权声明:本文来源网络,免费传达知识,版权归原作者所有。如涉及作品版权问题,请联系我进行删除。

‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧ END ‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-11-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 技术让梦想更伟大 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
如何使用CubeMx生成一个DFU工程
素材来源:https://blog.csdn.net/flydream0/article/details/54142208
李肖遥
2022/12/22
4390
如何使用CubeMx生成一个DFU工程
5分钟,使用STM32CubeMX把你的单片机变成优盘
哈喽大家好,这里是没什么人爱看的USB系列。USB系列停了几天,今天继续。这次说下如何通过STM32CubeMX软件,在5分钟的时间内,把你的单片机变成一个迷你优盘。
MCU起航
2020/06/29
2.1K0
U盘容量大小造假技术手段实现之8M变4G(以STM32 SPI_FLASH为例)
以前经常听别人说上某多或者某宝买便宜U盘的时候发现被坑,比如一个U盘大小是4GB,买回来到了手上插上PC端电脑显示也是4GB,但是真正用的时候发现并没有那么多,可能就只有那么几百MB的大小,甚至是几MB的大小,这些商家为了利益便会使用这样投机的方法,其目的是榨取用户的金钱;因此这样的商家真的很无良。当然不止是U盘可以这么来造假,其实市面上很多产品存储部分为了满足招标参数可能也会这么来搞, 那么这种手段是怎么来实现的呢?我们简单的用SPI_FLASH来模拟一下,揭露无良商家的丑陋的一面:
杨源鑫
2021/03/15
1.4K0
U盘容量大小造假技术手段实现之8M变4G(以STM32 SPI_FLASH为例)
【STM32H7教程】第81章 STM32H7的QSPI 总线应用之QSPI Flash的STM32CubeProg下载算法制作
完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第81章 STM32H7的QSPI 总线应用之QSPI F
Simon223
2020/11/24
9320
【STM32H7教程】第81章	STM32H7的QSPI 总线应用之QSPI Flash的STM32CubeProg下载算法制作
stm32cubemx软件库_STM32cube
前言: 本系列教程将HAL库与STM32CubeMX结合在一起讲解,使您可以更快速的学会各个模块的使用
全栈程序员站长
2022/09/28
8740
stm32cubemx软件库_STM32cube
STM32CubeMX学习–(5)SPI读写W25Q128
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/129269.html原文链接:https://javaforall.cn
全栈程序员站长
2022/07/29
1.3K0
STM32CubeMX学习–(5)SPI读写W25Q128
20-STM32+ESP8266+AIR202远程升级方案-扩展-移植远程更新方案包,实现STM32F072+DTU利用http或https远程更新STM32F072程序
GET /1.txt HTTP/1.1\r\nHost: mnif.cn\r\n\r\n
杨奉武
2020/10/29
1K0
20-STM32+ESP8266+AIR202远程升级方案-扩展-移植远程更新方案包,实现STM32F072+DTU利用http或https远程更新STM32F072程序
从零编写STM32H7的MDK SPI FLASH下载算法
当我们要下载编译好的镜像到Flash时,首先要做的一步就是选择合适的Flash下载算法,而这个算法本身就是一个FLM文件:
AIoT-KK
2023/03/01
1.4K0
从零编写STM32H7的MDK SPI FLASH下载算法
STM32Cube-18 | 使用QSPI读写SPI Flash(W25Q64)
本篇详细的记录了如何使用STM32CubeMX配置STM32L431RCT6的硬件QSPI外设与 SPI Flash 通信(W25Q64)。
Mculover666
2020/07/16
4.6K0
STM32Cube-18 | 使用QSPI读写SPI Flash(W25Q64)
stm32 spi协议_STM32库开发实战指南:基于STM32F4
✅作者简介:嵌入式入坑者,与大家一起加油,希望文章能够帮助各位!!!! 📃个人主页:@rivencode的个人主页 🔥系列专栏:玩转STM32 💬推荐一款模拟面试、刷题神器,从基础到大厂面试题👉点击跳转刷题网站进行注册学习 目录 一.SPI协议简介 二.SPI物理层 三.SPI协议层 1.通讯的起始和停止信号 2.数据有效性 3.时钟信号的相位和极性(重点) 四.SPI 特性及架构(重点) 1.通信引脚 2.时钟控制逻辑 3.数据控制逻辑(非常重要) 4.全双工发送和接收过程模式
全栈程序员站长
2022/11/03
8920
stm32 spi协议_STM32库开发实战指南:基于STM32F4
【STM32H7教程】第70章 STM32H7的内部Flash基础知识和HAL库API
完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第70章       STM32H7的内部Flash基础知识和HAL库
Simon223
2020/03/11
1.9K0
STM32通信模拟SPI
SPI(Serial Peripheral Interface,串行外设接口)是由摩托罗拉(Motorola)在1980前后提出的一种全双工同步串行通信接口,它用于MCU与各种外围设备以串行方式进行通信以交换信息,通信速度最高可达25MHz以上。
韦东山
2022/05/09
1.5K0
STM32通信模拟SPI
STM32通用FLASH管理软件包——SFUD/FAL
本次介绍的两个软件包SFUD/FAL都与FLASH有关,并且都可以独立使用或者结合在一起使用,两个软件包都对操作系统无依赖,可以使用裸机移植,也很方便移植到各种系统。
AIoT-KK
2020/07/13
2.3K0
STM32通用FLASH管理软件包——SFUD/FAL
20-STM32+ESP8266+AIR202/302远程升级方案-扩展-移植远程升级包实现STM32F072+DTU远程升级单片机程序(基于STM32CubeMX)
<p><iframe name="ifd" src="https://mnifdv.cn/resource/cnblogs/ESA2GJK1DH1K_B/" frameborder="0" scrolling="auto" width="100%" height="1500"></iframe></p>
杨奉武
2020/11/03
7180
用小安派 DSL做一个天气站
小安派-DSL(AiPi-DSL) 是安信可开源团队专门为Ai-M61-32S设计的一款屏幕驱动开发板,支持2.8/3.5寸等30Pin SPI显示屏、2.4寸及1.28寸等18Pin SPI显示屏。
安信可科技
2025/03/06
840
【STM32H7教程】第79章 STM32H7的QSPI总线应用之驱动W25QXX(支持查询和MDMA)
完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第79章 STM32H7的QSPI总线应用之驱动W25QX
Simon223
2020/11/24
2.7K0
【STM32H7教程】第79章       STM32H7的QSPI总线应用之驱动W25QXX(支持查询和MDMA)
【STM32H7教程】第71章 STM32H7的内部Flash应用之模拟EEPROM
完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第71章       STM32H7的内部Flash应用之模拟EEPR
Simon223
2020/03/11
2.2K0
【STM32H7教程】第80章 STM32H7的QSPI 总线应用之QSPI Flash的MDK下载算法制作
完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第80章 STM32H7的QSPI 总线应用之QSPI F
Simon223
2020/11/24
1.4K0
【STM32H7教程】第80章     STM32H7的QSPI 总线应用之QSPI Flash的MDK下载算法制作
TKM32F499高性能MCU评估板试用之万事开头难,先点个灯来压压惊!
TKM32F499深圳市好钜润科技有限公司发行的一款高性能单片机,以上图片是基于TKM32F499的一款评估板,可以看到评估板上的资源那是相当的丰富了,而且还是白菜价,到手价仅需88元,不得不说实在是香,香在哪呢?咱们看看特点就知道了。
杨源鑫
2020/05/21
5.5K2
【STM32F407开发板用户手册】第36章 STM32F407的SPI 总线应用之SPI Flash的MDK下载算法制作
最新教程下载:http://www.armbbs.cn/forum.php?mod=viewthread&tid=93255 第36章 STM32F407的SPI 总线应用之SPI Fla
Simon223
2020/11/26
7250
【STM32F407开发板用户手册】第36章       STM32F407的SPI 总线应用之SPI Flash的MDK下载算法制作
推荐阅读
相关推荐
如何使用CubeMx生成一个DFU工程
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验