3. Bootloader与应用程序内存分区规划

任务目标

为Bootloader与应用程序规划独立的内存分区,明确起始地址、分区大小及访问保护机制,确保两者在Flash中互不干扰,并为后续跳转与升级功能奠定地址基础。

内存布局设计

以瑞萨RH850/P1x系列(32位MCU,Flash起始地址0x00000000)为例,设计如下布局:

  • Bootloader区:0x00000000 ~ 0x0000FFFF(64KB),存放启动代码与升级驱动
  • 应用程序区:0x00010000 ~ 0x0007FFFF(448KB),存放应用逻辑
  • Flash保护状态寄存器区:0x00000000 起始的专用配置字(由芯片选项字节控制)
Bootloader 区 0x00000000 - 0x0000FFFF (64KB) 应用程序区 0x00010000 - 0x0007FFFF (448KB) 应用程序中断向量表 (0x00010000 - 0x000101FF) 应用程序主代码区 (0x00010200 - 0x0007FFFF) Flash保护配置区(选项字节,位于Bootloader起始地址) 分区边界

链接脚本实现(GHS Linker Script)

以下链接脚本定义物理分区与访问权限,是内存规划落地的核心文件:

/* memory_layout.ld */
MEMORY
{
    /* Bootloader区:64KB,只读+可执行 */
    FLASH_BOOT (rx)  : ORIGIN = 0x00000000, LENGTH = 64K
    
    /* 应用程序区:448KB,只读+可执行 */
    FLASH_APP  (rx)  : ORIGIN = 0x00010000, LENGTH = 448K
    
    /* 内部RAM:用于Bootloader与App共享的跳转参数 */
    RAM       (rwx)  : ORIGIN = 0xFED00000, LENGTH = 64K
}

SECTIONS
{
    /* Bootloader向量表与代码 */
    .boot_vector :
    {
        KEEP(*(.boot_vector))
    } > FLASH_BOOT
    
    .boot_text :
    {
        *(.boot_text)
        *(.text*)
    } > FLASH_BOOT
    
    /* 应用程序向量表:必须4字节对齐 */
    .app_vector 0x00010000 :
    {
        KEEP(*(.app_vector))
    } > FLASH_APP
    
    .app_text :
    {
        *(.app_text)
        *(.text*)
    } > FLASH_APP
    
    .rodata :
    {
        *(.rodata*)
    } > FLASH_APP
    
    /* 跳转参数块:固定地址,用于Bootloader与App通信 */
    .boot_param 0xFED00000 :
    {
        KEEP(*(.boot_param))
    } > RAM
}

分区保护配置

通过芯片选项字节(Option Bytes)设置Flash访问保护,防止应用程序意外写入Bootloader区。RH850系列在Flash编程时通过FLASH_ACR寄存器配置写保护窗口:

/* flash_protect.c */
#include "rh850_flash.h"

void Flash_Protect_Init(void)
{
    /* 设置Bootloader区为只读(禁止应用代码擦写) */
    FLASH_ACR &= ~(0xFFFF0000u);          /* 清除旧配置 */
    FLASH_ACR |= (0x00000000u << 16);    /* 保护0x00000000-0x0000FFFF */
    
    /* 使能保护 */
    FLASH_ACR |= (1u << 0);              /* PRG保护使能 */
    FLASH_ACR |= (1u << 1);              /* ERS保护使能 */
    
    /* 验证保护生效 */
    if ((FLASH_ACR & 0x3u) != 0x3u)
    {
        /* 保护配置失败,进入错误处理 */
        while(1);
    }
}

编译与链接命令

# 编译Bootloader(使用上述链接脚本)
ghs_rh850 -c boot_main.c -o boot_main.o
ghs_rh850 -c flash_protect.c -o flash_protect.o
ghs_rh850 -o bootloader.elf boot_main.o flash_protect.o -T memory_layout.ld

# 编译应用程序(使用相同链接脚本,但只链接app部分)
ghs_rh850 -c app_main.c -o app_main.o
ghs_rh850 -o app.elf app_main.o -T memory_layout.ld

# 生成烧录文件
elfdump -e bootloader.elf -o bootloader.hex
elfdump -e app.elf -o app.hex

验证方法

  1. 地址映射检查:使用elfdump -l bootloader.elf确认Bootloader的.text段起始地址为0x00000000,应用程序的.text段起始地址为0x00010000。
  2. 分区隔离验证:在应用程序中尝试调用Flash_Write(0x00000000, data),应返回错误码或触发硬件异常,证明Bootloader区受到写保护。
  3. 跳转地址验证:在Bootloader中读取0x00010000处的前4字节(应为应用程序栈顶指针),确认与app.elf的__stack符号值一致。

通过条件:上述地址检查全部匹配,且写保护操作被硬件拒绝,即判定内存分区规划正确落地。