查看: 493|回复: 0

[分享] MCXN947: 内部Flash启动结合外部Flash XIP的分析和配置

[复制链接]

该用户从未签到

719

主题

6378

帖子

0

超级版主

Rank: 8Rank: 8

积分
25344
最后登录
2025-8-29
发表于 2025-6-30 14:42:53 | 显示全部楼层 |阅读模式
本帖最后由 小恩GG 于 2025-6-30 14:47 编辑

概述
NXP的MCXN947是一款高性能微控制器,支持从内部Flash或外部Flash启动(Boot)。对于一般应用来说,内部Flash容量充足,代码和资源可以全部驻留其中。然而在AI应用、图像处理、语音识别等大模型场景中,内部Flash的容量就显得捉襟见肘。例如,在使用eIQ工具链部署深度神经网络模型时,模型体积通常远大于内部Flash的存储能力。
MCXN947虽然支持外部Flash启动和执行(XIP),但通常来说,系统需要从一个特定的启动介质(内部或外部)启动,代码执行的入口地址是固定的。那么,是否可以实现一种折中方案:系统从内部Flash启动,但部分大资源或代码段放入外部Flash,并从那里运行?
本文将介绍我设计实现的一个Demo,它正是采用了这种“内部启动 + 外部执行”的混合方案,在不牺牲启动速度和灵活性的前提下,有效扩展了可用的存储空间。
硬件环境:
        开发板:FRDM-MCXN947
软件环境:
        IDE:MCUXpresso IDE v11.9.0
        SDK:SDK Builder | MCUXpresso SDK Builder (nxp.com)
        基础工程: frdmmcxn947_tflm_cifar10
1.        外部Flash硬件配置与管脚配置
以下是官方FRDM-MCXN947中的八线Flash的原理图。

图片1.png
  
Flash芯片引脚
  
功能
与MCXN947相连
  
CS
  
SPI通讯的CS片选信号
P3_0/FLEXSPI0_A_SS0_b
  
SCK
  
SPI通讯的SCK时钟信号
P3_7/FLEXSPI0_A_SCLK
  
DQS
  
SPI通讯的DQS信号
P3_6/FLEXSPI0_A_DQS
  
DQ0
  
OSPI的数据信号D0
P3_8/FLEXSPI0_A_DATA0
  
DQ1
  
OSPI的数据信号D1
P3_9/FLEXSPI0_A_DATA1
  
DQ2
  
OSPI的数据信号D2
P3_10/FLEXSPI0_A_DATA2
  
DQ3
  
OSPI的数据信号D3
P3_11/FLEXSPI0_A_DATA3
  
DQ4
  
OSPI的数据信号D4
P3_12/FLEXSPI0_A_DATA4
  
DQ5
  
OSPI的数据信号D5
P3_13/FLEXSPI0_A_DATA5
  
DQ6
  
OSPI的数据信号D6
P3_14/FLEXSPI0_A_DATA6
  
DQ7
  
OSPI的数据信号D7
P3_15/FLEXSPI0_A_DATA7
配置代码为 例如
  1.       /* Enables the clock for PORT3: Enables clock */
  2.        CLOCK_EnableClock(kCLOCK_Port3);

  3.        const port_pin_config_t port3_0_pinB17_config = {/* Internal pull-up/down resistor is disabled */
  4.                                                         kPORT_PullDisable,
  5.                                                         /* Low internal pull resistor value is selected. */
  6.                                                         kPORT_LowPullResistor,
  7.                                                         /* Fast slew rate is configured */
  8.                                                         kPORT_FastSlewRate,
  9.                                                         /* Passive input filter is disabled */
  10.                                                         kPORT_PassiveFilterDisable,
  11.                                                         /* Open drain output is disabled */
  12.                                                         kPORT_OpenDrainDisable,
  13.                                                         /* Low drive strength is configured */
  14.                                                         kPORT_LowDriveStrength,
  15.                                                         /* Pin is configured as FLEXSPI0_A_SS0_b */
  16.                                                         kPORT_MuxAlt8,
  17.                                                         /* Digital input enabled */
  18.                                                         kPORT_InputBufferEnable,
  19.                                                         /* Digital input is not inverted */
  20.                                                         kPORT_InputNormal,
  21.                                                         /* Pin Control Register fields [15:0] are not locked */
  22.                                                         kPORT_UnlockRegister};
  23.        /* PORT3_0 (pin B17) is configured as FLEXSPI0_A_SS0_b */
  24.        PORT_SetPinConfig(PORT3, 0U, &port3_0_pinB17_config);
  25. // ...依次配置其他FLEXSPI管脚
