[应用相关] 通过 DfuSe 工具控制程序跳进 DFU 模式

[复制链接]
1818|16
 楼主| 问天少年 发表于 2021-11-10 11:51 | 显示全部楼层 |阅读模式
1 前言
我们之前经常有讲到过如何通过 USB DFU 方式来对固件进行升级, 在示例中我们通常是通过一个按键来触发
APP 跳转到 BOOT 从而进入到 DFU 升级模式。 但是也有一种情况, 客户的环境是没有任何按键或者其它触发条件,只有一
USB 口连接运行 windows 操作系统的上位机。 这不,前不久就碰到这么个客户, 下位机 MCU 端仅仅只有一个 USB 口连
接上位机, 且
MCU 端与上位机之间的 USB 是常连的, 并不能通过 USB 的拔插操作来触发 APP 的跳转, 在此情况下,我们
又该如何来实现客户的需求?
  

 楼主| 问天少年 发表于 2021-11-10 11:51 | 显示全部楼层
2 分析
33451618b41c33c9d2.png
如上图所示, 在 MCU 内部 FLASH 中, BOOT 与 APP 同时存在, BOOT 为 DFU 模式, 负责对固件进行升级, 而 APP(Runtime 模式)为客户的应用程序。 当 APP 运行时,通过某个事件触发(DFU_DETACH)程序从 APP 跳转到 BOOT 中从而进入到
DFU 模式中。
 楼主| 问天少年 发表于 2021-11-10 11:52 | 显示全部楼层
89414618b41e883007.png
这个 DFU_DETACH 的操作在这里我们可以通过 PC 端软件 DfuSe Demo 来触发。
 楼主| 问天少年 发表于 2021-11-10 11:53 | 显示全部楼层
68533618b422810165.png
在进入到 DFU 模式时, DfuSe Demo 软件的运行界面如上所示, 上图界面中有一个“Leave DFU mode”的按键,通过
它可以使运行在 MCU 的程序从 DFU 模式切换到 APP 中。 同时我们也发现,在按键“Leave DFU mode”的左边有一个灰色按
键“Enter DFU mode/HID detach”, 从字面就可以知道,它应该是进入到 DFU 模式的按键,在 APP 模式下此按键应该是激活
的,但是,在进入到 APP 模式后,此界面就检测不到 DFU 设备了,此软件将不再可用。那么我们又将如何来激活这个“Enter
DFU mode/HID detach”按键呢?
 楼主| 问天少年 发表于 2021-11-10 11:54 | 显示全部楼层
从帮助文档可知, 在 APP 模式时, 当 DfuSe Demo 这个软件识别到一个特定的 HID 设备时, “Enter DFU mod/HID
detach”按键将激活, 通过进一步了解, 我们知道此时 DfuSe Demo 这个软件是需要使能此项功能才可以, 所幸地是, 我们已
经有了此软件, 在与此文对应的附件中,可以找到一个名为 DfuSeDemo_A.exe 的可执行程序,将它拷贝到 DfuSeDemo 的
安装目录下, 如下图所示:
43205618b425a425b8.png
 楼主| 问天少年 发表于 2021-11-10 11:55 | 显示全部楼层
当运行在 APP 模式下时如下所示:
80551618b428b181f3.png
如上图所示, 在 APP 模式下时, 当程序检测到有效的 HID 设备时, DfuSe Demo 的”Available DFU Device”下拉框中会显示
这个 HID 设备, 并且“Enter DFU mode/HID detach”按键激活。 当按下此键时, MCU 会重启并进入到 DFU 模式。当然此 APP
是需要实现一个符合某种要求的 HID 设备才行。 下面我们通过制作这样一个 APP 来讲解。
 楼主| 问天少年 发表于 2021-11-10 11:57 | 显示全部楼层
3 制作 APP
我们基于之前 DFU 培训时使用的 STM32F072-Discovery 板来实现此 APP。
打开 STM32CubeMx 软件新建一个基于 STM32F072RB 的工程, 使能 USB 和 RTC 外设, RTC 我们主要用它的备份域寄存
器, 用来保存跳进入到 DFU 模式的标志;
Pinout 如下所示:
66283618b42c6984d4.png
使用 HSI48 作为系统时钟源, 同时给 USB 提供 48M 时候, 这样可以省一个外部晶振, RTC 就使用 LSI 时钟源,我们不要求
它的时间精确度,只求备份域寄存器可用。
88092618b42d8725f3.png
然后我们将 USB 类选择 “Custom Human Interface Device(HID)”, USB 中断等级设置为 1,堆为
0x500,栈大小设置为 0x2000, 然后生成工程。
 楼主| 问天少年 发表于 2021-11-10 11:58 | 显示全部楼层
打开 usbd_custom_hid_if.c 文件,找到 CUSTOM_HID_ReportDesc_FS, 修改报告描述符为:
  1. #define USBD_CUSTOM_HID_REPORT_DESC_SIZE 23
  2. /** Usb HID report descriptor. */
  3. __ALIGN_BEGIN static uint8_t CUSTOM_HID_ReportDesc_FS[USBD_CUSTOM_HID_REPORT_DESC_SIZE]
  4. __ALIGN_END =
  5. {
  6. /* USER CODE BEGIN 0 */
  7. 0x06, 0x00, 0xFF, /* USAGE_PAGE (Vendor Page: 0xFF00) */
  8. 0x09, 0x01, /* USAGE (Demo Kit) */
  9. 0xa1, 0x00, /* COLLECTION (Physical) */
  10. 0x85, 0x80, /* REPORT_ID (128) */
  11. 0x09, 0x55, /*USAGE (LED 1) */
  12. 0x15, 0x00, /* LOGICAL_MINIMUM (0) */
  13. 0x26, 0xFF, 0x00, /* LOGICAL_MAXIMUM (255) */
  14. 0x75, 0x08, /* REPORT_SIZE (8 bits) */
  15. 0x95, 0x01, /* REPORT_COUNT (1) */
  16. 0xB1, 0x82, /* FEATURE (Data,Var,Abs,Vol */
  17. /* USER CODE END 0 */
  18. 0xC0 /* END_COLLECTION */
  19. };
