news 2026/9/3 11:34:35

STM32H743 QSPI Flash XiP方案:突破内部Flash限制,实现外部程序执行与FOTA

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
STM32H743 QSPI Flash XiP方案:突破内部Flash限制,实现外部程序执行与FOTA

简介:本资源是一套面向嵌入式开发工程师与高级单片机学习者的STM32H743平台QSPI Flash在线运行用户APP的完整软件工程源码,解决高性能MCU从外部高速Flash直接执行应用程序(XIP)的核心技术难点,适用于工业控制、智能终端等对启动灵活性与存储扩展性要求较高的场景。压缩包共458个文件,含186个C源文件(驱动与应用逻辑)、217个头文件(硬件抽象与接口定义)、15个IAR链接脚本(.icf)、11个汇编启动文件(.s)及配套批处理工具(如CopyHex_Flash.bat)、位图资源与Keil工程配置文件,总大小3.55MB。已有87人学习下载。源码包含可商用级Bootloader实现,支持QSPI Flash自动识别、APP校验(CRC)、安全跳转与固件更新;集成多架构PDM滤波库(CM7/CM4/CM3适配IAR/GCC),并提供清晰的目录分层与硬件初始化框架,便于开发者快速移植、调试及二次开发。

1. 项目概述与核心价值

最近在做一个基于STM32H743的高性能数据采集项目,遇到了一个挺典型的问题:主芯片内部的Flash容量不够用了。H743虽然性能强悍,但不同型号的内部Flash从128KB到2MB不等,一旦程序复杂点,加上各种算法库、图形界面,很容易就塞满了。更麻烦的是,项目后期需要支持固件在线升级(FOTA),这需要预留出双份程序的空间,内部Flash更是捉襟见肘。这时候,把目光投向片外的大容量存储介质就成了必然选择。在众多方案里,使用QSPI接口的Nor Flash来直接运行程序,也就是所谓的“XiP”(eXecute in Place)模式,是一个兼顾性能、成本和灵活性的优雅解法。这个“基于STM32H743单片机开发 _QSPI Flash运行程序(用户APP)软件源码.zip”项目,正是为了解决这个问题而生的一套完整、可落地的工程方案。

简单来说,这个项目的核心目标就是:让STM32H743能够将用户应用程序(APP)编译后,直接下载到外挂的QSPI Nor Flash芯片中,并且单片机能够从这片外部Flash中直接取指令、执行程序,就像运行在内部Flash上一样流畅。这不仅仅是简单的存储扩展,它涉及到芯片启动流程的重构、内存映射的配置、编译链接脚本的深度定制,以及Bootloader的精心设计。对于需要大容量程序空间、支持动态加载或多固件并存的嵌入式应用,如高端HMI、复杂工业控制器、智能网关等,这项技术是突破存储瓶颈的关键。

网上能找到的很多资料要么只讲理论,要么代码片段残缺,真正能“开箱即用”、把坑都填平的完整工程很少。这个源码包的价值就在于,它提供了一个经过实际项目验证的、针对STM32H743的完整参考实现。你拿到手的不再是零散的模块,而是一个立即可编译、可烧录、可调试的工程框架,能帮你快速将产品从“内部Flash受限”的困境中解放出来。

2. 整体方案设计与思路拆解

2.1 为什么选择QSPI Nor Flash做XiP?

在决定用外部存储器运行程序前,我们有几个候选:并行Nor/Nand Flash、SD卡、SPI Flash、QSPI Flash等。

  • 并行Flash:速度快,但占用引脚多(数据+地址线可能超过20根),PCB布线复杂,成本高,在追求小型化的设计中不友好。
  • SD卡:容量大,但接口协议复杂,初始化和读取速度相对慢,不适合做零延迟的指令存储。
  • SPI Flash:接口简单(4-6根线),但标准SPI模式速度慢,通常用于存储数据而非运行程序。
  • QSPI Flash:在SPI基础上增加了数据线(IO0-IO3),支持四线同时传输,理论带宽是标准SPI的4倍。更重要的是,STM32H7系列的QSPI外设支持内存映射模式(Memory-Mapped Mode)。一旦配置成功,外部QSPI Flash会被映射到MCU的地址空间(例如0x90000000),CPU可以通过AXI总线直接访问这个地址来取指,无需用户软件干预数据搬运,实现了真正的“原地执行”。

