正点原子Apollo H743通过KEIL生成FLM算法实现外部QSPI-FLASH XIP功能(代码跑在外部FLASH)

Apollo V2 QSPI Flash XIP 设计说明

工程参考

ReturnDY/ApolloH743QSPI_FLASH_XIP

目标

在阿波罗 V2 STM32H743 开发板上,将应用程序存放在板载 W25Q256 QSPI Flash 中,并直接从外部 Flash 执行(XIP,Execute In Place)。

MCU 上电后,内部 Flash 中的 Bootloader 初始化 QSPI,开启 memory-mapped 模式,然后跳转至外部 Flash 中的应用。

存储布局

区域地址范围用途
STM32 内部 Flash0x08000000Bootloader、上电复位入口
QSPI 映射窗口0x90000000 - 0x91FFFFFFW25Q256,32 MiB
QSPI 镜像元数据0x90000000 - 0x9000FFFFmagic、版本、长度、CRC、升级状态
QSPI XIP 应用0x90010000应用向量表、代码、只读常量、.data 初值
AXI SRAM0x24000000应用 .data.bss、堆、栈

应用起始地址必须在以下四处完全一致:

  1. XIP 应用 Scatter 文件中的 LR_XIP 0x90010000

  2. Keil Flash Download 中应用镜像的下载地址。

  3. Bootloader 中的 APP_XIP_BASE

  4. 跳转前写入 SCB->VTOR 的向量表地址。

三类构建产物

产物链接地址下载位置作用
Bootloader0x08000000STM32 内部 Flash初始化硬件并启动应用
XIP 应用0x90010000W25Q256 QSPI Flash直接从 QSPI 执行
W25Q256.FLMKeil 临时装入 SRAM不保留在产品中擦除、写入 QSPI Flash

Bootloader 与 XIP 应用应使用两个 Keil Target,或使用两个独立工程;两者各自使用独立 Scatter 文件。

Scatter 文件只在链接期由编译器使用,MCU 运行时不会读取 Scatter 文件。

Keil 下载算法

Keil 下载程序时,会将 Flash Algorithm 临时装入 MCU SRAM 并调用其接口擦写 Flash。下载结束后,.FLM 不会留在 MCU 或 QSPI Flash 中。

Bootloader 一般使用 Keil 自带的 STM32H743 内部 Flash 下载算法。XIP 应用需要自定义 W25Q256.FLM,并在 Keil 的 Flash Download 设置中选中。

外部 Flash 下载算法至少实现:

 int Init(unsigned long adr, unsigned long clk, unsigned long fnc);
 int UnInit(unsigned long fnc);
 int EraseSector(unsigned long adr);
 int ProgramPage(unsigned long adr, unsigned long sz, unsigned char *buf);
 int EraseChip(void);

针对 W25Q256,算法需要自行完成 QSPI/GPIO 初始化、写使能、忙等待、4 KiB 扇区擦除、256 字节分页写入和读回校验。Flash 基地址定义为 0x90000000,容量为 0x02000000,擦除扇区粒度为 4 KiB。

生成 W25Q256 下载算法 FLM

本项目的下载算法工程位于:

 *\keli5\ARM\flash\<QSPI_FLASH>\NewDevice.uvprojx

它不是 XIP 应用工程。Keil 下载时会把它临时复制到 MCU SRAM 中执行,所以 FLM 的 Scatter 文件不能使用 LR_XIP。工程必须包含以下源文件:

 FlashPrg.c        FlashOS 调用入口:Init、EraseSector、ProgramPage 等
 FlashDev.c        FlashDevice 描述:名称、地址、容量、扇区大小
 qspi_w25q256.c    与 HAL/CubeMX 无关的 QSPI 硬件与 W25Q256 驱动
 FlashStk.s        下载算法 SRAM 栈大小(当前 0x400)

