你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32F0 使用 DFU 升级后 Leave DFUMode 不能运行用户代码

[复制链接]
STMCU小助手 发布时间:2022-2-20 16:37
前言
很多 STM32 的 System Memory 中所带的 Bootloader 都支持 USB DFU 功能,可以使用 USB 更新代码,详见《AN2606:STM32™ 微控制器系统存储器自举模式》。
问题
某客户在其产品的设计中,需要使用了 STM32F072RBT6。客户在使用过程中,使用 System Memory 中的 USB DFU 功能对代码进行更新,并直接使用“Leave DFU mode”跑用户代码,进行功能观察。但是,发现 STM32F0 在点击“Leave DFU mode”按钮后,用户代码并没有正常工作,这是为什么呢?

调研
1.了解问题
客户使用了 STM32F072B-Discovery 板进行调试的。在使用\STM32F072BDiscovery_FW_V1.0.1\Projects\Peripheral_Examples\TIM_TimeBase例程进行测试,先使用 IAR 将此例程进行编译,生成TIM_TimeBase.hex 文件。使用 STM32 ST-Link Utility 软件进行烧写,烧写后可见 Discovery 板上 4 个 LED 灯在闪烁,确认
例程及 hex 文件的正确性。

使用 Dfu file manager 软件将 TIM_TimeBase.hex 文件生成 TIM_TimeBase.dfu 文件。将 STM32F072 的 Boot0 引脚拉高,对芯片进行复位,进入 System Memory 运行 Bootloader,使用 Mini USB 线连接 USB USER 口(CN2)和 PC,打开 DfuseDemo 软件,可发现 STM32F072 已经进入 DFU mode,如下:

9KEC0YKV@(NB{(@N~XW[TBV.png

点击右下的“Choose”按钮选择 TIM_TimeBase.dfu,勾选“Verify after download”后点击“Upgrade”进行代码烧写,烧写成功后,点击“Leave DFU mode”离开 DFU 模式,发现 Discovery 板确实没有任何变化,4 个 LED 灯并没有闪烁,也就是说,用户代码没有正常运行。
但是客户使用 STM32F4-Discovery 板进行测试的时候,使用\STM32F4-Discovery_FW_V1.1.0\Project\Peripheral_Examples\TIM_TimeBase 例程,点击“Leave DFU mode”离开 DFU 模式后却可以正常运行程序。

2.分析问题
先来看一下《AN3156:USB DFU protocol used in the STM32 bootloader》中对 Leave DFU mode 的描述:

(S4K[UDWE[8O1WMU63ZA7TS.png

此处描述了离开 DFU 模式时,STM32 所执行的一些操作:
1. 断开连接
2. 初始化 Bootloader 所使用过的外设寄存器,并复位到默认值
3. 初始化用户应用程序主堆栈指针
4. 跳转到“地址+4”的位置,运行代码。
   再看一下底下的注意:

V2N69{H$PI4T`D1]I]{1]6S.png

   此处说明,跳转到应用程序,只有在用户代码有正确的向量表设置,才能正常工作。
   现在开始检查\STM32F072B-Discovery_FW_V1.0.1\Projects\Peripheral_Examples\TIM_TimeBase 例程中,跟设置向量表相关的代码,并没有找到。也就是说这个例程,当使用 USB DFU 功能进行升级后,使用“Leave DFU mode”离开 DFU 模式进入用户代码,由于没有重新设置向量表,所以向量表还停留在 System Memory 中,开始运行程序没问题,但是一旦产生中断,需要进入向量表的时候,就会跳错向量表而出错。(注:如果使用的是 GPIO_IOToggle 则不会有问题,因为这个例程没有使用中断)
   再来看一下为什么 STM32F4-Discovery 板跑\STM32F4-Discovery_FW_V1.1.0\Project\Peripheral_Examples\TIM_TimeBase例程就没有问题呢?同样我们来搜索一下关于设置向量表的代码。在 system_stm32f4xx.c 的 SystemInit()函数中,可以找到以下代码:
  1.    /* Configure the Vector Table location add offset address ------------------*/
  2.    #ifdef VECT_TAB_SRAM
  3.    SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
  4.    #else
  5.    SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH
  6.    */
  7.    #endif
复制代码

   此处为设置向量表,如果没有定义 VECT_TAB_SRAM,则设置向量表到 Main Flash Memory 中。这个函数在程序的最开始被运行,所以向量表得到了正确的设置,也就是为什么这个例程不会有问题的原因。


   3.问题解决
   那既然搞清楚原因了,如何解决呢?
   Cortex-M0 没有向量表重映射的功能,所以在 STM32F0 中,使用了 SYSCFG_CFGR1 寄存器中的 MEM_MODE 位来实现重映射,查看参考手册,可以找到:

SE}ZYH0R82X_W7[(%T3CQ~7.png

   从这可以看出,在 System Memory 运行 Bootloader 的时候,MEM_MODE 为 01,所以当离开 USB DFU 模式时,需要将这
   个值修改为 x0。
   在 STM32F0 的标准外设库中,修改 MEM_MODE 对应的函数为 SYSCFG_MemoryRemapConfig(),其原型为:
  1.   /**

  2. * @brief Configures the memory mapping at address 0x00000000.
  3. * @param SYSCFG_MemoryRemap: selects the memory remapping.
  4. * This parameter can be one of the following values:
  5. * @arg SYSCFG_MemoryRemap_Flash: Main Flash memory mapped at 0x00000000
  6. * @arg SYSCFG_MemoryRemap_SystemMemory: System Flash memory mapped at
  7.   0x00000000
  8. * @arg SYSCFG_MemoryRemap_SRAM: Embedded SRAM mapped at 0x00000000
  9. * @retval None
  10.   */
  11.   void SYSCFG_MemoryRemapConfig(uint32_t SYSCFG_MemoryRemap)
  12.   {
  13.   uint32_t tmpctrl = 0;
  14.   /* Check the parameter */
  15.   assert_param(IS_SYSCFG_MEMORY_REMAP(SYSCFG_MemoryRemap));
  16.   /* Get CFGR1 register value */
  17.   tmpctrl = SYSCFG->CFGR1;
  18.   /* Clear MEM_MODE bits */
  19.   tmpctrl &= (uint32_t) (~SYSCFG_CFGR1_MEM_MODE);
  20.   /* Set the new MEM_MODE bits value */
  21.   tmpctrl |= (uint32_t) SYSCFG_MemoryRemap;
  22.   /* Set CFGR1 register with the new memory remap configuration */
  23.   SYSCFG->CFGR1 = tmpctrl;
  24.   }
复制代码

  在调用这个程序之前,还必须打开 SYSCFG 的外设时钟,所以我们需要在用户代码最开始的地方,也就是 SystemInit()中或者在 main()的最开始,加入以下代码:
  1.   /* Enable the SYSCFG peripheral clock*/
  2.   RCC_APB2PeriphResetCmd(RCC_APB2Periph_SYSCFG, ENABLE);
  3.   /* Remap SRAM at 0x00000000 */
  4.   SYSCFG_MemoryRemapConfig(SYSCFG_MemoryRemap_Flash);
复制代码

  这样,就可以保证在用户代码中使用的是 Main Flash Memory 的向量表了。
  重新编译这个代码,并生成.dfu 文件,再使用 Dfuse Demo 进行烧写,点击“Leave DFU mode”离开 DFU 模式后即可发现4 个 LED 闪烁,代表代码正常运行了。

  结论
  由于在例程中并没有对向量表进行设置以确保用户代码的向量表为 Main Flash Memory 中,而用户在用户代码中也没有对其进行设置,导致在使用 System Memory 中使用 USB DFU 后离开 DFU 模式进入 Main Flash Memory 中运行用户代码,但向量表仍在 System Memory 中,造成中断产生时跳错向量表而造成出错。


  处理
  需要在用户代码中加入设置正确的向量表,以确保在运行用户代码时使用的是 Main Flash Memory 中的向量表。


收藏 评论0 发布时间:2022-2-20 16:37

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版