核心优势对比:

特性内部FlashQSPI Nor Flash (XiP模式)SPI Flash (数据存储)SD卡
执行速度最快(零等待)快(依赖时钟和延迟配置)慢,不适合取指慢,不适合取指
容量有限(通常≤2MB)大(常见16MB, 32MB, 64MB)非常大
接口复杂度中等(6根线)低(4-6根线)中等
成本包含在MCU内芯片成本外加
XiP支持原生支持关键特性,需MCU支持不支持不支持
典型用途核心固件、中断向量表用户应用程序、大代码段参数、字体、文件系统海量数据、文件

对于STM32H743,其QSPI时钟最高可达133MHz,在四线模式下理论传输速率可达66MB/s(133M * 4 / 8),足以满足大部分应用程序的运行需求。因此,QSPI Nor Flash是实现在H743上运行大容量APP的最佳平衡点。

2.2 系统启动与运行流程全景图

要实现从QSPI运行APP,整个系统的启动和运行流程需要重新设计,不能再用传统的“上电直接跑用户程序”模式了。核心思路是引入一个Bootloader作为“引路人”。

  1. 上电启动:MCU复位后,始终从内部Flash的起始地址(0x0800 0000)开始执行。这里存放着我们的Bootloader程序。
  2. Bootloader初始化:Bootloader首先完成最基本的系统初始化(时钟、少量外设),然后初始化QSPI外设,将其配置为内存映射模式。此时,QSPI Flash的物理存储空间就被映射到了某个外部地址(如0x9000 0000)。
  3. APP验证与跳转:Bootloader会检查QSPI Flash指定位置(如0x9000 0000)的APP程序是否有效(通常通过校验和或特定的头部魔术字)。如果有效,则进行必要的运行时环境配置(如重定位向量表),然后直接跳转到QSPI映射区的APP入口地址执行。
  4. APP执行:此后,CPU发出的指令读取请求,只要地址落在0x9000 0000开始的映射区间,就会通过QSPI外设自动从外部Flash读取数据。对于APP来说,它“感觉”自己就是运行在0x9000 0000地址的Flash上,无需关心底层细节。
  5. 双程序区与FOTA:此架构天然支持FOTA。我们可以将内部Flash的Bootloader设计得非常健壮。当需要升级时,新APP固件可以通过网络、串口等方式下载到QSPI Flash的另一个区域(例如0x9040 0000)。Bootloader在下次启动时验证并跳转到新区域即可。甚至可以实现A/B备份,确保升级失败也能回滚。

注意:中断向量表(VTOR)必须被重定位。默认VTOR在内部Flash,但APP运行在QSPI,其中断服务函数地址也在QSPI。因此,Bootloader跳转前,必须将VTOR寄存器设置为APP向量表所在的QSPI地址(如0x9000 0000)。

3. 核心细节解析与实操要点

3.1 QSPI外设的两种关键模式

理解QSPI外设的两种工作模式是成功配置的关键:

  1. 间接模式(Indirect Mode):这是用户主动控制的模式。你需要通过写QSPI的寄存器来发起读、写、擦除等命令,然后轮询或等待中断来获取结果。这种模式用于对QSPI Flash进行“管理”操作,例如初始化、擦除、编程(下载APP)、读取数据等。Bootloader在初始化Flash和下载新固件时,就工作在此模式下。

  2. 内存映射模式(Memory-Mapped Mode):这是实现XiP的核心。在此模式下,你只需要配置一次QSPI外设和Flash的读时序参数,然后使能内存映射。之后,QSPI外设就会像一个“地址转换器”和“缓存管理器”。当CPU访问特定的内存映射地址时,QSPI外设自动在后台生成正确的读命令序列,从Flash获取数据,并返回给CPU。APP运行时,QSPI就固定工作在此模式。

