当前位置:首页 > 单片机 > 单片机
[导读]前言大家都知道,任何STM32 都包含有一块系统存储器(System Memory),里边存储着内部的启动代码Bootloader。不同的STM32 型号所支持的用于升级代码的通讯口不尽相同,需要参考应用笔记AN2606。但是,有一个问题避免

前言
大家都知道,任何STM32 都包含有一块系统存储器(System Memory),里边存储着内部的启动代码Bootloader。不同的
STM32 型号所支持的用于升级代码的通讯口不尽相同,需要参考应用笔记AN2606。但是,有一个问题避免不了,那就是如
何进入System Memory 去执行Bootloader?通常的办法都是将BOOT1 和BOOT0 进行配置:BOOT0 拉高,BOOT1 拉低
(有些型号的BOOT1 由选项字节nBOOT1 进行控制)。可是在一些产品中,由于外观的要求,往往不方便在外边开口去放
置按键或跳线来改变BOOT 脚的电平。而且,用户并不想自己写IAP 代码,觉得麻烦。特别是一些产品,需要使用USB
DFU 来进行代码升级的,而在产品功能中USB 又没用到,用户就会觉得自己为了一个通过USB 进行代码升级的功能,去写
IAP 的话,需要去熟悉USB 的代码,觉得麻烦,而且这些USB 的代码还占用了用户的程序空间。对于这些用户来讲,他们很
希望能在不管BOOT 脚的情况下能够去调用STM32 中System Memory 的Bootloader,完成代码升级功能。

问题
某客户在其产品的设计中,使用了STM32F411。由于产品外观的要求,无法在外部对BOOT 脚进行控制,而且外观上只有
USB 接口是留在外边的,需要使用USB DFU 进行升级。而且USB 接口只用于代码升级,没有其他功能,所以客户不想去碰
USB 代码,希望能够直接使用System Memory 中的Bootloader 进行代码升级。

调研
1.判断其可行性
首先,打开应用笔记AN2606《STM32 microcontroller system memory boot mode》,翻到3.1 Bootloader activation 一节的
最后,可以看到如下信息:


这里的意思就是说,用户可以通过从用户代码跳转到系统存储器去执行Bootloader。但是,在跳转到Bootloader 之前,有几
个事情必须要做好:
1) 关闭所有外设的时钟
2) 关闭使用的PLL
3) 禁用所有中断
4) 清除所有挂起的中断标志位
最后,可以通过离开Bootloader 激活条件且产生一个硬件复位或者直接使用Go 命令去执行用户代码。
那么,如何从用户代码跳转到System Memory 中去呢?这个其实并不难,如果写过IAP,或者看过关于IAP 的应用笔记中的
参考代码的话,比如应用笔记AN3965“STM32F40x/STM32F41x in-application programming using the USART”及其参考
代码STSW-STM32067,都应该知道,IAP 的启动代码通过重新设置主堆栈指针并跳转到用户代码来执行用户代码的。同样
的道理,只要知道System Memory 的地址,一样可以从用户代码通过重新设置主堆栈指针并跳转到System Memory 来执行
Bootloader。而System Memory 地址可以从参考手册来获得。比如,查看STM32F411 的参考手册RM0383,可以找到如下
的表格:

可以知道STM32F411 的System memory 地址从0x1FFF0000 开始。

那很多人又会问了,我的代码很复杂,用了很多外设,开了很多中断,可是要跳转到System Memory 中的Bootloader,需要
关所有外设的时钟,需要关PLL,需要关闭所有中断,需要禁用所有的中断,清除所有挂起的中断。这可是一项非常庞大的
的任务啊!所以,在这里,我们需要一个更简单的事情来完成这项庞大的任务。其实真的就有这么简单的一个方法——复位!
通过软件复位来实现这一目的。但是,复位后,又怎么知道还记得我们要去做代码升级呢?这又要用到STM32 另一个特性了,
那就是后备数据寄存器Backup Data Registers 在软件复位后会保留其值,这样给了我们在复位前后做一个标志的机会。
这样,考证下来,客户的需求是具备可行性的。接下来需要做的是理清思路。

