STM32的bootloader程序(通过串口更新STM32应用程序)

1 什么是bootloader?

        Bootloader,也被称为引导加载程序,是操作系统启动过程中的一个重要组成部分。它是存储在非易失性存储器中的一段小程序,负责在操作系统内核运行之前加载并启动一些必要的系统组件。

        当计算机开机后,BIOS(基本输入/输出系统)会首先运行,检查并初始化系统硬件,然后从设定的启动设备(如硬盘、U盘等)中找到Bootloader并把控制权交给它。Bootloader随后开始执行,它会加载操作系统内核到内存,并传递一些必要的系统参数。

2 为什么需要Bootloader?

        Bootloader的任务很重要,因为它构成了硬件和操作系统之间的桥梁。如果没有Bootloader,操作系统就无法启动。Bootloader还通常包括一个用户接口,允许用户在多个操作系统中选择一个进行启动,或者修改操作系统的启动参数。

3 Bootloader实例

        Bootloader的具体实现和功能可能根据操作系统和硬件的不同而有所差异。例如,Linux系统常见的Bootloader有GRUB和LILO,而Windows系统通常使用的是NTLDR或BootMGR。

        说实话,从单片机角度来说,上述例子并不典型。这里举个最为典型的例子:ArduinoIDE为何能给Arduino开发板下载程序?就是因为开发板上搭载了Bootloader。当串口启动后,Arduino即进入复位,进入Bootloader程序,进行监听串口,接受串口下发的应用程序,将应用程序写入arduino芯片中。这样就可以不通过ISP,JTAG等方式,而是通过串口实现了芯片上程序的更新。

        具体原理,笔者在之前的文章写过,可跳转:

Arduino是如何实现打开串口时,程序复位的?-CSDN博客

4 如何实现在STM32的bootloader程序?

        根据上面举的arduino的例子,我们来实现一个STM32版本的,通过串口更新程序的bootloader吧。

        其运行原理大致可以归纳为以下几个步骤:

  1. 上电复位:首次给STM32供电或者按下复位键后,STM32会开始从预设的启动地址(一般是内部Flash的起始地址或者其他特定内存位置)开始运行程序。

  2. 启动阶段:在供电后的最初阶段,STM32的Bootloader会先被执行。Bootloader是一个预先在STM32内部ROM中烧录的小程序,其主要任务包括初始化硬件设备、设置系统时钟、配置内存等。

  3. 程序加载:Bootloader完成启动后,会开始加载用户程序。该程序通常存储在内部的Flash内存或者外部的存储设备中。程序被加载到SRAM中执行。如果用户程序存储在Flash中,Bootloader可以直接跳转到Flash的起始地址开始执行。

  4. 主循环:用户程序通常会包含一个主循环(main loop),在这个主循环中,程序会周期性地或者根据特定事件执行特定任务。例如,它可能会每隔一段时间读取一个传感器的数据,或者当接收到一个网络包时进行处理。

  5. 中断处理:在程序运行过程中,可能会发生各种中断,比如定时器到期、外部引脚状态变化、接收到串口数据等。当中断发生时,CPU会停止当前的任务,跳转到对应的中断服务程序进行处理,处理完毕后再返回到原来的任务继续执行。

4.1 keil编译后,HEX文件内容解读

        要实现串口下载功能,就得先知道烧录程序HEX或者BIN文件究竟是个什么东西。关于HEX我以前也写过相关文章,可以跳转一下:

STM32的hex文件格式的分析-CSDN博客

关于BIN,目前还未过深的了解,印象中是二进制版本的HEX文件。

4.2 如何实现程序跳转

        STM32的程序实际上就是从FLASH地址由上到下,根据指令内容,跳转到FLASH相应地址继续执行的而已。

因此,如果我们要实现从bootloader跳转到我们flash写入的地址,如何实现呢?这里给个bootloader跳转到用户程序的参考例子:

