STM32F103C8T6 IAP升级

0x00 前言

STM32有三种烧录程序的方式:烧录器下载、拉高boot1进行串口下载(ISP)还有通过在 Bootloader中进行flash擦除和写入(IAP)。

在进行开发之前,你需要了解一下Bootloader是什么。

Bootloader是嵌入式系统在加电后执行的第一段代码,也称为引导加载程序。它不属于操作系统内核,而是在操作系统内核或用户程序运行之前运行。

举个简单的例子。例如我的拓竹3D打印机,在开机之后,它的Bootloader会进行硬件自检、联网检查固件等操作,而一旦发现了有新版本的固件可以用,那么它就会提示你需要更新后才能使用,更新后它便会开始执行新的固件。

假设这台3D打印机的用到的芯片是STM32,那么它是如何实现这个操作的呢?

首先你的设备flash中,需要存储下一个Bootloader引导分区,然后是一个app应用分区。
当你的决定升级时,那么你就需要将app应用分区的内容擦除,然后用你的新固件去覆盖。
或者你决定不升级,那么在Bootloader程序结束后,直接进入到app应用分区之中。

那么你现在需要做的,就是编写一个Bootloader程序,然后再编写一个APP程序,并确保在bootloader程序结束后,能够准确的进入到app应用之中。你需要确保你的 STM32 flash够大,可以同时存下这两个程序。如果你有特殊需求,你甚至可以编写多个应用分区,以满足你不同的需求。

STM32的flash起始地址是0x0800 0000,八百万,很好记。意味着你每一次烧录程序,都是将程序从这个地址开始烧录;也代表着系统再运行的时候,每一次都是从这个地址开始加载程序。

至于flash结束地址,与你实际所使用的单片机有关系。本文选用了STM32F103C8T6开发板,最常见的小蓝板。它的flash大小是64kb,所以结束地址是0x0801 0000。

0x01 flash分区

做一件事情,最为重要的就是前期规划,不能想到什么做什么,这也是我最近学到的。

你需要将stm32的flash区间分为两段甚至多段。

我决定将STM32的 0x800 0000 - 0x800 2000 作为我们的Bootloader 地址段,这个段的大小大概是8KB,我之前写的Bootloader大小大概是5.6KB,分配8KB的原因为要为后续程序升级留有余地,否则牵一发而动全身,到时候重新修改flash分区则会导致很多地方需要修改。
在这里插入图片描述

然后我将剩下的flash分为两个大小一致的分区,打算放下两个app分区在里面。

在这里插入图片描述

这个是APP2在flash分区中所占用的地址段
在这里插入图片描述

0x02 Bootloader

在程序启动的时候,程序会从0x0800 0000地址加载代码,然后将其搬运至RAM(0x0200 0000)中以供执行。

所以我们的Bootloader自然是从0x0800 0000 开始。

在Bootloader中,主要需要实现两个功能:

  1. 选择需要进入的分区
  2. 进入选中的分区

在这里我选择了根据按键的状态进入选中的分区,如果按键1 按下,就进入APP1,如果按键2按下,就进入APP2。

主要靠下面的代码进入到APP1分区或APP2分区。

需要关中断和设置栈顶指针

#include "stm32f10x.h"
#include "key.h"

#define 	appxaddr 			 0x08000000
#define	 	FLASH_APP1_ADDR		 0x08002000
#define 	FLASH_APP2_ADDR 	 0x08006000

void iap_load_app(u32 appxaddr)
{
	SysTick->CTRL = 0X00;//禁止SysTick
	SysTick->LOAD = 0;
    SysTick->VAL = 0;
    __disable_irq();
    jump2app=(iapfun)*(vu32*)(appxaddr+4);
    MSR_MSP(*(vu32*)appxaddr);
    jump2app();	
}

int main()
{
	Key_Init();
	while(1)
	{
		if (Key1 == 1)
			iap_load_app(FLASH_APP1_ADDR);
		if (Key2 == 1)
			iap_load_app(FLASH_APP2_ADDR);
	}
	
	return 0;
}

0x02 APP设置

在APP中,需要修改的地方比较少,需要为你的工程设置flash起始地址和flash结束地址,这样如果你编译的固件超过了规定的大小,会弹出报错来提示flash不够用。

设置完工程后,需要将中断向量地址表偏移指定长度。例如APP1之前有一个0x2000大小的Bootloader,那么你的中断向量地址表就需要偏移0x2000个字节。例如APP2,在这个地址之前有Bootloader和APP1一共0x6000大小,那么就需要偏移0x6000个字节。

如下代码,只需要加一句代码就足够

#include "stm32f10x.h"
#include "delay.h"
#include "led.h"

int main()
{
    /* 中断向量表偏移 */
    SCB->VTOR = FLASH_BASE | 0x2000;  
	
	LED_Init();
	delay_init();

	while(1)
	{
		LED_ON;
		delay_ms(1000);
		LED_OFF;
		delay_ms(1000);
	}

	return 0;
}

0x03 升级程序编写

升级程序可以直接使用正点原子的IAP例程中的iap.c和stmflash.c,修改你的触发逻辑就可以了。

比如说 单机按键1就进入app1,长按按键1 就开始接收新程序并且切入到app1分区

还有 单机按键2就进入app2,长按按键2 就开始接收新程序并且切入到app2分区

0x04 固件烧录

烧录固件时需要注意固件烧录的起始地址,不要覆盖了之前的程序。并且一定要烧录二进制文件,不能烧录16进制文件,16进制的文件包含了一些地址信息可能会导致APP无法运行。

在Keil中需要将你的Bootloader程序设置地址为 0x0800 0000,然后 size 设置为 0x2000
将你的APP1程序设置地址为 0x0800 2000,然后 size 设置为 0x4000
将你的APP2程序设置地址为 0x0800 6000,然后 size 设置为 0x4000

需要烧录三次。

写好了例程,需要的评论区留下邮箱

相关推荐

  1. 基于stm32f103c8t6连接阿里云上传信息

    2024-06-13 19:28:03       57 阅读
  2. 如何使用Arduino IDE对STM32F103C8T6进行编程

    2024-06-13 19:28:03       37 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-13 19:28:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-13 19:28:03       100 阅读
  3. 在Django里面运行非项目文件

    2024-06-13 19:28:03       82 阅读
  4. Python语言-面向对象

    2024-06-13 19:28:03       91 阅读

热门阅读

  1. MySQL bin-log日志恢复数据

    2024-06-13 19:28:03       32 阅读
  2. LVS ipvsadm命令的使用(二)

    2024-06-13 19:28:03       28 阅读
  3. CVE-2020-1472域渗透 NetLogon 权限提升漏洞

    2024-06-13 19:28:03       34 阅读
  4. 在 Visual Studio 调试器中指定符号 (.pdb) 和源文件

    2024-06-13 19:28:03       29 阅读
  5. Android 调用系统相册、系统相机拍照

    2024-06-13 19:28:03       26 阅读
  6. 新视野大学英语2 词组 6.13

    2024-06-13 19:28:03       32 阅读
  7. Hutool有哪些常用方法

    2024-06-13 19:28:03       24 阅读
  8. SQL Server几种琐

    2024-06-13 19:28:03       28 阅读
  9. 等保测评练习题

    2024-06-13 19:28:03       29 阅读