热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

STM32单片机Bootloader入门指南:从零开始学习必备知识

STM32单片机Bootloader入门指南:从零开始掌握核心知识本文详细介绍了STM32单片机Bootloader的基本概念及其与应用程序(APP)的关系。Bootloader是一种特殊的程序,负责在系统启动时加载并运行主应用程序。与普通应用程序类似,Bootloader同样运行在单片机上,但其主要功能是确保系统的可靠启动和固件更新。通过本文,读者将了解Bootloader的工作原理、开发流程以及如何实现基本的固件升级功能。

STM32单片机BootLoader扫盲


BootLoader和APP之间的关系

APP就是平时写的单片机上的应用程序,而BootLoader本质上和APP一样,也是平时写的应用程序。BootLoader只不过是拥有从外部接收数据,更新Flash(也就是APP),跳转至APP功能的特殊APP罢了。

以STM32F103为例,如果没有BootLoader,flash分布就如下图左半部分。如果有BootLoader,就如下图右半部分,将flash分为两部分(这里举例用0x800 4000做分界线),存储了两个应用程序(BootLoader和APP)

在这里插入图片描述


如何从BootLoader跳转到APP

从外部接收数据,更新Flash,普通的APP也会有这样的需求。不常见的也就是从BootLoader跳转到APP这个功能了。STM32 单片机启动流程中介绍了单片机上电后的启动流程,其实也就主要干了两件事:


  • 将栈顶位置加载到MSP寄存器中
  • 将复位中断服务函数的入口地址给PC寄存器

然后单片机执行复位中断服务函数,在复位中断服务函数中设置中断向量表的偏移地址,准备C环境,最后跳转到main()函数。同理,从Bootloader跳到APP也需要干这两件事情,只不过上电时是单片机自动加载的MSP和PC,而从Bootloader跳到APP则需要我们编写函数进行跳转。

下面是STM32 跳转到APP的具体函数,在BootLoader函数中调用即可跳转到APP_ADDR,如果该地址存放了APP的bin文件则会运行APP的复位中断服务函数(一定要记得在APP中修改中断向量表偏移地址,如APP中不修改则默认使用BootLoader的中断向量表,APP中发生中断时就会去查BootLoader的中断向量表,从而调用BootLoader的中断服务函数),进而运行APP的main()函数。同理,APP跳转到BootLoader,修改跳转地址 APP_ADDR 为BootLoader地址(这里为0x8000000)即可实现.

/* 开关全局中断的宏 */
#define ENABLE_INT() __set_PRIMASK(0) /* 使能全局中断 */
#define DISABLE_INT() __set_PRIMASK(1) /* 禁止全局中断 */
#define APP_ADDR 0x8004000 /* APP地址 */
/*
*********************************************************************************************************
* 函 数 名: JumpToApp
* 功能说明: 跳转到APP
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/

void JumpToApp(void)
{void (*SysMemBootJump)(void); /* 声明一个函数指针 */__IO uint32_t AppAddr = APP_ADDR; /* APP地址 *//* 如果初始化了外设,需要反向初始化外设 *//* 设置所有时钟到默认状态,使用HSI时钟 */HAL_RCC_DeInit();/* 关闭滴答定时器,复位到默认值 */SysTick->CTRL = 0;SysTick->LOAD = 0;SysTick->VAL = 0;/* 关闭全局中断 */DISABLE_INT();/* 关闭所有中断,清除所有中断挂起标志 */for (uint32_t i = 0; i < 8; i++){NVIC->ICER[i]=0xFFFFFFFF;NVIC->ICPR[i]=0xFFFFFFFF;} /* 使能全局中断 */ENABLE_INT();/* 设置SysMemBootJump为中断服务函数入口地址,首地址是MSP,地址+4是复位中断服务程序地址 */SysMemBootJump = (void (*)(void)) (*((uint32_t *) (AppAddr + 4)));/* 设置主堆栈指针 */__set_MSP(*(uint32_t *)AppAddr);/* 在RTOS工程,这条语句很重要,设置为特权级模式,SP使用MSP指针 */__set_CONTROL(0);/* 进行跳转 也就是将SysMemBootJump 赋值给PC */SysMemBootJump(); /* 跳转成功的话,不会执行到这里,用户可以在这里添加代码 */while (1){}
}

常用的BootLoader+APP框架

单片机升级的原理大致是:收到升级指令——>MCU复位或者跳转到Boot程序区——>擦除对应的Flash区域——>获取APP数据——>写入FLASH数据——>校验——>跳转到APP应用程序区


单APP

在这里插入图片描述

单APP方案将Flash分成了三个部分,Boot+APP+Config,Boot负责更新APP;APP实现程序的主要功能;Config区域主要是存放APP是否完整的标志位,协助Boot判断是否要跳转到APP。单APP有个明显的缺点:开始升级时就将原来的APP擦除了,如果升级中断则会一直停留在BootLoader,直至APP升级完成。

