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。举个比较简单的例子,我用STM32F103C8T6写了两个游戏程序,但是如果要来回烧录程序来游玩不同的游戏就很麻烦,所以我用我现在的方式,实现了在开机后,按下按键1就执行游戏1的程序,按下按键2就执行另一个游戏2的程序。

你问我能不能通过编写多级菜单的方式来实现游戏数据的切换?我的回答当然是可以,但是你需要将两个游戏的工程合并到一个工程中,然后还要考虑到单片机的内存因素,编写很多内存管理的代码,略微麻烦,所以通过Bootloader来进行这个选择是比较好的方式。

那么主要靠下面的代码进入到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

需要烧录三次。也可以通过将bin文件合并的方式只烧录一次

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

### STM32F103 微控制器内存分布详解 STM32F103 是基于 ARM Cortex-M3 内核的高性能微控制器,其内部存储器结构经过精心设计,能够高效支持程序运行和数据处理。以下是对其内存分布的具体分析: #### 1. **代码区 (Code Area)** - 地址范围:`0x00000000 ~ 0x1FFFFFFF` (共 512 MB) - 主要用途: - 启动空间 (`0x00000000 ~ 0x07FFFFFF`):用于引导加载程序。 - Flash 存储区 (`0x08000000 ~ 0x08xxxxxx`):存放用户编写的程序代码,大小取决于具体型号。例如,STM32F103C8T6 的 Flash 容量为 64 KB[^1],而 STM32F103CBT6 则为 128 KB[^1]。 - 系统存储区 (`0x1FFFF000 ~ 0x1FFFF800`):容量为 2 KB,主要用于存放串口下载程序或其他特定功能代码。 #### 2. **内部 SRAM (Static Random Access Memory)** - 地址范围:`0x20000000 ~ 0x200xxxxx` - 大小:根据具体型号有所不同,例如 STM32F103C8T6 提供 20 KB SRAM,而更高规格版本可能达到 96 KB 或更多。 - 功能:SRAM 是一种易失性存储器,用于存储程序运行过程中产生的临时变量、堆栈和其他动态分配的数据。 #### 3. **外设寄存器地址空间 (Peripheral Registers Space)** - 地址范围:分布在 `0x40000000 ~ 0xFFFFFFFF` 范围内的多个子区间。 - 特点:每个外设都有独立的寄存器地址映射,便于 CPU 访问和控制硬件资源。常见的外设有 UART、SPI、I2C、GPIO 和定时器等。 - 示例: - USART1 寄存器位于 `0x40013800` 开始的地址范围内[^4]。 - TIM2 定时器寄存器位于 `0x40000000` 开始的地址范围内[^5]。 #### 4. **特殊功能区域** - **Bootloader 区域**:某些情况下,系统会将 Flash 或者系统存储区的内容映射到启动空间,从而决定是从 Flash 运行用户程序还是进入 Bootloader 模式进行固件升级。 - **备份寄存器区**:部分型号提供了专门的备份寄存器(Backup Register),即使在掉电状态下也能保持少量重要数据不丢失。 #### 数据存储格式说明 - STM32F103 中的数据是以 **小端模式** 存放的[^2]。这意味着低位字节总是存储在较低的物理地址处,高位字节则依次向更高的地址扩展。 --- ### 示例代码展示如何访问 STM32F103 的内存区域 以下是一个简单的例子,演示如何通过指针操作访问 SRAM 和 Flash 区域中的数据。 ```c #include "stm32f1xx.h" int main(void) { uint32_t *flash_ptr = (uint32_t *)0x08000000; // 指向 Flash 起始地址 uint32_t *sram_ptr = (uint32_t *)0x20000000; // 指向 SRAM 起始地址 // 假设我们在 Flash 的第一个位置写入了数值 0xDEADBEEF sram_ptr[0] = flash_ptr[0]; // 将 Flash 的值复制到 SRAM while (1); } ``` --- ###
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

IoT_H2

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

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

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

打赏作者

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

抵扣说明:

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

余额充值