[ROMAPI] XPI REMAP 技术解析与应用指南

技术背景与核心概念

1. XIP 内存映射机制

在嵌入式系统中,XIP(eXecute In Place)技术允许MCU直接从FLASH存储器执行代码。先楫半导体MCU通过XPI控制器实现以下物理地址映射:

XPI0 控制器:映射至系统内存 0x80000000 起始地址
XPI1 控制器(部分型号):映射至 0x90000000 起始地址
XIP内存映射架构

2. 工程构建与链接配置

当采用XIP模式构建工程时,链接脚本需明确配置FLASH的XIP映射地址。典型配置示例如下:

MEMORY {
    FLASH (rx)  : ORIGIN = 0x80000000, LENGTH = 16M
    RAM   (rwx) : ORIGIN = 0x0C000000, LENGTH = 8M
}

多固件管理痛点分析

传统分区方案的局限性

在固件更新场景中,传统分区方案存在以下问题:

关键问题表现:

  • 各应用固件需独立配置链接脚本
  • 固件存储位置与执行地址强耦合
  • 固件二进制无法跨分区部署
  • OTA更新容错率低

XPI REMAP 解决方案

技术实现原理

通过XPI控制器的地址重映射功能,实现物理存储地址与系统内存地址的解耦:

地址重映射架构

核心优势

XPI REMAP API说明

ATTR_RAMFUNC
static inline bool rom_xpi_nor_remap_config(XPI_Type *base, uint32_t start, uint32_t len, uint32_t offset);

说明: 配置XPI remap映射接口

  • base, XPI控制器基地址
  • start, 映射起始地址
  • len, 映射长度
  • offset, 相对start起始地址的偏移长度
    返回:true:配置参数有效,映射成功并生效; false:配置参数无效,映射失败;
    注意: 起始地址必须4K对齐。
ATTR_RAMFUNC
static inline void rom_xpi_nor_remap_disable(XPI_Type *base);

说明: 关闭XPI remap映射

  • base, XPI控制器基地址

ATTR_RAMFUNC
static inline bool rom_xpi_nor_is_remap_enabled(XPI_Type *base)

说明: 判断XPI remap映射是否已使能

  • base, XPI控制器基地址
    返回:true:已使能; flase:未使能;

XPI REMAP实例

在先楫半导体hpm_apps 的OTA参考设计中,通过XPI Remap技术实现了固件二进制完全统一的架构。

具有以下优势:

以下为remap实例:


void hpm_appindex_jump(uint8_t appindex)
{
#ifdef FLASH_USER_APP2_ADDR
    //关闭remap映射
    rom_xpi_nor_remap_disable(HPM_XPI0);
    if (appindex == HPM_APP2)
    {
        //当需要跳转到APP2区域固件时,重新remap映射配置
        //起始地址:APP1地址;长度:APP2区域长度; OFFSET:APP2相对于起始APP1的偏移长度
        //这样就将APP2固件存储的区域重新映射到APP1区域地址。后续跳转APP1,实际运行的就是APP2区域的固件。
        rom_xpi_nor_remap_config(HPM_XPI0, FLASH_USER_APP1_ADDR + FLASH_ADDR_BASE, FLASH_USER_APP2_SIZE, FLASH_USER_APP2_ADDR - FLASH_USER_APP1_ADDR);

        //判断remap是否使能成功
        if(!rom_xpi_nor_is_remap_enabled(HPM_XPI0))
        {
            printf("BAD, xpi remap failed!\r\n");
            return;
        }
    }
#endif
    disable_global_irq(CSR_MSTATUS_MIE_MASK);
    disable_global_irq(CSR_MSTATUS_UIE_MASK);
    l1c_dc_invalidate_all();
    l1c_dc_disable();
    l1c_ic_disable();
    fencei();
    //跳转时均是APP1的起始地址
    __asm("la a0, %0" ::"i"(FLASH_USER_APP1_ADDR + sizeof(hpm_app_header_t) + FLASH_ADDR_BASE));
    __asm("jr a0");
    WFI();
    while (1)
    {
    }
}
1
0
发表回复 0

Your email address will not be published. Required fields are marked *