#define FLASH_SAVE_ADDR  0x08020000		//设置 FLASH 地址(必须为偶数,且其值要大于本代码所占用FLASH的大小+0X08000000)
typedef  void (*iapfun)(void);			//定义一个函数类型的参数.//设置栈顶地址
//addr:栈顶地址
__asm void MSR_MSP(uint32_t addr) {MSR MSP, r0 			//set Main Stack valueBX r14
}iapfun jump2app; //跳转到应用程序段
//appxaddr:用户代码起始地址.
void iap_load_app(uint32_t appxaddr) {if(((*(__IO uint32_t*)appxaddr)&0x2FFE0000)==0x20000000) 	//检查栈顶地址是否合法.{ jump2app=(iapfun)*(__IO uint32_t*)(appxaddr+4);		//用户代码区第二个字为程序开始地址(复位地址)		MSR_MSP(*(__IO uint32_t*)appxaddr);					//初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)jump2app();									//跳转到APP.}
}int main(void) {//判断是否 PA5 按键状态,按下则跳转到 FLASH_SAVE_ADDR 地址运行另外一个程序if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5) == RESET) {iap_load_app(FLASH_SAVE_ADDR);//跳转执行FLASH_APP代码}
}

我们烧写的用户应用程序则需要注意修改一下地址便宜:

根据实际需要进行修改。图中Start地址#define FLASH_SAVE_ADDR保持一致。图中Size大小则应该是0x8040000-Start地址

并且修改Flash地址偏移(在main首句或之前赋值即可):

SCB->VTOR = FLASH_BASE | 0x20000; //内部FLASH的向量表重定位

 根据实际需要进行修改。这偏移值应该是 Start地址-0x8000000

4.3 如何实现对STM32内部Flash的写入

        STM32的标准库有对FLASH操作的API,可以使用这些API对FLASH进行操作。其大致流程如下:

  1. 解锁Flash:在写入Flash之前,首先需要对Flash进行解锁。STM32的Flash有写保护功能,为了防止意外操作导致的数据损坏,需要手动解除保护。解锁操作需要向特定的解锁寄存器(如KEYR)写入特定的密钥序列。

  2. 等待Flash就绪:解锁完成后,需要确保Flash处于就绪状态。可以通过检查FLASH_SR寄存器的相关位(如BSY位)来判断Flash是否处于忙碌状态。务必等待Flash就绪后再进行后续操作。

  3. 擦除目标扇区:在写入数据之前,需要先擦除目标扇区。STM32的Flash是按扇区进行擦写的,擦除一个扇区会把该扇区的所有数据设置为全1(0xFF)。擦除操作需要设置FLASH_CR寄存器的相关位,并指定需要擦除的扇区。

  4. 等待擦除完成:擦除操作需要一定的时间,因此需要等待擦除完成。可以通过检查FLASH_SR寄存器的相关位(如EOP位)来判断擦除是否完成。务必等待擦除完成后再进行后续操作。

  5. 写入数据:擦除完成后,就可以开始向目标地址写入数据了。通常,可以选择按字(32位)或半字(16位)进行写入。写入操作需要设置FLASH_CR寄存器的相关位,并将数据写入到目标地址。

  6. 等待写入完成:与擦除操作类似,写入操作也需要一定的时间。因此需要等待写入完成。可以通过检查FLASH_SR寄存器的相关位(如EOP位)来判断写入是否完成。

  7. 锁定Flash:写入操作完成后,为了防止意外操作导致的数据损坏,建议重新锁定Flash。锁定操作需要设置FLASH_CR寄存器的相关位(如LOCK位)。

具体的开发实例,可以参考野火或者正点原子的教程。笔者比较喜欢实用标准库,因此,喜欢实用野火的教程作为参考。

4.4 实现的Bootloader展示

        这里就不用过多篇幅去展示我的程序代码了,有需要跳转下方链接自行下载(包含上下位机):

