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 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的一些疑惑,有不少的收货和感悟。

  • 10
    点赞
  • 86
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星羽空间

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值