FlashDev.c 中的设备范围必须与目标芯片一致:

 EXTSPI,
 0x90000000,       /* Flash 映射起始地址 */
 0x02000000,       /* W25Q256:32 MiB */
 0x001000, 0x000000, /* 4 KiB 扇区 */

Options for Target -> Linker 中选择 Target.lin

其内容如下。PRG 0 PI 表示下载算法以位置无关形式组织,Keil 会把它装入 SRAM;DSCR 区域保存 FlashDevice 描述,供 Keil 识别算法支持的地址范围。

 PRG 0 PI
 {
     PrgCode +0 { * (+RO) }
     PrgData +0 { * (+RW,+ZI) }
 }
 ​
 DSCR +0
 {
     DevDscr +0 { FlashDev.o }
 }

Options for Target -> Linker -> Misc Controls 中加入:

 --keep FlashDevice

否则链接器可能删除未被普通 C 调用引用的 FlashDevice 描述,生成的文件无法作为 Flash Algorithm 使用。

Options for Target -> Output 中:

  • 勾选 Create Executable

  • Output Name 设置为 STM32H743_W25Q256

  • 不需要生成 HEX 或 BIN。

Options for Target -> User -> After Build/Rebuild 中勾选 Run User Program 1,命令为:

 cmd.exe /C copy "Objects\%L" ".\@L.FLM"

Keil 首先生成 Objects\STM32H743_W25Q256.axf。上述命令把这个符合 FlashOS Scatter 布局的 AXF 复制为:

 D:\keli5\ARM\QSPI_FLASH\STM32H743_W25Q256.FLM

构建成功后,将 FLM 放入 Keil 算法目录:

*\keli5\ARM\Flash\STM32H743_W25Q256.FLM

在 XIP 应用工程中选用 FLM

打开 XIP 应用工程的 Options for Target -> Utilities -> Settings -> Flash Download。点击 Add,在弹窗中选中 W25Q256 QSPI Flash (32MB) 后,必须再点击弹窗右下角的 Add。返回上一窗口后,Programming Algorithm 列表应实际出现以下范围:

W25Q256 QSPI Flash (32MB)    0x90000000 - 0x91FFFFFF

只在弹窗中选中算法但未点击 Add 不会把算法加入工程,会导致下载日志出现:

No Algorithm found for: 90000000H

XIP 应用项目不应保留 STM32H7x_2048 片内 Flash 算法。Bootloader 工程仍使用该片内 Flash 算法;XIP 应用工程只使用 W25Q256 QSPI Flash (32MB)

当前已实现的最小 XIP 配置将应用向量表放在 0x90000000。本文前述 0x90010000 是为未来 64 KiB 镜像元数据预留的布局。若采用该预留布局,必须同步修改 XIP Scatter、Boot 的应用基址与 VTOR;不能只修改其中一处。

两份 Scatter 文件

Bootloader

Bootloader 是普通内部 Flash 程序,向量表和代码位于 0x08000000,可写数据、堆和栈位于 SRAM。

LR_BOOT 0x08000000 0x00020000
{
    ER_BOOT 0x08000000 0x00020000
    {
        *.o (RESET, +First)
        *(InRoot$$Sections)
        .ANY (+RO)
    }

    RW_RAM 0x24000000 0x00080000
    {
        .ANY (+RW +ZI)
    }
}

XIP 应用

应用的代码和只读常量位于 QSPI,所有可写数据位于 SRAM:

LR_XIP 0x90010000 0x01000000
{
    ER_XIP 0x90010000 0x01000000
    {
        *.o (RESET, +First)
        *(InRoot$$Sections)
        .ANY (+RO)
    }

    RW_AXI 0x24000000 0x00080000
    {
        .ANY (+RW +ZI)
    }
}

应用启动代码会将 .data 初值从 QSPI 复制至 SRAM,并清零 .bss;流程与普通 Flash 应用相同,只是代码存储区由内部 Flash 变成 QSPI Flash。

运行流程