基于stm32实现串口烧录程序资源-CSDN文库

        大概说明一下,笔者实现了,开机时按下key1按钮,待LED熄灭,释放key1按钮即进入程序烧录模式。如按下的key2按钮,将自动烧录在bootloader中准备好的点亮LED1的程序。收录完成后即会自行跳转到用户应用程序。

        笔者这示例,用户应用程序是从地址0x8010000开始的,size为0x30000。

        需要先进入烧录模式再启动python脚本进行程序烧录。因为只是测试用例,并未设计得太用户化。

5 总结

        bootloader的功能并不止程序更新这一种,还应该包括开机自检等功能,不过这些功能都需要结合实际情况进行开发了,笔者也就不再过多叙述。这此实验算是解开了笔者从前对arduino的一些疑惑,有不少的收货和感悟。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/124926.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ICC2: 如何在显示GUI操作产生的命令

我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧? 拾陆楼知识星球入口 ICC2:自定义快捷键和菜单 VIEW -> Perference -> Global Settings 把display commands in logging console 下面几个都勾上即可。

css:button实现el-radio效果

先看最终效果&#xff1a; ​​​ 思路&#xff1a; 一、 首先准备好按钮内容&#xff1a;const a [one,two,three] 将按钮循环展示出来&#xff0c;并设置一些样式&#xff0c;将按钮背景透明&#xff1a; <button v-for"(item,index) in a" :key"in…

Python 字典(Dictionary) get() 函数返回指定键的值

Python 字典(Dictionary) get() 函数返回指定键的值。 语法 get()方法语法&#xff1a; dict.get(key[, value]) 参数 key – 字典中要查找的键。 value – 可选&#xff0c;如果指定键的值不存在时&#xff0c;返回该默认值。 返回值 返回指定键的值&#xff0c;如果键不在字…

实战之巧用header头

案例&#xff1a; 遇到过三次 一次是更改accept&#xff0c;获取到tomcat的绝对路径&#xff0c;结合其他漏洞获取到shell。 一次是更改accept&#xff0c;越权获取到管理员的MD5加密&#xff0c;最后接管超管权限。 一次是更改accept&#xff0c;结合参数获取到key。 这里以越…

C # 基础知识汇总

C# 委托和事件 非常经典 上文最初链接

计算节点上iptables安全组分析

计算节点上iptables安全组分析 之前介绍过neutron 安全组基于iptables 和 ct 实现&#xff0c;分析一下计算节点上面的neutron 安全组的iptables&#xff0c;加深一下理解iptables以及安全组的实现。&#xff08;PS: 如下基于openstack stein) 查看某计算节点上面的iptables …

如何选购适合自己的内衣洗衣机?性价比高内衣洗衣机推荐

内衣洗衣机&#xff0c;在几年前或许是个新事物&#xff0c;但近两年却是成为了很普遍的家电产品&#xff0c;由于近几年内衣洗衣机需求量的增加&#xff0c;我们在商场的电子产品区都能见到它&#xff0c;就像普通的家庭洗衣机那样&#xff0c;直接摆在展台上销售&#xff0c;…

VPS是什么?详解亚马逊云科技Amazon Lightsail(VPS)虚拟专用服务器

2006年&#xff0c;南非开普敦&#xff0c;亚马逊推出了WBS&#xff0c;以网络服务的形式向企业提供基础的IT服务。亚马逊云科技的一小步&#xff0c;在无数技术更迭&#xff0c;天才设计师和程序员的努力与基础设施建设的完善之下成为了人类科技进展的一大步。 亚马逊云科技可…

LeetCode75——Day21

文章目录 一、题目二、题解 一、题目 1207. Unique Number of Occurrences Given an array of integers arr, return true if the number of occurrences of each value in the array is unique or false otherwise. Example 1: Input: arr [1,2,2,1,1,3] Output: true Ex…

【Spring Boot 源码学习】RedisAutoConfiguration 详解

Spring Boot 源码学习系列 RedisAutoConfiguration 详解 引言往期内容主要内容1. Spring Data Redis2. RedisAutoConfiguration2.1 加载自动配置组件2.2 过滤自动配置组件2.2.1 涉及注解2.2.2 redisTemplate 方法2.2.3 stringRedisTemplate 方法 总结 引言 上篇博文&#xff0…