然后找到 CUSTOM_HID_OutEvent_FS 函数,修改为:
  1. static int8_t CUSTOM_HID_OutEvent_FS(uint8_t event_idx, uint8_t state)
  2. {
  3. /* USER CODE BEGIN 6 */
  4. extern RTC_HandleTypeDef hrtc;
  5. if(event_idx ==0x80 && state ==0x55)
  6. {
  7. __HAL_RCC_PWR_CLK_ENABLE();
  8. HAL_PWR_EnableBkUpAccess();
  9. HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR0,0x32F2);
  10. HAL_PWR_DisableBkUpAccess();
  11. HAL_NVIC_SystemReset();
  12. while (1);
  13. }
  14. return (USBD_OK);
  15. /* USER CODE END 6 */
  16. }




 楼主| 问天少年 发表于 2021-11-10 11:59 | 显示全部楼层
如上代码所示,只有当 PC 端软件 DfuSe Demo 检测到具有这个报告描述符的 HID 设备后才会认可其为满足要求的 HID 设备,
并将其显示在设备列表中, 按键“Enter DFU mode/HID detach”激活。 当用户按下此按键后, DfuSe Demo 会向 HID 设备发送
一条 SetFeature 指令。
当 MCU 收到 SetFeature 指令后,往备份域寄存器写入 0x32F2 作为进入 DFU 模式的标志, 然后重启切换到 BOOT, 接下来
在 BOOT 内如果程序检测到备份域寄存器的标志时则进入到 DFU 模式。 整个过程如图 2 所示。
当然, APP 还需要修改 FLASH 中的偏移位置,通过工具烧录到 0x0800 7000 的位置,这个在之前 DFU 培训时已经讲述过如
何操作了,这里就不具体再重复了,有兴趣的同学可以查看此文档附件内的 APP 源码。  

 楼主| 问天少年 发表于 2021-11-10 12:00 | 显示全部楼层
接下来我们再来看看 BOOT 程序中检测跳转标志的过程:
  1. /* USER CODE BEGIN 2 */
  2. if (((*(__IO uint32_t*)USBD_DFU_APP_DEFAULT_ADD) & 0x2FFE0000 ) != 0x20000000)
  3. {
  4. jump2App =JUMP_FLAG_DFU;
  5. }
  6. if(jump2App !=JUMP_FLAG_DFU)
  7. {
  8. __HAL_RCC_PWR_CLK_ENABLE();
  9. HAL_PWR_EnableBkUpAccess();
  10. if(0x32F2 ==HAL_RTCEx_BKUPRead(&hrtc,RTC_BKP_DR0))//检测备份域寄存器中的标志
  11. {
  12. HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR0,0);
  13. jump2App = JUMP_FLAG_DFU;
  14. }
  15. HAL_PWR_DisableBkUpAccess();
  16. }
  17. if(jump2App == JUMP_FLAG_INIT)
  18. {
  19. if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) !=GPIO_PIN_SET)
  20. {
  21. jump2App = JUMP_FLAG_APP;
  22. }
  23. else
  24. {
  25. jump2App =JUMP_FLAG_DFU ;
  26. }
  27. }
  28. if(jump2App ==JUMP_FLAG_APP)
  29. {
  30. /* Jump to user application */
  31. JumpAddress = *(__IO uint32_t*) (USBD_DFU_APP_DEFAULT_ADD + 4);
  32. JumpToApplication = (pFunction) JumpAddress;
  33. /* Initialize user application's Stack Pointer */
  34. __set_MSP(*(__IO uint32_t*) USBD_DFU_APP_DEFAULT_ADD);
  35. JumpToApplication();
  36. }
  37. //进入到 DFU 模式
  38. MX_USB_DEVICE_Init();
  39. /* USER CODE END 2 */
如上代码所示,只有当 jump2App ==JUMP_FLAG_APP 时程序才会跳转到 APP 中运行,否则进入到 DFU 模式



 楼主| 问天少年 发表于 2021-11-10 12:01 | 显示全部楼层
4 总结
使用此方法毕竟在 APP 中实现了一套 HID, 如果不是必要的话,建议还是使用按键的方式来触发从 APP 跳转到 DFU 模式,
除非遇到像本文中客户的情况,或者 APP 本身就需要实现某个 USB 类的功能,此时可以做成 USB 复合设备,其中一个 HID
设备就是本文中的 HID 设备,这样 PC 端的软件 DfuSe Demo 也可以识别。
木木guainv 发表于 2021-12-6 15:25 | 显示全部楼层
这个工具可以从哪里下载啊
tpgf 发表于 2021-12-6 15:25 | 显示全部楼层
app怎么写呢
磨砂 发表于 2021-12-6 15:26 | 显示全部楼层
可以避免跳进去哈
晓伍 发表于 2021-12-6 15:28 | 显示全部楼层
在哪里可以下载pc端软件啊
八层楼 发表于 2021-12-6 15:30 | 显示全部楼层
如何做复合设备呢
观海 发表于 2021-12-6 15:32 | 显示全部楼层
如何识别特定设备呢
您需要登录后才可以回帖 登录 | 注册

本版积分规则

79

主题

564

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部