复制代码
2.        FlexSPI 模块初始化
为了使用FlexSPI进行XIP,需正确配置时钟并初始化FlexSPI模块。以下是关键步骤:
2.1 配置FlexSPI时钟
    /* Flexspi frequency 150MHz / 2 = 75MHz */
    CLOCK_SetClkDiv(kCLOCK_DivFlexspiClk, 2U);
    CLOCK_AttachClk(kPLL0_to_FLEXSPI); /*!< Switch FLEXSPI to PLL0 */

2.2 添加FlexSPI驱动并初始化
在工程中引入 FlexSPI 驱动(SDK 中已有),然后在主程序中添加初始化代码:
    /*Get FLEXSPI default settings and configure the flexspi. */
    FLEXSPI_GetDefaultConfig(&config);

    /*Set AHB buffer size for reading data through AHB bus. */
    config.ahbConfig.enableAHBPrefetch = true;
    config.rxSampleClock               = EXAMPLE_FLEXSPI_RX_SAMPLE_CLOCK;
    config.ahbConfig.enableAHBBufferable = true;
    config.ahbConfig.enableAHBCachable   = true;
    FLEXSPI_Init(base, &config);

    /* Configure flash settings according to serial flash feature. */
    FLEXSPI_SetFlashConfig(base, &deviceconfig, FLASH_PORT);
#if defined(EXAMPLE_FLASH_RESET_CONFIG)
    uint32_t TempFastReadSDRLUTCommandSeq[4];

    memcpy(TempFastReadSDRLUTCommandSeq, FastReadSDRLUTCommandSeq, sizeof(FastReadSDRLUTCommandSeq));
#endif

3.        配置MCUXpresso工程支持Octal Flash
在 MCUXpresso IDE 中,进入 MCU Settings > Memory,添加一个新的 memory 区域:
名称:OSPI_FLASH(或 OCTAL_FLASH)
起始地址:根据你芯片连接的外部flash地址设置,
Snipaste_2025-06-30_14-22-49.png

根据用户手册,FlexSPI起始地址为0x80000000。大小:例如 128MB
然后,选择 NXP 提供的对应外部flash驱动,
FRDM_MCXN947连接的flash为mt35xu512aba,该flash支持SFDP,故我们可以选择MCXN9xx_SFDP_FlexSPI.cfx
添加后,可以看到Memory details如下。
图片3.png

4. 添加链接脚本和模型数据迁移
4.1 创建链接脚本片段
在工程的 linkscripts/ 文件夹中添加两个文件:
text.ldt(用于代码段)
rodata.ldt(用于模型只读数据)
内容如下:

<#if memory.name=="OSPI_FLASH">
KEEP (*(.model_data*))
KEEP (*(model.o*))
KEEP(*(.text.OSPI_FLASH*))
*(.text.QSPI_FLASH*)
*(.text.${memory.alias}*)
*(.text.${memory.name}*)
</#if>

确保模型数据(如 .model_data 段)被正确保留并放入 XIP 区域。
4.2 模型数据放入XIP区域
将模型通过如下方式放置到 .model_data 段中(C代码):
__attribute__((section(".model_data")))
const unsigned char model_data[] = {
    #include "model_data.inc" // 从模型文件导出的原始数据
};

图片4.png
5. 编译与验证
在构建项目后,MCUXpresso IDE 的映像映射报告将显示部分 .text 和 .rodata 段已成功放置至 Octal Flash(OSPI_FLASH)区域,例如
图片5.png
OSPI_FLASH:      100144 B    262140 KB      0.04%
下载运行后,系统从内部Flash启动,并成功从外部Flash中直接读取模型数据,完成AI推理任务。
图片6.png

结语
通过本文介绍的配置步骤,MCXN947成功实现了内部启动 + 外部XIP执行的混合存储方案。该方案既保留了启动速度优势,又显著拓展了程序/模型的可用存储容量,为部署复杂AI模型提供了良好支撑。
对于资源有限的MCU平台而言,这种结构不仅是实用可行的选择,也是未来嵌入式AI应用普遍采用的一种优化思路。



回复

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /3 下一条

Archiver|手机版|小黑屋|恩智浦技术社区

GMT+8, 2025-8-30 21:23 , Processed in 0.104062 second(s), 20 queries , MemCache On.

Powered by Discuz! X3.4

Copyright © 2001-2024, Tencent Cloud.

快速回复 返回顶部 返回列表