在这里插入图片描述


双APP

在这里插入图片描述

双APP方案将Flash分成了四个部分,Boot+APP1+APP2+Config,Boot负责更新APP;APP1实现程序的主要功能;APP2相当于缓冲区,Boot升级APP时,会将接收到的APP数据包写入APP2,当APP数据包全部接收完毕,再将APP2搬运到APP1,这样就避免了单APP方案,升级中断一直停留在BootLoader的尴尬; Config区域主要是存放APP1是否需要升级的标志位,协助Boot判断是否要将APP2的内容搬运至APP1。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1h8UZhVP-1634826311355)(https://note.youdao.com/yws/res/573/WEBRESOURCE9f58c37b82b61bd1f9cb2807c2d1055d)]


STM32系统BootLoader

STM32自举具体信息可以去官网查看手册AN2606
如果BOOT0为高电平,复位后将从系统存储器自举(系统存储区存放着系统bootLoader,出厂时,官方固化在单片机中的一段代码,用户无法修改的。在STM32中,常用的串口下载,DFU就是系统bootLoad中的功能)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kkPeB2VH-1634826311356)(https://note.youdao.com/yws/res/3/WEBRESOURCE1bf266619a522750a44281bafa410193)]

使用系统bootLoader需要在复位时调整BOOT0管脚的电平,使用起来还是比较麻烦的。系统BootLoader也是FLash中的一段程序,只不过是官方烧录的不可修改的,我们可以利用前面说的跳转到APP的方法跳转到系统BootLoader,这样就可以不修改BOOT0管脚电平,直接进入系统BootLoader,利用系统BootLoader的下载功能下载更新程序。

在这里插入图片描述

在手册中的闪存章节,找到系统BootLoader的起始地址0x1FFF F000,将APP_ADDR宏定义改为系统BootLoader地址即可跳转到系统BootLoader

/* 开关全局中断的宏 */
#define ENABLE_INT() __set_PRIMASK(0) /* 使能全局中断 */
#define DISABLE_INT() __set_PRIMASK(1) /* 禁止全局中断 */
#define APP_ADDR 0x1FFFF000 /* 系统bootloader地址 */
/*
*********************************************************************************************************
* 函 数 名: JumpToApp
* 功能说明: 跳转到APP
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/

void JumpToApp(void)
{void (*SysMemBootJump)(void); /* 声明一个函数指针 */__IO uint32_t AppAddr = APP_ADDR; /* 跳转地址 *//* 如果初始化了外设,需要反向初始化外设 *//* 设置所有时钟到默认状态,使用HSI时钟 */HAL_RCC_DeInit();/* 关闭滴答定时器,复位到默认值 */SysTick->CTRL = 0;SysTick->LOAD = 0;SysTick->VAL = 0;/* 关闭全局中断 */DISABLE_INT();/* 关闭所有中断,清除所有中断挂起标志 */for (uint32_t i = 0; i < 8; i++){NVIC->ICER[i]=0xFFFFFFFF;NVIC->ICPR[i]=0xFFFFFFFF;} /* 使能全局中断 */ENABLE_INT();/* 设置SysMemBootJump为中断服务函数入口地址,首地址是MSP,地址+4是复位中断服务程序地址 */SysMemBootJump = (void (*)(void)) (*((uint32_t *) (AppAddr + 4)));/* 设置主堆栈指针 */__set_MSP(*(uint32_t *)AppAddr);/* 在RTOS工程,这条语句很重要,设置为特权级模式,SP使用MSP指针 */__set_CONTROL(0);/* 进行跳转 也就是将SysMemBootJump 赋值给PC */SysMemBootJump(); /* 跳转成功的话,不会执行到这里,用户可以在这里添加代码 */while (1){}
}

从APP跳转到系统BootLoader后,利用STM32CubeProgrammer工具更新程序
在这里插入图片描述