2.软件流程
这里使用32F411EDISCOVERY 板来设计一个参考例程:设计一个用户程序,让LED3 进行闪烁;当用户按键被按下,产生
EXTI 中断,在中断中选择后备数据寄存器RTC_BKP0R,写入值0x32F2,然后产生软件复位;软件复位后,在运行代码的
最前面对RTC_BKP0R 进行判断,如果其值不是0x32F2 则直接去运行用户代码,如果其值为0x32F2 则是需要跳转到
Bootloader 去进行代码升级,并在跳转前将RTC_BKP0R 清零。这样,在进入Bootloader 后,客户进行USB DFU 升级后,
将来不会因为非需要升级代码的复位而误入Bootloader。
来看软件流程图,先来看主程序的流程图:


再来看EXTI 中断的流程图:


3.主要代码
使用STM32F4Cube 库来开发这个例程。先来看位于main.c 中的main 函数:

Main 函数很简单,配置系统时钟,对使用的LED 进行初始化,然后配置了用户按键的EXTI 中断,然后就进入主循环了。前
面说到,要实现用户的功能程序为LED3 闪烁,在主循环我们没看到,是因为在Cube 库中,会使用SysTick,所以把LED3
的闪烁放到SysTick 的中断代码中了,查看stm32f4xx_it.c,如下:

从main 函数最开始的那段注释中知道,跳入main 函数前,在startup_stm32f411xe.s 中早已经先调用执行了位于
system_stm32f4xx.c 中的SystemInit 函数。SystemInit 函数主要执行初始化FPU、复位RCC 时钟寄存器、配置向量表等功
能。由于我们希望在最原始的状态下进入System Memory,所以我们将跳转到System Memory 放在这个函数的最前头,如
下:


可以看到,在函数的最前面对RTC_BKP_DR0 进行了判断,如果其值为0x32F2 的话,则先启动备份域的访问时序,如
RM0383 中5.1.2 Battery backup domain 所描述的:


然后将RTC_BKP_DR0 清零,再关闭执行这次操作所打开的时钟。
主堆栈指针MSP 的初始值位于向量表偏移量为0x00 的位置,复位Reset 的值则位于向量表偏移量为0x04 的位置。对于
STM32F411 来说,当执行System Memeory 中的Bootloader 时,MSP 的初始值位于0x1FFF0000,而Reset 则位于
0x1FFF0004。所以在程序中,使用__set_MSP(*(__IO uint32_t*) 0x1FFF0000);来重新设置主堆栈指针,而后再跳转到
0x1FFF0004 去执行Bootloader。

再来看位于stm32f4xx_it.c 中的EXTI 中断程序:


及其位于main.c中的Callback函数:


当判断到用户按键按下,需要进行用户代码升级时,先启动备份域的访问时序,将RTC_BKP_DR0 的值写为0x32F2。再读
回来判断是否写入成功,以方便调试。如果写入成功后,则就调用HAL_NVIC_SystemReset()进行软件复位。重新复位后,
就可以进入System Memory 了。

4.实验
使用32F411EDISCOVERY 来做实验。
1) 先将程序编译,下载到32F411EDISCOVERY 板,可以看到LED3 在进行闪烁


2) 按下User 按键,LED3 熄灭,已经进入System Memory 中的Bootloader
3) 打开DfuSeDemo 软件,此时Available DFU Devices 中没有任何显示


4) 将一根USB Micro 连接线插入32F411EDISCOVERY 板的CN5,可见LED7 亮起,USB 已连接


5) 驱动完成后,可以再查看一下DfuSeDemo,Available DFU Devices 已经显示为“STM Device in DFU Mode”,代
表已经成功驱动并正常工作了


6) 之后就是正常的升级代码的流程了,点“Choose”按钮选择要更新的代码,这里准备好了一个
32F411EDISCOVERY 板的Demo 程序经过Dfu file manager 软件生成的32f411ediscovery.dfu 的文件,导入


7) 点“Upgrade”按钮进行升级,弹出的对话框选Yes 就可以了,之后就升级成功了


8) 再点一下“Leave DFU mode”,进度条显示“Successfully left DFU mode!”,就可以进入更新后的用户代码了,
可以看到4 个LED 灯正常欢快的滚动和闪烁着……