一个常见的误区是以为只需要内存映射模式。实际上,一个完整的系统需要在这两种模式间切换。Bootloader启动时,先用间接模式初始化并验证Flash;跳转前,切换到内存映射模式;如果Bootloader需要实现FOTA下载,在擦写新固件时,又需要切回间接模式。

3.2 Flash芯片选型与硬件连接要点

不是所有SPI Flash都支持QSPI模式和内存映射访问。必须选择明确支持四线快速读(Quad I/O Fast Read)命令的Nor Flash芯片,常见型号有Winbond的W25QxxJV系列、GD的GD25Qxx系列、Micron的MT25Q系列等。以W25Q128JV(16MB)为例:

  • 关键命令:需要用到0xEB(Quad I/O Fast Read) 命令,这个命令支持地址和数据的四线传输,并且可以配置“假周期(Dummy Cycles)”来匹配高速时钟。
  • 硬件连接:除了标准的SPI线(CLK, CS#),数据线必须连接4根(IO0, IO1, IO2, IO3)。在STM32H743上,QSPI引脚通常是固定的(如Bank1在PE2, PE3, PD11, PD12, PD13, PF6等),需查阅数据手册和原理图确认。
  • 原理图检查清单
    • QSPI CLK线是否尽量短,远离其他高速信号线?
    • Flash芯片的/HOLD/WP引脚是否已通过电阻上拉至高电平(使其无效)?
    • Flash的电源滤波电容(通常0.1uF和10uF组合)是否靠近芯片VCC引脚?
    • 对于高速运行(>100MHz),是否考虑在数据线上串联小电阻(如22欧姆)以改善信号完整性?

实操心得:第一次调试时,如果无法进入内存映射模式,先用间接模式写一个简单的“读ID”测试函数。如果连ID都读不出来,那问题大概率在硬件(虚焊、连线错误、电源)或最基本的SPI时序配置上。从简到繁,逐步排查。

3.3 编译与链接脚本(.ld文件)的深度定制

这是将代码“定位”到QSPI区域的核心。你不能使用默认的链接脚本,必须告诉编译器:“中断向量表放在QSPI映射区的开头,代码段(.text)放在那里,只读数据(.rodata)也放在那里,而数据段(.data)和零初始化段(.bss)需要放在RAM里。”

一个针对STM32H743和QSPI APP的链接脚本关键部分示例如下:

/* 定义内存区域 */ MEMORY { /* 内部Flash,这里只放Bootloader,APP不用 */ BOOTROM (rx) : ORIGIN = 0x08000000, LENGTH = 128K /* QSPI Flash 映射地址,用于存放APP的代码和只读数据 */ QSPI_FLASH (rx) : ORIGIN = 0x90000000, LENGTH = 16M /* 主RAM (DTCM) */ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K /* 附加RAM (AXI SRAM) 可用于大数据缓冲 */ AXI_RAM (xrw) : ORIGIN = 0x24000000, LENGTH = 512K } SECTIONS { /* .isr_vector 中断向量表必须放在QSPI区域的最开始 */ .isr_vector : { . = ALIGN(4); KEEP(*(.isr_vector)) . = ALIGN(4); } >QSPI_FLASH /* .text 代码段 */ .text : { . = ALIGN(4); *(.text) *(.text*) . = ALIGN(4); } >QSPI_FLASH /* .rodata 只读常量数据 */ .rodata : { . = ALIGN(4); *(.rodata) *(.rodata*) . = ALIGN(4); } >QSPI_FLASH /* .data 初始化了的全局变量。链接时放在QSPI,但运行时需要拷贝到RAM */ /* 这里定义了在QSPI中的加载地址(LMA)和在RAM中的运行地址(VMA) */ _sidata = LOADADDR(.data); /* QSPI中.data内容的起始地址 */ .data : AT ( _sidata ) /* AT指定加载地址 */ { . = ALIGN(4); _sdata = .; /* RAM中.data段的起始地址 */ *(.data) *(.data*) . = ALIGN(4); _edata = .; /* RAM中.data段的结束地址 */ } >RAM /* .bss 未初始化的全局变量,直接放在RAM并清零 */ .bss : { . = ALIGN(4); _sbss = .; *(.bss) *(.bss*) *(COMMON) . = ALIGN(4); _ebss = .; } >RAM /* 其他段... */ }

在APP的启动文件(如startup_stm32h743xx.s)中,系统初始化函数SystemInit之后,需要有一段代码将.data段从QSPI(_sidata)拷贝到RAM(_sdata_edata),并将.bss段(_sbss_ebss)清零。这个工作通常由__main函数(C库的一部分)在跳转到main()之前自动完成,但其底层依赖正确的链接脚本提供这些符号地址。

关键点:APP工程的ROM起始地址和大小必须在IDE(如Keil、IAR或STM32CubeIDE)中设置为QSPI映射地址(0x90000000)和大小。否则,编译器生成的地址会错乱。

4. 实操过程与核心环节实现

4.1 Bootloader的详细实现步骤

Bootloader要尽可能精简、可靠。以下是基于STM32CubeH7 HAL库的实现骨架。

步骤一:创建Bootloader工程

  1. 在STM32CubeIDE中新建工程,选择正确的H743型号。
  2. 配置时钟树,达到最高性能(例如主频400MHz,QSPI时钟133MHz)。
  3. Pinout & Configuration中激活QSPI外设,模式选择“间接模式”。CubeMX会自动配置引脚。
  4. 生成代码。

步骤二:实现QSPI Flash底层驱动在生成代码的基础上,需要编写Flash芯片的驱动函数。核心函数包括:

  • QSPI_Init(): 初始化QSPI外设为间接模式,并配置好时钟分频、采样边沿等。
  • QSPI_EnableMemoryMappedMode(): 配置并切换到内存映射模式。这是最关键的函数。你需要根据Flash数据手册,正确设置:
    • QuadSpI->DCR寄存器中的FSIZE(Flash容量)。
    • QuadSpI->CCR寄存器中的指令、地址模式、数据模式、假周期数。对于W25Q128JV的0xEB命令,通常指令阶段1线,地址阶段4线,数据阶段4线,假周期为6或8(取决于时钟速度)。
  • QSPI_EraseSector(),QSPI_WritePage(),QSPI_Read(): 用于擦除、编程和读取的间接模式函数,用于FOTA下载。

步骤三:APP跳转逻辑在Bootloader的main函数中,流程如下:

int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_QUADSPI_Init(); // 初始化QSPI为间接模式 // 1. 检查QSPI Flash中的APP是否有效(例如,检查APP起始地址的栈指针值是否在合理范围内) uint32_t* app_sp = (uint32_t*)APP_QSPI_ADDRESS; // APP_QSPI_ADDRESS = 0x90000000 uint32_t* app_reset = (uint32_t*)(APP_QSPI_ADDRESS + 4); if (is_valid_app(app_sp, app_reset)) { // 2. 配置QSPI为内存映射模式 QSPI_EnableMemoryMappedMode(); // 3. 禁用所有中断(避免Bootloader中断影响APP) __disable_irq(); // 4. 重设SysTick定时器(HAL库用) SysTick->CTRL = 0; SysTick->LOAD = 0; SysTick->VAL = 0; // 5. 重定位向量表到APP区 SCB->VTOR = APP_QSPI_ADDRESS; // 6. 设置主堆栈指针(MSP)为APP向量表的第一个条目 __set_MSP(*app_sp); // 7. 获取APP复位处理函数的地址(向量表第二个条目),并跳转 uint32_t jump_address = *app_reset; void (*app_reset_handler)(void) = (void (*)(void))jump_address; app_reset_handler(); // 跳转! // 跳转后不会返回 } else { // APP无效,进入DFU模式或错误处理 enter_dfu_mode(); } while (1) {} }

4.2 用户APP工程的配置与编译

步骤一:创建APP工程

  1. 同样新建一个工程,但不要在CubeMX中激活QSPI外设。因为APP运行时,QSPI已由Bootloader配置为内存映射模式,APP不应再对其进行初始化控制。
  2. 配置时钟树,确保与Bootloader中的配置一致(尤其是系统主频和总线时钟)。

步骤二:修改链接脚本如上文所述,修改.ld文件,将代码和只读数据定位到0x90000000开始的区域。在STM32CubeIDE中,可以在Project Properties -> C/C++ Build -> Settings -> Tool Settings -> MCU GCC Linker -> General下指定自定义链接脚本文件。

步骤三:设置工程目标地址

  • STM32CubeIDE: 在Run -> Debug Configurations -> Startup选项卡下,取消勾选Use flash programming,因为我们要下载到外部QSPI。下载动作将由Bootloader或外部编程器完成。在C/C++ Application中指定生成的.elf文件。
  • Keil MDK: 在Options for Target -> Target页,将IROM1的起始地址改为0x90000000,大小改为你的QSPI Flash大小。
  • IAR: 在Options -> Linker -> Config中编辑.icf文件,定义ROM区域为0x90000000

步骤四:处理中断向量表重定位在APP的main.c最开始,需要显式设置向量表偏移寄存器(VTOR)。尽管Bootloader跳转前已设置,但这是一个好习惯,确保APP自身也知道向量表在哪。

int main(void) { // 设置VTOR指向本APP的向量表起始地址(在QSPI中) SCB->VTOR = 0x90000000; // ... 其他初始化 while (1) {} }

步骤五:生成二进制或Hex文件编译APP工程后,你需要生成一个.bin.hex文件,用于烧录到QSPI Flash的0x90000000位置。在CubeIDE中,可以在Project Properties -> C/C++ Build -> Settings -> Build Steps -> Post-build steps中添加命令:arm-none-eabi-objcopy -O binary ${ProjName}.elf ${ProjName}.bin

4.3 程序下载与烧录策略

如何将编译好的APP.bin文件放到QSPI Flash的0x90000000位置?有几种方法:

  1. 通过Bootloader下载(推荐,支持FOTA):Bootloader实现一个通信协议(如串口Ymodem、CAN、以太网TFTP),接收PC端发送的APP.bin文件,然后使用间接模式函数QSPI_WritePage()将其写入QSPI Flash的指定位置。这是产品最终需要的功能。

  2. 使用ST-Link Utility或STM32CubeProgrammer(开发阶段):这些工具支持通过ST-Link调试器直接对QSPI Flash进行编程。

    • 连接好ST-Link。
    • 在工具中连接芯片,选择“External Loader”。对于常见的QSPI Flash,ST提供了现成的加载算法(例如STM32H7x_2048_QSPI.stldr)。你需要将这个.stldr文件放到编程器工具的对应目录。
    • 选择你的APP.bin或.hex文件,设置下载地址为0x90000000,然后编程即可。
    • 注意:这种方式需要Bootloader不干扰QSPI的初始化。通常需要将Bootloader中初始化QSPI的代码暂时注释掉,或者通过一个引脚电平来决定Bootloader是否跳过QSPI初始化。
  3. 使用J-Flash等第三方工具:原理类似,也需要加载对应的Flash算法。

实操心得:开发初期,建议先用方法2,快速验证硬件连接和内存映射模式是否正常。等Bootloader的通信和烧写功能稳定后,再切换到方法1进行集成测试。务必注意,用编程器工具下载时,确保芯片没有运行会操作QSPI的程序(比如正在运行的Bootloader),否则会导致编程失败。

5. 性能优化与调试技巧

5.1 提升XiP性能的关键配置

从外部Flash取指毕竟比内部Flash慢,优化性能至关重要。

  1. 使能指令缓存(I-Cache):STM32H7有独立的指令缓存和数据缓存。必须使能I-Cache来缓存从QSPI读取的指令,这对性能提升是数量级的。在main()函数初始化系统时钟后立即使能:

    SCB_EnableICache(); // 使能指令缓存

    对于数据读取(如访问const数组),如果频繁,也可以考虑使能D-Cache,但要注意数据一致性问题(DMA操作等需要维护缓存一致性)。

  2. 优化QSPI时钟和读时序

    • 在允许范围内,将QSPI时钟(QUADSPI_CLK)配置到最高(如133MHz)。
    • 精确配置“假周期(Dummy Cycles)”:这是Flash芯片在收到地址后,到开始输出数据之间需要等待的时钟周期数。值太小会导致读出的数据错误,太大会降低性能。必须根据Flash数据手册和你的QSPI时钟频率来设置。通常需要反复测试一个边界值。
    • 使用“内存映射模式下的扩展模式”:有些Flash和STM32 QSPI支持更高效的读命令,可以进一步减少指令和地址周期,提升连续读效率。
  3. 关键代码搬运到RAM执行:对于极端要求执行速度的代码(如中断服务函数、关键循环),可以将其指定到内部RAM中执行。在链接脚本中定义一段RAM区域,并在函数定义时使用属性声明:

    // 在链接脚本中定义 MEMORY { ITCM_RAM (rx) : ORIGIN = 0x00000000, LENGTH = 64K } // 在代码中 __attribute__((section(".ram_code"))) void critical_isr(void) { // ... 关键代码 }

    然后在链接脚本中将.ram_code段放入ITCM_RAM

5.2 调试技巧与常见问题排查

在QSPI上调试程序比内部Flash复杂,因为传统的“单步调试”需要实时从QSPI读取指令,可能会受缓存和时序影响。

  1. 调试配置:在IDE的调试配置中,需要正确设置“下载算法”。对于APP,你需要一个针对QSPI Flash地址范围(0x90000000)的调试算法(.FLM或.stldr文件)。这样调试器才能正确设置断点、查看该地址范围内的代码。

  2. 无法跳转到APP?

    • 检查栈指针(SP)和复位向量值:在Bootloader中,打印或调试查看APP_QSPI_ADDRESSAPP_QSPI_ADDRESS+4处的值。第一个值(SP)应该是一个合理的RAM地址(如0x200xxxxx),第二个值(复位向量)应该是一个合法的代码地址(如0x9000xxxx)。如果不是,说明APP的bin文件没有正确烧录或链接地址错误。
    • 检查VTOR:在跳转前和跳转后,检查SCB->VTOR寄存器的值是否正确指向0x90000000。
    • 检查QSPI内存映射模式是否成功:在跳转前,尝试从0x90000000地址读取几个字,看是否能正确读出烧录的APP内容。如果读出的全是0xFF或错误数据,说明内存映射模式配置失败或Flash未初始化。
  3. APP运行不稳定、跑飞?

    • 时序问题:最常见的原因。重点检查QSPI的时钟分频、采样边沿和Flash的假周期数。将假周期数增加1或2个再测试。
    • 缓存一致性问题:如果你使能了D-Cache,并且有DMA从QSPI Flash读取数据到RAM(比如显示一幅存储在QSPI中的图片),那么DMA写入RAM后,CPU可能读到的是缓存中的旧数据。需要在DMA传输完成后,对相关的RAM地址范围执行SCB_CleanInvalidateDCache_by_Addr()操作。
    • 中断冲突:确保Bootloader跳转前关闭了所有中断(__disable_irq()),并且APP在启动后重新正确配置了中断优先级。
  4. Flash下载失败(Flash Download Failed): 这是使用编程器工具时最常见的错误。

    • 确认外部加载算法(External Loader)是否正确安装并选择
    • 检查硬件连接,特别是CS#引脚是否被其他电路拉低。
    • 降低QSPI时钟速度。在加载算法的配置文件中,有时初始时钟设得太高,导致Flash无法响应。尝试在工具中寻找降低编程速度的选项。
    • 确保芯片处于复位或停止状态,没有程序在运行并控制QSPI引脚。

6. 进阶应用:双备份与固件升级(FOTA)

基于QSPI XiP的架构,实现安全的A/B双备份固件升级非常清晰。

  1. 分区设计:将QSPI Flash划分为多个区域。

    • Bootloader区(内部Flash):0x0800 0000 (128KB)
    • APP_A区(QSPI):0x9000 0000 (1MB)
    • APP_B区(QSPI):0x9010 0000 (1MB)
    • 参数区(QSPI):0x9020 0000 (64KB),用于存储当前活动分区标志、固件CRC、版本号等。
  2. 升级流程

    • 设备当前从APP_A区运行。
    • 收到升级指令后,将新固件下载到APP_B区(通过Bootloader的间接模式写入)。
    • 下载完成后,计算新固件的CRC,与服务器下发的校验值比对。
    • 校验通过后,将参数区的“活动分区”标志修改为B,并更新版本号。
    • 重启设备。
    • Bootloader启动后,读取参数区标志,发现活动分区是B,于是验证APP_B区的有效性,然后跳转到APP_B区执行。
    • 升级完成。如果APP_B区启动失败(比如看门狗复位),Bootloader可以检测到并自动回滚到APP_A区。
  3. 实现细节

    • 固件校验:除了CRC,还可以使用数字签名(如ECDSA)进行更严格的身份和完整性验证。
    • 断电保护:在更新参数区标志时,应使用“写-读-验证”的原子操作,或者将标志存储在两处,通过状态机判断,防止断电导致标志损坏。
    • Bootloader的健壮性:Bootloader本身应该极其简单且稳定,避免使用动态内存分配、复杂的协议栈。它的唯一任务就是选择并跳转到正确的APP。

将用户APP移植到QSPI Flash运行,初次接触会觉得步骤繁琐,但一旦打通,整个系统的设计空间就大大拓宽了。它不仅仅是解决容量问题,更是为产品赋予了可靠的远程升级能力和灵活的固件管理能力。在实际项目中,建议先用一个简单的LED闪烁程序作为APP进行全流程测试,从链接脚本修改、编译下载到Bootloader跳转,一步步验证通过后,再将复杂的应用工程迁移过来。这个过程踩的每一个坑,都会让你对STM32H7的内存架构、启动过程和编译链接有更深的理解。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/3 11:33:26

从韩服王者局复盘看英雄联盟高端对局战术决策与工程化思维

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/3 11:31:47

AgentScope 多智能体框架实战:5 分钟跑通你的第一个智能体应用

AgentScope 多智能体框架实战:5 分钟跑通你的第一个智能体应用 【免费下载链接】agentscope Build and run agents you can see, understand and trust. 项目地址: https://gitcode.com/GitHub_Trending/ag/agentscope AgentScope 是一个开源的多智能体应用开…

作者头像 李华
网站建设 2026/9/3 11:31:11

用 WeChatMsg 把微信聊天记录导出成 HTML、Word、CSV 并生成年度报告

用 WeChatMsg 把微信聊天记录导出成 HTML、Word、CSV 并生成年度报告 【免费下载链接】WeChatMsg 提取微信聊天记录,将其导出成HTML、Word、CSV文档永久保存,对聊天记录进行分析生成年度聊天报告 项目地址: https://gitcode.com/GitHub_Trending/we/We…

作者头像 李华
网站建设 2026/9/3 11:31:04

Open-Sora本地部署完整指南:20分钟生成AI视频

Open-Sora本地部署完整指南:20分钟生成AI视频 【免费下载链接】Open-Sora Open-Sora: Democratizing Efficient Video Production for All 项目地址: https://gitcode.com/GitHub_Trending/op/Open-Sora 想给产品演示录一条10秒的视频,外包报价好…

作者头像 李华
网站建设 2026/9/3 11:30:52

档案盒打印机DA580:从环境准备到批量打印全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/3 11:30:33

OpenClaw 2.0部署实战:接入微信钉钉与配置本地模型指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华