推荐阅读
  • 在上篇文章的基础上,本文将继续探讨 Linux 设备驱动中的设备模型与 `devicedriverbus` 机制。在将设备注册到总线之前,需要先创建 `device` 对象。可以通过静态定义 `device` 结构体变量,并调用 `device_register` 函数来完成这一过程。此外,文章还将详细解析设备模型的内部工作机制,以及 `devicedriverbus` 机制如何实现设备与驱动的自动匹配和管理。 ... [详细]
  • Android开发常见问题汇总(含Gradle解决方案)第二篇
    本文继续深入探讨Android开发中常见的问题及其解决方案,特别聚焦于Gradle相关的挑战。通过详细分析和实例演示,帮助开发者高效解决构建过程中的各种难题,提升开发效率和项目稳定性。 ... [详细]
  • 微软发布紧急安全更新,所有Windows 10版本均面临影响!
    微软于周五紧急发布了两项安全更新,旨在解决Windows 10所有版本中Windows Codecs库和Visual Studio Code应用存在的安全隐患。此次更新是继本周初发布的月度例行安全补丁之外的额外措施,凸显了这些问题的紧迫性和重要性。这些漏洞可能被攻击者利用,导致系统权限提升或远程代码执行等严重后果。建议用户尽快安装更新,以确保系统的安全性。 ... [详细]
  • 7.2 利用关系运算符与表达式进行数值对比分析
    在C语言中,关系运算符和表达式是进行数值对比分析的基础工具。本节详细介绍了真值的概念及其在编程中的应用,包括布尔类型(_Bool)的引入,以及关系运算符的优先级。通过具体示例,展示了如何在 `while` 循环中使用关系表达式来控制程序流程。这些内容对于理解和编写高效的条件判断逻辑至关重要。 ... [详细]
  • 深入解析 Go 语言中的位操作技术 ... [详细]
  • HOJ 1402:整数分解与组合优化问题研究
    HOJ 1402 题目涉及整数划分的经典问题,旨在通过具体的实例提升对组合数学的理解和应用能力。该问题不仅考察了基本的数学原理,还要求对算法优化有深入的认识,以高效解决大规模数据下的整数分解与组合优化挑战。 ... [详细]
  • `ArrayDeque` 类中的 `removeLast()` 方法用于移除并返回双端队列中的最后一个元素。该方法在处理数据结构时非常有用,特别是在需要高效地从队列末尾移除元素的场景中。本文将详细介绍 `removeLast()` 方法的工作原理,并通过具体的应用实例展示其使用方法和优势。 ... [详细]
  • 本文探讨了Huffman树在数据结构中的应用及其原理。Huffman树,即哈夫曼树,是一种高效的数据压缩技术,通过构建最优二叉树实现编码,广泛应用于文件压缩和网络传输中,有效减少数据存储和传输的空间需求。 ... [详细]
  • 本章深入探讨了Java中的多态特性,这是面向对象编程的核心概念之一。多态指的是同一操作作用于不同的对象时,可以有不同的解释和执行方式。在Java中,多态通过父类引用变量引用子类对象来实现,即 `父类类型 引用变量名 = new 子类类型();`。这种方式允许程序在运行时根据实际对象的类型动态地选择合适的方法执行,从而提高代码的灵活性和可扩展性。此外,本章还详细介绍了多态的应用场景和注意事项,帮助读者更好地理解和运用这一重要概念。 ... [详细]
  • [Offer收割]编程竞赛第8轮 A 小Ho的完美主义倾向
    题目链接:小Ho的完美主义倾向题目描述:小Ho在一条直线型的街道上漫步。这条街道由若干块长度为L的石板铺设而成,因此每隔L的距离就会出现一道石板间的接缝。小Ho对这些规律排列的接缝产生了浓厚的兴趣,他决定研究如何在这条街道上行走,以满足自己对完美路径的追求。本题要求在给定的约束条件下,计算出小Ho能够实现其目标的所有可能方案数。 ... [详细]
  • 深入解析 org.hibernate.event.spi.EventSource.getFactory() 方法及其应用实例 ... [详细]
  • 本文详细解析了 `DirectoryInfo.GetFiles` 方法的使用方法及其应用场景。通过示例代码展示了如何在 C# 程序中利用该方法获取指定目录下的所有文件列表,同时探讨了其参数选项和返回值类型,为开发者提供了实用的操作指南。 ... [详细]
  • 在《物联网内核与驱动开发基础课程》第五讲中,详细解析了平台总线技术的应用与开发。本讲内容不仅涵盖了平台总线的基本概念,还深入探讨了其在嵌入式系统中的实现方法及优化策略,为开发者提供了宝贵的实践指导。通过具体案例分析,帮助学员更好地理解平台总线在设备管理、资源分配等方面的关键作用。 ... [详细]
  • 运用雅可比迭代法与高斯-赛德尔迭代法解线性方程组的比较分析
    本文对比分析了雅可比迭代法和高斯-赛德尔迭代法在求解线性方程组中的应用效果。通过详细的算法介绍和C语言实现,展示了两种方法的具体步骤和计算过程。实验结果表明,高斯-赛德尔迭代法在收敛速度和计算效率上优于雅可比迭代法,但在某些特定条件下,雅可比迭代法仍具有一定的优势。此外,文章还探讨了不同初始值和矩阵特性对迭代法性能的影响,为实际应用提供了有价值的参考。 ... [详细]
  • 在上一节中,我们完成了网络的前向传播实现。本节将重点探讨如何为检测输出设定目标置信度阈值,并应用非极大值抑制技术以提高检测精度。为了更好地理解和实践这些内容,建议读者已经完成本系列教程的前三部分,并具备一定的PyTorch基础知识。此外,我们将详细介绍这些技术的原理及其在实际应用中的重要性,帮助读者深入理解目标检测算法的核心机制。 ... [详细]
author-avatar
fuck__镇豪_152
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有