上电复位
  -> STM32 Boot ROM 根据 BOOT 配置从内部 Flash 启动
  -> Bootloader 的 Reset_Handler(0x08000000)
  -> 配置时钟、MPU/Cache、QSPI GPIO 和 W25Q256
  -> QSPI 进入 memory-mapped 模式
  -> 校验 QSPI 应用的镜像头、向量表和 CRC
  -> 设置 VTOR 为 0x90010000,跳转到应用 Reset_Handler
  -> 应用直接从 QSPI 执行

Bootloader 必须在读取 0x90010000 前完成 W25Q256 QE 位、四字节地址模式与 QSPI memory-mapped 读模式配置。

Bootloader 跳转应用

这里是普通跳转,不是硬件复位。因此 QSPI 的 GPIO、时钟和 memory-mapped 配置都会保留。

#define APP_XIP_BASE 0x90010000UL

typedef void (*app_entry_t)(void);

static void boot_jump_to_xip_app(void)
{
    uint32_t msp = *(volatile uint32_t *)APP_XIP_BASE;
    uint32_t reset = *(volatile uint32_t *)(APP_XIP_BASE + 4U);

    __disable_irq();
    SysTick->CTRL = 0;
    SysTick->LOAD = 0;
    SysTick->VAL = 0;

    for (uint32_t i = 0; i < 8U; i++)
    {
        NVIC->ICER[i] = 0xFFFFFFFFU;
        NVIC->ICPR[i] = 0xFFFFFFFFU;
    }

    SCB->VTOR = APP_XIP_BASE;
    __DSB();
    __ISB();
    __set_MSP(msp);
    ((app_entry_t)reset)();
}

跳转前至少校验:MSP 位于有效 SRAM、Reset Handler 的 Thumb 位有效(reset & 1U)、Reset Handler 位于 QSPI 应用范围内、镜像 CRC 正确。

XIP 应用不得重新初始化、反初始化、复位 QSPI,也不得退出 QSPI memory-mapped 模式。应用启动代码应继续保持:

SCB->VTOR = 0x90010000UL;

NVIC_SystemReset()、看门狗复位、NRST 或掉电复位会丢失 QSPI 配置。此时 MCU 会重新进入内部 Flash Bootloader,Bootloader 再次初始化 QSPI 后跳转应用。

MPU 与 Cache

0x90000000 映射区必须配置为可执行的 Normal Memory。XIP 常规读操作建议启用 Cache 以获得性能。

擦写 QSPI 后、重新读取或执行新内容前,需要进行 Cache 维护:

SCB_InvalidateICache();
SCB_InvalidateDCache();
__DSB();
__ISB();

XIP 运行时更新限制

应用从 QSPI 执行期间,不能安全擦写同一颗 QSPI Flash。擦写前必须退出 memory-mapped 模式,而这会使 CPU 无法从 QSPI 取指。

第一版建议由内部 Flash Bootloader 执行所有 QSPI 镜像更新;XIP 应用只运行,不写自身所在的 QSPI Flash。

若以后确实需要应用在线更新,以下内容必须全部放入 SRAM:

  • 擦除、写入函数及其所有调用函数;

  • 这些函数使用的字符串、常量、查找表;

  • 向量表和可能触发的 ISR,或在更新期间全局关闭中断;

  • 栈和运行期间使用的 DMA 描述符。

完成擦写后重新进入 memory-mapped 模式,失效 Cache,之后才能恢复 XIP 执行。

当前阶段边界

  • 不要把 Bootloader 与 QSPI 应用链接成一个普通镜像。

  • 不要在 XIP 应用中调用 CubeMX 生成的 MX_QUADSPI_Init()

  • 不要把 Keil .FLM 当作产品 Bootloader。

  • 不要让镜像元数据区与可执行代码区重叠。

  • A/B 分区、回滚、签名与在线升级应在基础 XIP 启动验证成功后再加入。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

BaiZer.

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

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

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

打赏作者

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

抵扣说明:

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

余额充值