携手云栖,共望未来

&#x1f4a8;随着信息技术的迅猛发展&#xff0c;云计算已成为推动数字经济发展的重要驱动力之一。在这个领域中&#xff0c;云栖大会无疑是中国乃至全球最重要的盛会之一。云栖大会的历史可以追溯到2009年的地方网站峰会&#xff0c;随着时间的推移&#xff0c;它逐渐演变为阿…

如何在Instagram和kol展开合作

网红营销已经演变成一个由品牌、MCN机构、红人和消费者组成的复杂生态系统&#xff0c;并在某种程度上重新定义了当今社交媒体时代营销和广告的本质。在这个情况下&#xff0c;品牌找红人进行营销推广已经成为大势&#xff0c;而最能体现网红营销发展的莫过于Instagram这个平台…

数据结构(三):栈及面试常考的算法

一、栈介绍 1、定义 栈也是一种数据呈线性排列的数据结构&#xff0c;不过在这种结构中&#xff0c;我们只能访问最新添加的数据。从栈顶放入元素的操作叫入栈&#xff0c;取出元素叫出栈。 2、优缺点及使用场景 优点&#xff1a;高效的操作、简单易用、空间效率高等 缺点&…

【SpringSecurity】快速入门—通俗易懂

目录 1.导入依赖 2.继承WebSecurityConfigurerAdapter 3.实现UserDetailsService 4.记住我 5.用户注销 6.CSRF理解 7.注解功能 7.1Secured 7.2PreAuthorized 7.3PostAuthorized 7.4PostFilter 7.5ZPreFilter 8.原理解析 1.导入依赖 首先&#xff0c;在pom.xml文…

计算机网络-IP地址

文章目录 子网划分定长子网划分子网划分的方法子网掩码 可变长子网划分 无类别编址网络前缀路由聚合 特殊用途的IP地址专用网络地址链路本地地址运营商级NAT共享地址用于文档的测试网络地址 IP地址的规划和分配IP地址的规划和分配方法IP地址的规划和分配实例 子网划分 定长子网…

PyTorch入门学习(八):神经网络-卷积层

目录 一、数据准备 二、创建卷积神经网络模型 三、可视化卷积前后的图像 一、数据准备 首先&#xff0c;需要准备一个数据集来演示卷积层的应用。在这个示例中&#xff0c;使用了CIFAR-10数据集&#xff0c;该数据集包含了10个不同类别的图像数据&#xff0c;用于分类任务。…

文章分类管理接口

目录 前言 新建表 获取文章分类列表接口 初始化路由模块 将路由对象导出并使用 初始化路由对象处理函数 修改路由代码 导入数据库 定义sql语句 调用db.query() 完整的获取文章分类列表处理函数 新增文章分类接口 定义路由和处理函数 验证表单数据 查询分类名称与…

<基础数学> 三个点生成一个圆

三个点生成一个圆 如果给定三个点的坐标&#xff0c;我们可以通过这三个点来确定一个圆。以下是一种求解方法&#xff1a; 假设给定的三个点分别为 A ( x 1 , y 1 ) 、 B ( x 2 , y 2 ) 、 C ( x 3 , y 3 ) A(x_1, y_1)、B(x_2, y_2)、C(x_3, y_3) A(x1​,y1​)、B(x2​,y2​…

UDP网络编程的接受与发送信息

/发送端B>可以接受数据 public class UDPSenderB {public static void main(String[] args) throws IOException {//创建一个DatagramSocket 对象&#xff0c;准备发送和接受数据DatagramSocket socket new DatagramSocket(9998);//将需要发送的数据&#xff0c;封装到Data…

空号检测API如何助力于提高客户关系管理

引言 在现代商业世界中&#xff0c;客户关系管理已经成为企业成功的关键要素之一。CRM不仅涉及到如何吸引新客户&#xff0c;还包括如何维护并与现有客户建立持久而有益的关系。在这个过程中&#xff0c;通信是至关重要的。为了确保您的客户数据库保持最新和准确&#xff0c;空…