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

news2024/11/19 21:29:54

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 value
    BX 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.coloradmin.cn/o/1149869.html

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

相关文章

C++设计模式_19_Memento 备忘录(理解,目前多使用序列化方案来实现)

Memento 备忘录模式也属于“状态变化”模式,它是一个小模式,在今天来看有些过时,当今已经很少使用当前模式实现需求,思想却不变(信息隐藏),目前多使用序列化方案来实现。本系列所介绍的模式&…

资深8年测试总结,接口测试常用测试点汇总(精辟详细)

目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 接口测试是测试系…

【VPX630】青翼 基于KU115 FPGA+C6678 DSP的6U VPX通用超宽带实时信号处理平台

板卡概述 VPX630是一款基于6U VPX总线架构的高速信号处理平台,该平台采用一片Xilinx的Kintex UltraScale系列FPGA(XCKU115)作为主处理器,完成复杂的数据采集、回放以及实时信号处理算法。采用一片带有ARM内核的高性能嵌入式处理器…

当面试问你接口测试时,不要再说不会了

很多人会谈论接口测试。到底什么是接口测试?如何进行接口测试?这篇文章会帮到你。 前端和后端 在谈论接口测试之前,让我们先明确前端和后端这两个概念。 前端是我们在网页或移动应用程序中看到的页面,它由 HTML 和 CSS 编写而成…

Unity DOTS系列之Struct Change核心机制分析

最近DOTS发布了正式的版本, 我们来分享一下DOTS里面Struct Change机制,方便大家上手学习掌握Unity DOTS开发。 基于ArchType与Chunk的Entity管理机制 我们回顾以下ECS的内存管理核心机制,基于ArchTypeChunk的Entity管理模式。每个Entity不直接存放数据&#xff0c…

css矩形盒子实现虚线流动边框+css实现step连接箭头

由于项目里需要手写步骤条 且实现指定状态边框虚线流动效果&#xff0c;故使用css去绘制步骤条连接箭头和绘制边框流动效果 效果&#xff1a; 1.绘制步骤条连接箭头 <ul class"process-list"><div v-for"(process, index) in processes" :key&qu…

万圣节到了尽情狂欢吧Halloween is here Have a good time!

万圣节前夜是在10月31日庆祝的一个节日&#xff0c;根据传统&#xff0c;万圣节前夜的庆祝活动从太阳落山开始。Halloween is a holiday celebrated on October 31. By tradition, Halloween begins after sunset. 为了庆祝万圣节&#xff0c;孩子们化装成女巫、鬼和恶魔。To c…

『第十四章』雨燕的自我修养:Swift 调试技巧(下)

在本篇博文中,您将学到如下内容: 6. Xcode 界面调试6.1 Xcode 预览(Preview)7. 分析编译阶段8. 强大的 Instruments 工具9. Xcode 15 新结构化日志调试10. 一些调试小技巧总结离离原上草,一岁一枯荣. 野火烧不尽,春风吹又生 6. Xcode 界面调试 我们知道 App 在 Xcode 中运行…

kafka为什么如此之快?

天下武功&#xff0c;唯快不破。同样的&#xff0c;kafka在消息队列领域&#xff0c;也是非常快的&#xff0c;这里的块指的是kafka在单位时间搬运的数据量大小&#xff0c;也就是吞吐量&#xff0c;下图是搬运网上的一个性能测试结果&#xff0c;在同步发送场景下&#xff0c;…

一百九十七、Java——IDEA项目中把多层文件夹拆开显示

一、目的 由于IDEA项目中&#xff0c;默认的是把文件夹连在一起显示&#xff0c;于是为了方便需要把这些连在一起的文件夹拆开&#xff0c;分层显示 如文件夹cn.kgc 二、解决措施 解决方法很简单 &#xff08;一&#xff09;找到IDEA项目上的小齿轮 &#xff08;二&#xf…

QT实现用本地资源管理器来打开文件夹

QString path"文件夹路径";QDesktopServices::openUrl(QUrl("file:"path, QUrl::TolerantMode)); 在windows中QT编程&#xff0c;使用资源管理器来打开指定本地文件夹的方法&#xff1a; 第一种&#xff1a;使用Qprocess命令&#xff08;相当于在cmd命令管…

c语言基础:L1-064 估值一亿的AI核心代码

以上图片来自新浪微博。 本题要求你实现一个稍微更值钱一点的 AI 英文问答程序&#xff0c;规则是&#xff1a; 无论用户说什么&#xff0c;首先把对方说的话在一行中原样打印出来&#xff1b;消除原文中多余空格&#xff1a;把相邻单词间的多个空格换成 1 个空格&#xff0c…

生产环境接口频繁502

目录 基本信息 问题现象 问题原因 排查过程 解决方案 基本信息 客户名称&#xff1a;xx集团 产品名称&#xff1a;ATS 3.0微服务单体 版本号&#xff1a;3.1.14.X 问题分类&#xff1a;环境问题 环境类型&#xff1a;K8S 问题现象 单体组织计划的新增/修改功能&#xff0…

基于STM32的多功能智能密码锁控制设计

**单片机设计介绍&#xff0c;1653基于STM32的多功能智能密码锁控制设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序文档 六、 文章目录 一 概要 基于STM32的多功能智能密码锁控制设计是一种用STM32微控制器开发的系统&#xff0c;用于控制和管理密码…

html获取网络数据,列表展示 第二种

html获取网络数据&#xff0c;列表展示 第二种 js遍历json数组中的json对象 image.png || - 判断数据是否为空&#xff0c;为空就显示 - <!DOCTYPE html> <html><head><meta charset"utf-8"><title>网页列表</title><script …

1.7 攻击面和攻击树

思维导图&#xff1a; 1.7 攻击面与攻击树 攻击面: 描述计算机和网络系统面对的安全威胁和攻击。 定义: 攻击面是由系统中可访问和可利用的漏洞所组成。常见攻击面: 向外部Web及其他服务器开放的端口和相应代码。防火墙内部的服务。处理入站数据、电子邮件、XML文件、Office文档…

css写个三角形

点击三角形&#xff0c;展开或者收起内容 <template><div><div class"zhankai" click"btn()">展开 <span :class"{sanjiao:true,rotate:flag}"></span></div><!-- 展示或者收起 --><el-collapse-…

21.14 Python 实现Web指纹识别

在当今的Web安全行业中&#xff0c;识别目标网站的指纹是渗透测试的常见第一步。指纹识别的目的是了解目标网站所使用的技术栈和框架&#xff0c;从而进一步根据目标框架进行针对性的安全测试&#xff0c;指纹识别的原理其实很简单&#xff0c;目前主流的识别方式有下面这几种。…

图像编辑软件 Pixelmator Pro mac中文版高级功能

Pixelmator Pro mac是一款功能强大、易于使用的图像编辑软件&#xff0c;适合各种用户进行图像处理、修复和设计。它提供了丰富多样的工具和功能&#xff0c;帮助您轻松创建出令人惊艳的图像作品。 Pixelmator Pro mac支持非破坏性编辑&#xff0c;意味着您可以对图像进行修改而…