MCU双分区方案,如何优雅地获知当前运行分区?

请添加图片描述


引言

在嵌入式系统的固件更新策略中,双分区设计因其可靠性和安全性成为行业标准做法。在这种架构中,芯片保留两个独立固件分区:一个当前运行分区(Active)和一个备份分区(Backup)。当需要更新固件时,系统会将新固件写入非活动分区,然后通过安全切换机制交换分区角色。但应用程序如何知道自己运行在哪个分区中?本文将探讨几种优雅的解决方案。


双分区基础方案

典型的双分区布局如下(以512KB Flash为例):

分区A:
  ORIGIN: 0x00000000
  SIZE:   256KB

分区B:
  ORIGIN: 0x00040000
  SIZE:   256KB

方法一:链接脚本定义分区变量(硬件级别)

// 分区A的链接脚本
.partition_info :
{
   
  . = ORIGIN(m_partition_flag);
  __partition_id = .;
  LONG(0x55AAAA55); // A分区魔法值
  . = ALIGN(4);
} > m_partition_flag

// 应用程序使用
__attribute__((used, section(".partition_info")))
extern const uint32_t __partition_id;

int get_current_partition(void) {
   
    return (__partition_id == 0x55AAAA55) ? PARTITION_A : PARTITION_B;
}

优点:

  • 无运行时开销

  • 内存地址固定在Flash中

  • 无法被意外修改

缺点:

  • 需要为每个分区单独编译固件

方法二:PC指针范围检测(通用方法)

typedef enum {
   
    PARTITION_A = 0,
    PARTITION_B,
    PARTITION_UNKNOWN
} PartitionID;

PartitionID get_current_partition(void) {
   
    uint32_t pc = (uint32_t)__builtin_return_address(0);
    
    #define PARTITION_A_START   0x00000000
    #define PARTITION_A_END     0x0003FFFF
    #define PARTITION_B_START   0x00040000
    #define PARTITION_B_END     0x0007FFFF
    
    if(pc >= PARTITION_A_START && pc <= PARTITION_A_END) {
   
        return PARTITION_A;
    }
    else if(pc >= PARTITION_B_START && pc <= PARTITION_B_END) {
   
        return PARTITION_B;
    }
    else {
   
        return PARTITION_UNKNOWN;
    }
}

优点:

  • 无需特殊硬件支持

  • 单固件适配双分区

  • 简单可靠

缺点:

  • 轻微运行时开销(约10 CPU周期)

  • 依赖编译器内置函数


方法三:Bootloader分区信令(协作式)

核心原理

Bootloader在加载并跳转到应用程序时,通过特定的RAM区域传递分区信息,如下图所示:

[Bootloader启动]
        │
        ▼
[验证分区完整性]
        │
        ▼
[设置分区标识到RAM]
        │
        ▼
[跳转到应用程序]
        │
        ▼
[应用读取RAM标识]

详细实现

​​1. 内存规划 (链接脚本)​

MEMORY {
    /* ... 其他区域定义 ... */
    m_shared_ram (RW) : ORIGIN = 0x2000F000, LENGTH = 0x00000100
}

SECTIONS {
    .shared_data : {
        _shared_data_start = .;
        *(.shared_data)
        _shared_data_end = .;
    } > m_shared_ram
}

2. Bootloader关键代码​

// 定义共享数据结构体
typedef struct {
   
    uint32_t partition_id;
    uint32_t crc_checksum; // 可选校验值
    uint32_t boot_timestamp;
} SharedBootInfo;

#define SHARED_DATA_ADDR 0x2000F000

void launch_app(uint32_t app_addr, PartitionID partition) {
   
    volatile SharedBootInfo* info = (SharedBootInfo*)SHARED_DATA_ADDR;
    
    // 设置分区信息
    info->partition_id = partition;
    info->boot_timestamp =
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

智驾

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

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

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

打赏作者

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

抵扣说明:

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

余额充值