注意
此例程仅为验证其可行性,在实际应用中,有不尽完善的地方请用户自行完善。另外,有几个需要注意的地方:
1) 此Demo 代码基于STM32Cube_FW_F4_V1.11.0 撰写,解压缩后,可将其放入
STM32Cube_FW_F4_V1.11.0ProjectsSTM32F411E-DiscoveryTemplates 替换掉原来的源代码文件,即可编译
运行。
2) 此程序使用按键按下作为条件来触发软件代码升级,用户可以根据自己的情况修改触发条件,如多个按键同时按下,
等等。
3) 当用户应用中使用了RTC 的话,RTC 时钟源一旦被选择后是无法修改的,除非备份域被复位。在RM0383 关于
RCC_BDCR 的描述中有提及:

4) 关于如何使用Dfu file manager 生成.dfu 文件,请参考UM0412“Getting started with DfuSe USB device firmware
upgrade”或者实战经验“利用USB DFU 实现IAP 功能”。
5) 关于Bootloader 中所使用的USB DFU 协议,请参考AN3156“USB DFU protocol used in the STM32 bootloader”。

文档和代码下载地址:
http://www.stmcu.org/document/detail/index/id-217309
http://www.stmcu.org/document/download/index/id-212785

实战经验汇总:
http://www.stmcu.org/module/forum/thread-606863-1-1.html

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

在嵌入式开发中,STM32的时钟系统因其灵活性和复杂性成为开发者关注的焦点。然而,看似简单的时钟配置背后,隐藏着诸多易被忽视的陷阱,轻则导致系统不稳定,重则引发硬件损坏。本文从时钟源选择、PLL配置、总线时钟分配等关键环...

关键字: STM32 时钟系统

在嵌入式系统开发中,STM32系列微控制器的内部温度传感器因其低成本、高集成度特性,广泛应用于设备自检、环境监测等场景。然而,受芯片工艺差异和电源噪声影响,其原始数据存在±1.5℃的固有误差。本文从硬件配置、校准算法、软...

关键字: STM32 温度传感器

在能源效率与智能化需求双重驱动下,AC-DC转换器的数字控制技术正经历从传统模拟方案向全数字架构的深刻变革。基于STM32微控制器的PFM(脉冲频率调制)+PWM(脉冲宽度调制)混合调制策略,结合动态电压调整(Dynam...

关键字: AC-DC STM32

当前智能家居产品需求不断增长 ,在这一背景下 ,对现有浇花装置缺陷进行了改进 ,设计出基于STM32单片机的全 自动家用浇花机器人。该设计主要由机械结构和控制系统构成 ,机械结构通过麦克纳姆轮底盘与喷洒装置的结合实现机器...

关键字: STM32 麦克纳姆轮 安全可靠 通过性强

用c++编程似乎是让你的Arduino项目起步的障碍吗?您想要一种更直观的微控制器编程方式吗?那你需要了解一下Visuino!这个图形化编程平台将复杂电子项目的创建变成了拖动和连接块的简单任务。在本文中,我们将带您完成使...

关键字: Visuino Arduino ESP32 STM32

基于STM32与LoRa技术的无线传感网络凭借其低功耗、广覆盖、抗干扰等特性,成为环境监测、工业自动化等场景的核心解决方案。然而,如何在复杂电磁环境中实现高效休眠调度与动态信道优化,成为提升网络能效与可靠性的关键挑战。本...

关键字: STM32 LoRa

在实时控制系统、高速通信协议处理及高精度数据采集等对时间敏感的应用场景中,中断响应延迟的优化直接决定了系统的可靠性与性能上限。STM32系列微控制器凭借其灵活的嵌套向量中断控制器(NVIC)、多通道直接内存访问(DMA)...

关键字: STM32 DMA

数字电源技术向高功率密度、高效率与高动态响应方向加速演进,STM32微控制器凭借其基于DSP库的算法加速能力与对LLC谐振变换器的精准控制架构,成为优化电源动态性能的核心平台。相较于传统模拟控制或通用型数字控制器,STM...

关键字: STM32 数字电源

STM32微控制器凭借其针对电机控制场景的深度优化,成为高精度、高可靠性驱动系统的核心选择。相较于通用型MCU,STM32在电机控制领域的核心优势集中体现在FOC(磁场定向控制)算法的硬件加速引擎与PWM死区时间的动态补...

关键字: STM32 电机控制

无线充电技术加速渗透消费电子与汽车电子领域,基于Qi协议的无线充电发射端开发成为智能设备能量补给的核心课题。传统模拟控制方案存在响应滞后、参数调整困难等问题,而基于STM32的数字PID控制结合FOD(Foreign O...

关键字: STM32 无线充电
关闭